Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

react-to-print

Package Overview
Dependencies
Maintainers
0
Versions
94
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-to-print - npm Package Compare versions

Comparing version 3.0.2 to 3.0.3-beta-1

lib/utils/getErrorMessage.d.ts

2

lib/index.js

@@ -1,1 +0,1 @@

!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react")):"function"==typeof define&&define.amd?define("lib",["react"],t):"object"==typeof exports?exports.lib=t(require("react")):e.lib=t(e.react)}("undefined"!=typeof self?self:this,(function(e){return function(){"use strict";var t={155:function(t){t.exports=e}},o={};function n(e){var r=o[e];if(void 0!==r)return r.exports;var s=o[e]={exports:{}};return t[e](s,s.exports,n),s.exports}n.d=function(e,t){for(var o in t)n.o(t,o)&&!n.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:t[o]})},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var r={};n.r(r),n.d(r,{useReactToPrint:function(){return f}});var s=n(155);function i({level:e="error",messages:t,suppressErrors:o=!1}){o||("error"===e?console.error(t):"warning"===e?console.warn(t):"debug"===e&&console.debug(t))}function l(e,t){if(t||!e){const e=document.getElementById("printWindow");e&&document.body.removeChild(e)}}function a(e,t){const{documentTitle:o,onAfterPrint:n,onPrintError:r,preserveAfterPrint:s,print:a,suppressErrors:c}=t;setTimeout((()=>{var t,d;if(e.contentWindow)if(e.contentWindow.focus(),a)a(e).then((()=>null==n?void 0:n())).then((()=>l(s))).catch((e=>{r?r("print",e):i({messages:["An error was thrown by the specified `print` function"],suppressErrors:c})}));else{if(e.contentWindow.print){const n=null!==(d=null===(t=e.contentDocument)||void 0===t?void 0:t.title)&&void 0!==d?d:"",r=e.ownerDocument.title;o&&(e.ownerDocument.title=o,e.contentDocument&&(e.contentDocument.title=o)),e.contentWindow.print(),o&&(e.ownerDocument.title=r,e.contentDocument&&(e.contentDocument.title=n))}else i({messages:["Printing for this browser is not currently possible: the browser does not have a `print` method available for iframes."],suppressErrors:c});null==n||n(),l(s)}else i({messages:["Printing failed because the `contentWindow` of the print iframe did not load. This is possibly an error with `react-to-print`. Please file an issue: https://github.com/MatthewHerbst/react-to-print/issues/"],suppressErrors:c})}),500)}function c(e){const t=[],o=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT,null);let n=o.nextNode();for(;n;)t.push(n),n=o.nextNode();return t}function d(e,t,o){const n=c(e),r=c(t);if(n.length===r.length)for(let e=0;e<n.length;e++){const t=n[e],s=r[e],i=t.shadowRoot;if(null!==i){const e=s.attachShadow({mode:i.mode});e.innerHTML=i.innerHTML,d(i,e,o)}}else i({messages:["When cloning shadow root content, source and target elements have different size. `onBeforePrint` likely resolved too early.",e,t],suppressErrors:o})}const u='\n @page {\n /* Remove browser default header (title) and footer (url) */\n margin: 0;\n }\n @media print {\n body {\n /* Tell browsers to print background colors */\n color-adjust: exact; /* Firefox. This is an older version of "print-color-adjust" */\n print-color-adjust: exact; /* Firefox/Safari */\n -webkit-print-color-adjust: exact; /* Chrome/Safari/Edge/Opera */\n }\n }\n';function p(e,t,o,n){var r,s,l;const{contentNode:c,clonedContentNode:p,clonedImgNodes:h,clonedVideoNodes:f,numResourcesToLoad:g,originalCanvasNodes:m}=o,{bodyClass:b,fonts:y,ignoreGlobalStyles:v,pageStyle:w,nonce:E,suppressErrors:A,copyShadowRoots:T}=n;e.onload=null;const x=e.contentDocument||(null===(r=e.contentWindow)||void 0===r?void 0:r.document);if(x){const o=x.body.appendChild(p);T&&d(c,o,!!A),y&&((null===(s=e.contentDocument)||void 0===s?void 0:s.fonts)&&(null===(l=e.contentWindow)||void 0===l?void 0:l.FontFace)?y.forEach((o=>{const n=new FontFace(o.family,o.source,{weight:o.weight,style:o.style});e.contentDocument.fonts.add(n),n.loaded.then((()=>{t(n)})).catch((e=>{t(n,["Failed loading the font:",n,"Load error:",e])}))})):(y.forEach((e=>t(e))),i({messages:['"react-to-print" is not able to load custom fonts because the browser does not support the FontFace API but will continue attempting to print the page'],suppressErrors:A})));const n=null!=w?w:u,r=x.createElement("style");E&&(r.setAttribute("nonce",E),x.head.setAttribute("nonce",E)),r.appendChild(x.createTextNode(n)),x.head.appendChild(r),b&&x.body.classList.add(...b.split(" "));const a=x.querySelectorAll("canvas");for(let e=0;e<m.length;++e){const t=m[e],o=a[e];if(void 0===o){i({messages:["A canvas element could not be copied for printing, has it loaded? `onBeforePrint` likely resolved too early.",t],suppressErrors:A});continue}const n=o.getContext("2d");n&&n.drawImage(t,0,0)}for(let e=0;e<h.length;e++){const o=h[e],n=o.getAttribute("src");if(n){const e=new Image;e.onload=()=>t(o),e.onerror=(e,n,r,s,i)=>t(o,["Error loading <img>",o,"Error",i]),e.src=n}else t(o,['Found an <img> tag with an empty "src" attribute. This prevents pre-loading it.',o])}for(let e=0;e<f.length;e++){const o=f[e];o.preload="auto";const n=o.getAttribute("poster");if(n){const e=new Image;e.onload=()=>t(o),e.onerror=(e,r,s,i,l)=>t(o,["Error loading video poster",n,"for video",o,"Error:",l]),e.src=n}else o.readyState>=2?t(o):(o.onloadeddata=()=>t(o),o.onerror=(e,n,r,s,i)=>t(o,["Error loading video",o,"Error",i]),o.onstalled=()=>t(o,["Loading video stalled, skipping",o]))}const g="select",S=c.querySelectorAll(g),k=x.querySelectorAll(g);for(let e=0;e<S.length;e++)k[e].value=S[e].value;if(!v){const e=document.querySelectorAll("style, link[rel~='stylesheet'], link[as='style']");for(let o=0,n=e.length;o<n;++o){const n=e[o];if("style"===n.tagName.toLowerCase()){const e=x.createElement(n.tagName),t=n.sheet;if(t){let r="";try{const e=t.cssRules.length;for(let o=0;o<e;++o)"string"==typeof t.cssRules[o].cssText&&(r+=`${t.cssRules[o].cssText}\r\n`)}catch(e){i({messages:["A stylesheet could not be accessed. This is likely due to the stylesheet having cross-origin imports, and many browsers block script access to cross-origin stylesheets. See https://github.com/MatthewHerbst/react-to-print/issues/429 for details. You may be able to load the sheet by both marking the stylesheet with the cross `crossorigin` attribute, and setting the `Access-Control-Allow-Origin` header on the server serving the stylesheet. Alternatively, host the stylesheet on your domain to avoid this issue entirely.",n,`Original error: ${null==e?void 0:e.message}`],level:"warning"})}e.setAttribute("id",`react-to-print-${o}`),E&&e.setAttribute("nonce",E),e.appendChild(x.createTextNode(r)),x.head.appendChild(e)}}else if(n.getAttribute("href"))if(n.hasAttribute("disabled"))i({messages:["`react-to-print` encountered a <link> tag with a `disabled` attribute and will ignore it. Note that the `disabled` attribute is deprecated, and some browsers ignore it. You should stop using it. https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link#attr-disabled. The <link> is:",n],level:"warning"}),t(n);else{const e=x.createElement(n.tagName);for(let t=0,o=n.attributes.length;t<o;++t){const o=n.attributes[t];o&&e.setAttribute(o.nodeName,o.nodeValue||"")}e.onload=()=>t(e),e.onerror=(o,n,r,s,i)=>t(e,["Failed to load",e,"Error:",i]),E&&e.setAttribute("nonce",E),x.head.appendChild(e)}else i({messages:["`react-to-print` encountered a <link> tag with an empty `href` attribute. In addition to being invalid HTML, this can cause problems in many browsers, and so the <link> was not loaded. The <link> is:",n],level:"warning"}),t(n)}}}0===g&&a(e,n)}function h(e,t,o,n){e.onload=()=>p(e,t,o,n),document.body.appendChild(e)}function f(e){const{contentRef:t,fonts:o,ignoreGlobalStyles:n,onBeforePrint:r,onPrintError:c,preserveAfterPrint:d,suppressErrors:u}=e,p=(0,s.useCallback)((s=>{l(d,!0);const p=function({contentRef:e,optionalContent:t,suppressErrors:o}){return t&&(e&&i({level:"warning",messages:['"react-to-print" received a `contentRef` option and a optional-content param passed to its callback. The `contentRef` option will be ignored.']}),"function"==typeof t)?t():e?e.current:void i({messages:['"react-to-print" did not receive a `contentRef` option or a optional-content param pass to its callback.'],suppressErrors:o})}({contentRef:t,optionalContent:s,suppressErrors:u});if(!p)return void i({messages:["There is nothing to print"],suppressErrors:u});const f=p.cloneNode(!0),g=document.querySelectorAll("link[rel~='stylesheet'], link[as='style']"),m=f.querySelectorAll("img"),b=f.querySelectorAll("video"),y=o?o.length:0,v=(n?0:g.length)+m.length+b.length+y,w=[],E=[],A=function(){const e=document.createElement("iframe");return e.width=`${document.documentElement.clientWidth}px`,e.height=`${document.documentElement.clientHeight}px`,e.style.position="absolute",e.style.top=`-${document.documentElement.clientHeight+100}px`,e.style.left=`-${document.documentElement.clientWidth+100}px`,e.id="printWindow",e.srcdoc="<!DOCTYPE html>",e}(),T=(t,o)=>{w.includes(t)?i({level:"debug",messages:["Tried to mark a resource that has already been handled",t],suppressErrors:u}):(o?(i({messages:['"react-to-print" was unable to load a resource but will continue attempting to print the page',...o],suppressErrors:u}),E.push(t)):w.push(t),w.length+E.length===v&&a(A,e))},x={contentNode:p,clonedContentNode:f,clonedImgNodes:m,clonedVideoNodes:b,numResourcesToLoad:v,originalCanvasNodes:p.querySelectorAll("canvas")};r?r().then((()=>h(A,T,x,e))).catch((e=>{null==c||c("onBeforePrint",e)})):h(A,T,x,e)}),[e]);return p}return r}()}));
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react")):"function"==typeof define&&define.amd?define("lib",["react"],t):"object"==typeof exports?exports.lib=t(require("react")):e.lib=t(e.react)}("undefined"!=typeof self?self:this,(function(e){return function(){"use strict";var t={155:function(t){t.exports=e}},o={};function n(e){var r=o[e];if(void 0!==r)return r.exports;var s=o[e]={exports:{}};return t[e](s,s.exports,n),s.exports}n.d=function(e,t){for(var o in t)n.o(t,o)&&!n.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:t[o]})},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var r={};n.r(r),n.d(r,{useReactToPrint:function(){return g}});var s=n(155);function i({level:e="error",messages:t,suppressErrors:o=!1}){o||("error"===e?console.error(t):"warning"===e?console.warn(t):console.debug(t))}function l(e,t){if(t||!e){const e=document.getElementById("printWindow");e&&document.body.removeChild(e)}}function a(e){return e instanceof Error?e:new Error("Unknown Error")}function c(e,t){const{documentTitle:o,onAfterPrint:n,onPrintError:r,preserveAfterPrint:s,print:c,suppressErrors:d}=t;setTimeout((()=>{var t,u;if(e.contentWindow)if(e.contentWindow.focus(),c)c(e).then((()=>{null==n||n()})).then((()=>{l(s)})).catch((e=>{r?r("print",a(e)):i({messages:["An error was thrown by the specified `print` function"],suppressErrors:d})}));else{if(e.contentWindow.print){const n=null!==(u=null===(t=e.contentDocument)||void 0===t?void 0:t.title)&&void 0!==u?u:"",r=e.ownerDocument.title;o&&(e.ownerDocument.title=o,e.contentDocument&&(e.contentDocument.title=o)),e.contentWindow.print(),o&&(e.ownerDocument.title=r,e.contentDocument&&(e.contentDocument.title=n))}else i({messages:["Printing for this browser is not currently possible: the browser does not have a `print` method available for iframes."],suppressErrors:d});window.addEventListener("focus",(()=>{null==n||n(),l(s)}),{once:!0})}else i({messages:["Printing failed because the `contentWindow` of the print iframe did not load. This is possibly an error with `react-to-print`. Please file an issue: https://github.com/MatthewHerbst/react-to-print/issues/"],suppressErrors:d})}),500)}function d(e){const t=[],o=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT,null);let n=o.nextNode();for(;n;)t.push(n),n=o.nextNode();return t}function u(e,t,o){const n=d(e),r=d(t);if(n.length===r.length)for(let e=0;e<n.length;e++){const t=n[e],s=r[e],i=t.shadowRoot;if(null!==i){const e=s.attachShadow({mode:i.mode});e.innerHTML=i.innerHTML,u(i,e,o)}}else i({messages:["When cloning shadow root content, source and target elements have different size. `onBeforePrint` likely resolved too early.",e,t],suppressErrors:o})}const p='\n @page {\n /* Remove browser default header (title) and footer (url) */\n margin: 0;\n }\n @media print {\n body {\n /* Tell browsers to print background colors */\n color-adjust: exact; /* Firefox. This is an older version of "print-color-adjust" */\n print-color-adjust: exact; /* Firefox/Safari */\n -webkit-print-color-adjust: exact; /* Chrome/Safari/Edge/Opera */\n }\n }\n';function h(e,t,o,n){var r,s,l,d,h;const{contentNode:f,clonedContentNode:g,clonedImgNodes:m,clonedVideoNodes:b,numResourcesToLoad:y,originalCanvasNodes:v}=o,{bodyClass:w,fonts:E,ignoreGlobalStyles:A,pageStyle:T,nonce:x,suppressErrors:k,copyShadowRoots:S}=n;e.onload=null;const N=null!==(r=e.contentDocument)&&void 0!==r?r:null===(s=e.contentWindow)||void 0===s?void 0:s.document;if(N){const o=N.body.appendChild(g);S&&u(f,o,!!k),E&&((null===(l=e.contentDocument)||void 0===l?void 0:l.fonts)&&(null===(d=e.contentWindow)||void 0===d?void 0:d.FontFace)?E.forEach((o=>{const n=new FontFace(o.family,o.source,{weight:o.weight,style:o.style});e.contentDocument.fonts.add(n),n.loaded.then((()=>{t(n)})).catch((e=>{t(n,["Failed loading the font:",n,"Load error:",a(e)])}))})):(E.forEach((e=>{t(e)})),i({messages:['"react-to-print" is not able to load custom fonts because the browser does not support the FontFace API but will continue attempting to print the page'],suppressErrors:k})));const n=null!=T?T:p,r=N.createElement("style");x&&(r.setAttribute("nonce",x),N.head.setAttribute("nonce",x)),r.appendChild(N.createTextNode(n)),N.head.appendChild(r),w&&N.body.classList.add(...w.split(" "));const s=N.querySelectorAll("canvas");for(let e=0;e<v.length;++e){const t=v[e],o=s[e];if(void 0===o){i({messages:["A canvas element could not be copied for printing, has it loaded? `onBeforePrint` likely resolved too early.",t],suppressErrors:k});continue}const n=o.getContext("2d");n&&n.drawImage(t,0,0)}for(let e=0;e<m.length;e++){const o=m[e],n=o.getAttribute("src");if(n){const e=new Image;e.onload=()=>{t(o)},e.onerror=(e,n,r,s,i)=>{t(o,["Error loading <img>",o,"Error",i])},e.src=n}else t(o,['Found an <img> tag with an empty "src" attribute. This prevents pre-loading it.',o])}for(let e=0;e<b.length;e++){const o=b[e];o.preload="auto";const n=o.getAttribute("poster");if(n){const e=new Image;e.onload=()=>{t(o)},e.onerror=(e,r,s,i,l)=>{t(o,["Error loading video poster",n,"for video",o,"Error:",l])},e.src=n}else o.readyState>=2?t(o):(o.onloadeddata=()=>{t(o)},o.onerror=(e,n,r,s,i)=>{t(o,["Error loading video",o,"Error",i])},o.onstalled=()=>{t(o,["Loading video stalled, skipping",o])})}const c="select",y=f.querySelectorAll(c),C=N.querySelectorAll(c);for(let e=0;e<y.length;e++)C[e].value=y[e].value;if(!A){const e=document.querySelectorAll("style, link[rel~='stylesheet'], link[as='style']");for(let o=0,n=e.length;o<n;++o){const n=e[o];if("style"===n.tagName.toLowerCase()){const e=N.createElement(n.tagName),t=n.sheet;if(t){let r="";try{const e=t.cssRules.length;for(let o=0;o<e;++o)"string"==typeof t.cssRules[o].cssText&&(r+=`${t.cssRules[o].cssText}\r\n`)}catch(e){i({messages:["A stylesheet could not be accessed. This is likely due to the stylesheet having cross-origin imports, and many browsers block script access to cross-origin stylesheets. See https://github.com/MatthewHerbst/react-to-print/issues/429 for details. You may be able to load the sheet by both marking the stylesheet with the cross `crossorigin` attribute, and setting the `Access-Control-Allow-Origin` header on the server serving the stylesheet. Alternatively, host the stylesheet on your domain to avoid this issue entirely.",n,`Original error: ${a(e).message}`],level:"warning"})}e.setAttribute("id",`react-to-print-${o}`),x&&e.setAttribute("nonce",x),e.appendChild(N.createTextNode(r)),N.head.appendChild(e)}}else if(n.getAttribute("href"))if(n.hasAttribute("disabled"))i({messages:["`react-to-print` encountered a <link> tag with a `disabled` attribute and will ignore it. Note that the `disabled` attribute is deprecated, and some browsers ignore it. You should stop using it. https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link#attr-disabled. The <link> is:",n],level:"warning"}),t(n);else{const e=N.createElement(n.tagName);for(let t=0,o=n.attributes.length;t<o;++t){const o=n.attributes[t];o&&e.setAttribute(o.nodeName,null!==(h=o.nodeValue)&&void 0!==h?h:"")}e.onload=()=>{t(e)},e.onerror=(o,n,r,s,i)=>{t(e,["Failed to load",e,"Error:",i])},x&&e.setAttribute("nonce",x),N.head.appendChild(e)}else i({messages:["`react-to-print` encountered a <link> tag with an empty `href` attribute. In addition to being invalid HTML, this can cause problems in many browsers, and so the <link> was not loaded. The <link> is:",n],level:"warning"}),t(n)}}}0===y&&c(e,n)}function f(e,t,o,n){e.onload=()=>{h(e,t,o,n)},document.body.appendChild(e)}function g(e){const{contentRef:t,fonts:o,ignoreGlobalStyles:n,onBeforePrint:r,onPrintError:d,preserveAfterPrint:u,suppressErrors:p}=e,h=(0,s.useCallback)((s=>{l(u,!0);const h=function({contentRef:e,optionalContent:t,suppressErrors:o}){return t&&(e&&i({level:"warning",messages:['"react-to-print" received a `contentRef` option and a optional-content param passed to its callback. The `contentRef` option will be ignored.']}),"function"==typeof t)?t():e?e.current:void i({messages:['"react-to-print" did not receive a `contentRef` option or a optional-content param pass to its callback.'],suppressErrors:o})}({contentRef:t,optionalContent:s,suppressErrors:p});if(!h)return void i({messages:["There is nothing to print"],suppressErrors:p});const g=h.cloneNode(!0),m=document.querySelectorAll("link[rel~='stylesheet'], link[as='style']"),b=g.querySelectorAll("img"),y=g.querySelectorAll("video"),v=o?o.length:0,w=(n?0:m.length)+b.length+y.length+v,E=[],A=[],T=function(){const e=document.createElement("iframe");return e.width=`${document.documentElement.clientWidth}px`,e.height=`${document.documentElement.clientHeight}px`,e.style.position="absolute",e.style.top=`-${document.documentElement.clientHeight+100}px`,e.style.left=`-${document.documentElement.clientWidth+100}px`,e.id="printWindow",e.srcdoc="<!DOCTYPE html>",e}(),x=(t,o)=>{E.includes(t)?i({level:"debug",messages:["Tried to mark a resource that has already been handled",t],suppressErrors:p}):(o?(i({messages:['"react-to-print" was unable to load a resource but will continue attempting to print the page',...o],suppressErrors:p}),A.push(t)):E.push(t),E.length+A.length===w&&c(T,e))},k={contentNode:h,clonedContentNode:g,clonedImgNodes:b,clonedVideoNodes:y,numResourcesToLoad:w,originalCanvasNodes:h.querySelectorAll("canvas")};r?r().then((()=>{f(T,x,k,e)})).catch((e=>{null==d||d("onBeforePrint",a(e))})):f(T,x,k,e)}),[e]);return h}return r}()}));

