skip to Main Content

I’m trying to print specific components of my app using react-to-print library. I’m trying to override the event of pressing ctrl+p for printing by using event.preventDefault() and it’s working for the first time that is when the app renders, on ctrl+p the required components are getting printed but after this the second time I click ctrl+p is not getting caught inside my handleKeyDown function, instead the browser default of printing the entire page is happening.

import React, { useCallback, useEffect, useRef } from "react";
import { useReactToPrint } from "react-to-print";

const Example = () => {
  const componentRef = useRef();
  const handlePrint = useReactToPrint({
    content: () => componentRef.current,
  });

  const handleKeyDown = useCallback(
    (event) => {
      console.log("keydown");
      if (event.ctrlKey && event.key === "p") {
        event.preventDefault();
        handlePrint();
      }
    },
    [handlePrint]
  );

  useEffect(() => {
    document.addEventListener("keydown", handleKeyDown);
    return () => {
      document.removeEventListener("keydown", handleKeyDown);
    };
  }, [handleKeyDown]);

  return (
    <div>
      <div ref={componentRef}>
        <div>Div 1</div>
        <div>Div 2</div>
        <div>Div 3</div>
      </div>
      <div>Div not printed</div>
      <button onClick={handlePrint}>Print this out!</button>
    </div>
  );
};
export default Example;

The ctrl+p gives the desired result the first time after every re-render but on further tries its not working. I’m assuming the issue to be with the keyDown event not getting caught after causing the print for the first time.

How can I get it to work properly so that ctrl+p prints the desired output ?

2

Answers


  1. Chosen as BEST ANSWER

    I found the solution. What happened was, when the print dialogue opened, the focus from the app was somehow lost (not sure) until I manually clicked on the screen/app component and ctrl+p worked as desired.

    const handlePrint = useReactToPrint({
        content: () => componentRef.current,
        onAfterPrint: () => {
          document.activeElement.blur();
          componentRef.current.focus();
        },
      });
    

    Just modifying the handlePrint function and taking the focus back on the component worked.


  2. Instead of listening for the event on the document object, you can try utilising the window object to catch the keydown event at a higher level in your component hierarchy to resolve this problem. In this manner, the event will be recorded regardless of the app’s current focus.

    import React, { useCallback, useEffect, useRef } from "react";
    import { useReactToPrint } from "react-to-print";
    
    const Example = () => {
      const componentRef = useRef();
      const handlePrint = useReactToPrint({
        content: () => componentRef.current,
      });
    
      const handleKeyDown = useCallback(
        (event) => {
          console.log("keydown");
          if (event.ctrlKey && event.key === "p") {
            event.preventDefault();
            handlePrint();
          }
        },
        [handlePrint]
      );
    
      useEffect(() => {
        window.addEventListener("keydown", handleKeyDown); // Use window object instead of document
        return () => {
          window.removeEventListener("keydown", handleKeyDown); // Use window object instead of document
        };
      }, [handleKeyDown]);
    
      return (
        <div>
          <div ref={componentRef}>
            <div>Div 1</div>
            <div>Div 2</div>
            <div>Div 3</div>
          </div>
          <div>Div not printed</div>
          <button onClick={handlePrint}>Print this out!</button>
        </div>
      );
    };
    export default Example;
    

    You should be able to reliably capture Ctrl+P keydown events and cause the desired printing behaviour even after the first print by leveraging the window object to capture the keydown event.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search