'Render a react component in a new window

I am developing a Certificate Management System where after all the processes have been done, the user may print a certificate.

I am struggling to implement such that upon clicking the print button, a new tab will open containing the ready to print HTML certificate so that the user will only CTRL + P to have the certificate printed.

How do i render my react certificate component in a new window? Such that i would only pass the props which are the data to be put into the certificate e.g., name, date etc.. like <Certificate name={john} />

I have tried implementing the npm react-new-window but it does not work with

<Button onclick={() => { 
<NewWindow>
  <CertificateComponent>
</NewWindow>
}}
>
PRINT BUTTON 
</Button>

I have looked into react portals but most use cases are for Modals, which is where my "PRINT" button is rendered.

Sorry for the bad english/explanation. Thank you!



Solution 1:[1]

New Solution based on CreatePortal

import React, { useEffect, useCallback, useMemo, useState } from "react";
import { render, createPortal } from "react-dom";

const App = () => {
  const [isOpen, setOpenState] = useState(false);
  const open = useCallback(() => setOpenState(true));
  const close = useCallback(() => setOpenState(false));

  return (
    <div>
      <h1>Portals in React</h1>
      <button onClick={open}>Open</button>
      <button onClick={close}>Close</button>
      {isOpen && (
        <NewWindow close={close}>
          Example <button onClick={close}>Close</button>
        </NewWindow>
      )}
    </div>
  );
};

const NewWindow = ({ children, close }) => {
  const newWindow = useMemo(() =>
    window.open(
      "about:blank",
      "newWin",
      `width=400,height=300,left=${window.screen.availWidth / 2 -
        200},top=${window.screen.availHeight / 2 - 150}`
    )
  );
  newWindow.onbeforeunload = () => {
    close();
  };
  useEffect(() => () => newWindow.close());
  return createPortal(children, newWindow.document.body);
};

render(<App />, document.getElementById("root"));

Solution 2:[2]

There can be multiple approaches for this.

Approach 1:

Create a new route and map the certificateComponent to it, make sure it doesn't have any authentication or any dependency to it.

Store the required data for certificateComponent either in session storage or local storage.

When the user clicks on print button, redirect the user to this new route using window.open("http://localhost:port/newroute").

In certificateComponent read the values stored in session/local storage and map it accordingly.

Approach 2:

Make the certificate component as an overlay which occupies the entire screen which shows up when the user click on print button. If any UI elements need to be hidden, you can do something as shown below:

printFn = function() {
    // show the certificate component 
    // hide the ui elements not required
    // window.print()
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Bashid
Solution 2 M4C4R