@@ -1,2 +0,2 @@

export type Font = {
export interface Font {
family: string;

@@ -6,2 +6,2 @@ source: string;

style?: string;
};
}
import { ContentNode } from "../types/ContentNode";
import type { UseReactToPrintOptions } from "../types/UseReactToPrintOptions";
import { UseReactToPrintHookContent } from "../types/UseReactToPrintHookContent";
type GetContentNodesArgs = {
interface GetContentNodesArgs {
contentRef?: UseReactToPrintOptions["contentRef"];
optionalContent?: UseReactToPrintHookContent;
suppressErrors?: boolean;
};
}
export declare function getContentNode({ contentRef, optionalContent, suppressErrors }: GetContentNodesArgs): ContentNode;
export {};
import { Font } from "../types/font";
import type { UseReactToPrintOptions } from "../types/UseReactToPrintOptions";
export type HandlePrintWindowOnLoadData = {
export interface HandlePrintWindowOnLoadData {
contentNode: Node;

@@ -10,5 +10,5 @@ clonedContentNode: Node;

originalCanvasNodes: never[] | NodeListOf<HTMLCanvasElement>;
};
}
type MarkLoaded = (resource: Element | Font | FontFace, errorMessages?: unknown[]) => void;
export declare function handlePrintWindowOnLoad(printWindow: HTMLIFrameElement, markLoaded: MarkLoaded, data: HandlePrintWindowOnLoadData, options: UseReactToPrintOptions): void;
export {};

@@ -1,7 +0,7 @@

type LogMessagesArgs = {
interface LogMessagesArgs {
level?: 'error' | 'warning' | 'debug';
messages: unknown[];
suppressErrors?: boolean;
};
}
export declare function logMessages({ level, messages, suppressErrors }: LogMessagesArgs): void;
export {};
{
"name": "react-to-print",
"version": "3.0.2",
"version": "3.0.3-beta-1",
"description": "Print React components in the browser",

@@ -13,3 +13,3 @@ "main": "lib/index.js",

"lint": "eslint ./src",
"prepare": "npm run build && husky install",
"prepare": "npm run lint && npm run build && husky install",
"start": "NODE_ENV=development webpack serve"

@@ -40,13 +40,13 @@ },

"devDependencies": {
"@types/react": "^18.3.10",
"@types/react-dom": "^18.3.0",
"@typescript-eslint/eslint-plugin": "^8.7.0",
"@typescript-eslint/parser": "^8.7.0",
"acorn": "^8.12.1",
"@eslint/js": "^9.16.0",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"acorn": "^8.14.0",
"clean-webpack-plugin": "^4.0.0",
"copy-webpack-plugin": "^12.0.2",
"css-loader": "^7.1.2",
"eslint": "^8.56.0",
"html-webpack-plugin": "^5.6.0",
"husky": "^9.1.6",
"eslint": "^9.16.0",
"eslint-plugin-react": "^7.37.2",
"html-webpack-plugin": "^5.6.3",
"husky": "^9.1.7",
"lint-staged": "^15.2.10",

@@ -58,6 +58,7 @@ "react": "^18.3.1",

"ts-loader": "^9.5.1",
"tslib": "^2.7.0",
"typescript": "^5.6.2",
"tslib": "^2.8.1",
"typescript": "^5.7.2",
"typescript-eslint": "^8.16.0",
"url-loader": "^4.1.1",
"webpack": "^5.95.0",
"webpack": "^5.96.1",
"webpack-cli": "^5.1.4",

@@ -64,0 +65,0 @@ "webpack-dev-server": "^5.1.0"

@@ -12,2 +12,4 @@ <p align="center">

`npm install --save react-to-print`
## Demo

@@ -17,11 +19,8 @@

## Install
## Usage
`npm install --save react-to-print`
```tsx
import { useReactToPrint } from "react-to-print";
import { useRef } from "react";
## API
### Usage
```tsx
const contentRef = useRef<HTMLDivElement>(null);

@@ -32,3 +31,3 @@ const reactToPrintFn = useReactToPrint({ contentRef });

<div>
<button onClick={reactToPrintFn}>Print</button>
<button onClick={() => reactToPrintFn()}>Print</button>
<div ref={contentRef}>Content to print</div>

@@ -39,23 +38,23 @@ </div>

### Options
It is also possible to lazy set the ref if your content being printed is dynamic. See the [`LazyContent`](https://github.com/MatthewHerbst/react-to-print/blob/master/examples/LazyContent/index.tsx) example for more. This can also be useful for setting the ref in non-React code, such as util functions.
## API
| Option | Type | Description |
| :-------------------: | :------- | :---------------------------------------------------------------------------------------------------------------------------------- |
| **`bodyClass?`** | `string` | One or more class names to pass to the print window, separated by spaces |
| **`contentRef?`** | `React.RefObject<Element \| Text>` | The ref pointing to the content to be printed. Alternatively, pass the ref directly to the callback returned by `useReactToPrint` |
| **`documentTitle?`** | `string` | Set the title for printing when saving as a file. Ignored when passing a custom `print` option |
| **`fonts?`** | `{ family: string, source: string; weight?: string; style?: string; }[]` | A list of fonts to load into the printing iframe. This is useful if you are using custom fonts |
| **`ignoreGlobalStyles?`** | `boolean` | Ignore all `<style>` and `<link type="stylesheet" />` tags from `<head>` |
| **`nonce?`** | `string` | Set the [`nonce`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/nonce) attribute for allow-listing script and style elements for Content Security Policy (CSP) |
| **`onAfterPrint?`** | `() => void` | Callback function that triggers after the print dialog is closed _regardless of if the user selected to print or cancel_ |
| **`onBeforePrint?`** | `() => Promise<void>` | Callback function that triggers before print. This can be used to change the content on the page before printing as an alternative to, or in conjunction with `@media print` queries |
| **`onPrintError?`** | `(errorLocation: 'onBeforePrint' \| 'print', error: Error) => void` | Called if there is a printing error serious enough that printing cannot continue. Currently limited to Promise rejections in `onBeforePrint`, and `print`. Use this to attempt to print again. `errorLocation` will tell you where the Promise was rejected |
| **`pageStyle?`** | `string` | `react-to-print` sets some basic styles to help improve page printing, notably, removing the header and footer that most browsers add. Use this to override these styles and provide your own |
| **`preserveAfterPrint?`** | `boolean` | Preserve the print iframe after printing. This can be useful for debugging by inspecting the print iframe |
| **`print?`** | `(iframe: HTMLIFrameElement) => Promise<void>` | If passed, this function will be used instead of `window.print` to print the content. Use this to print in non-browser environments such as Electron |
| **`suppressErrors?`** | `boolean` | When passed, prevents `console` logging of errors |
| **`copyShadowRoots?`** | `boolean` | When passed, shadow root content will be copied to print window. WARNING: Use with care if you print large documents. TreeWalker's are used to traverse source and target documents. |
| **`bodyClass`** | `string` | One or more class names to pass to the print window, separated by spaces |
| **`contentRef`** | `React.RefObject<Element \| Text>` | The ref pointing to the content to be printed. Alternatively, pass the ref directly to the callback returned by `useReactToPrint` |
| **`copyShadowRoots`** | `boolean` | Copy shadow root content into the print window. Warning: Use with care if you print large documents as traversing these can be slow. |
| **`documentTitle`** | `string` | Set the title for printing when saving as a file |
| **`fonts`** | `{ family: string, source: string; weight?: string; style?: string; }[]` | A list of fonts to load into the printing iframe. This is useful if you are using custom fonts |
| **`ignoreGlobalStyles`** | `boolean` | Ignore all `<style>` and `<link type="stylesheet" />` tags |
| **`nonce`** | `string` | Set the [`nonce`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/nonce) attribute for allow-listing script and style elements for Content Security Policy (CSP) |
| **`onAfterPrint`** | `() => void` | Callback function that triggers after the print dialog is closed _regardless of if the user selected to print or cancel_ |
| **`onBeforePrint`** | `() => Promise<void>` | Callback function that triggers before print. This can be used to change the content on the page before printing as an alternative to, or in conjunction with, `@media print` queries |
| **`onPrintError`** | `(errorLocation: 'onBeforePrint' \| 'print', error: Error) => void` | Called if there is a printing error serious enough that printing cannot continue. Currently limited to Promise rejections in `onBeforePrint`, and `print`. |
| **`pageStyle`** | `string` | `react-to-print` sets some basic styles to help improve page printing, notably, removing the header and footer that most browsers add. Use this to override these styles and provide your own |
| **`preserveAfterPrint`** | `boolean` | Preserve the print iframe after printing. This can be useful for debugging by inspecting the print iframe |
| **`print`** | `(iframe: HTMLIFrameElement) => Promise<void>` | If passed, this function will be used instead of `window.print` to print the content. Use this to print in non-browser environments such as Electron |
| **`suppressErrors`** | `boolean` | When passed, prevents `console` logging of errors |
The hook returns a function that will initiate the print process when called. This function can also be optionally passed the `content` when called, allowing for its use in conditional rendering logic (where hooks are not allowed) and/or in non-React code such as a util function. See the repo examples for more.
## Compatibility

@@ -103,5 +102,31 @@

### How can content be hidden/shown during printing?
The simplest way to hide or show content during printing is to use a [CSS Media Query](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_media_queries/Using_media_queries).
```css
.printContent {
display: none;
@media print {
display: block;
}
}
```
```tsx
const contentRef = useRef<HTMLDivElement>(null);
const reactToPrintFn = useReactToPrint({ contentRef });
return (
<div>
<button onClick={reactToPrintFn}>Print</button>
<div className="printContent" ref={contentRef}>Content to print</div>
</div>
);
```
### Can `react-to-print` be used to download a PDF without using the Print Preview window?
No. We aren't able to print a PDF as we lose control once the print preview window opens. However, it should be very easy to use `react-to-print` to take the information you need and pass it to a library that can generate a PDF.
Not directly. We aren't able to print a PDF as we lose control once the print preview window opens. However, it is possible to use `react-to-print` to gather the content you want to print and pass it to a library that can generate a PDF.

@@ -178,3 +203,3 @@ ```tsx

const [isPrinting, setIsPrinting] = useState(false);
const printRef = useRef(null);
const contentRef = useRef(null);

@@ -193,3 +218,3 @@ // We store the resolve Promise being used in `onBeforePrint` here

const handlePrint = useReactToPrint({
content: () => printRef.current,
contentRef,
onBeforePrint: () => {

@@ -209,3 +234,3 @@ return new Promise((resolve) => {

Note: for Class components, just pass the `resolve` to the callback for `this.setState`: `this.setState({ isPrinting: false }, resolve)`
Note: for Class components, pass the Promise `resolve` to the callback for `this.setState`: `this.setState({ isPrinting: false }, resolve)`

@@ -436,6 +461,10 @@ ### Changing print settings in the print dialog

*NOTE*: The library is tested and built locally using Node >= 20.
*NOTE*: The library is built and tested locally using Node ^20.
## Related
- Clone the repo
- `npm ci`
- `npm start`
* [vue-to-print](https://github.com/siaikin/vue-to-print): vue3 version of react-to-print
## Related Packages
- [vue-to-print](https://github.com/siaikin/vue-to-print): vue3 version of react-to-print
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc