{"id":2289,"date":"2022-01-26T09:22:09","date_gmt":"2022-01-26T09:22:09","guid":{"rendered":"https:\/\/lvboard.infostore.in.ua\/?p=2289"},"modified":"2022-01-26T09:22:09","modified_gmt":"2022-01-26T09:22:09","slug":"react-pdf-rendering","status":"publish","type":"post","link":"https:\/\/lvboard.infostore.in.ua\/?p=2289","title":{"rendered":"React &#038; PDF Rendering"},"content":{"rendered":"\n<p><strong>Portable Document Format (PDF)<\/strong> &#8211; developed 30 years ago still exists and is one of the most widely-used documents formats. There are many reasons why people still prefer to use them such as the widely supported document format which works is compatible with many devices and apps, and the content always remains the same format.<\/p>\n\n\n\n<!--more-->\n\n\n\n<h3><a href=\"https:\/\/dev.to\/przpiw\/react-pdf-rendering-4g7b#what-is-reactpdf-\"><\/a> What is React-PDF ?<\/h3>\n\n\n\n<p>React-pdf lets us render documents on server and web.<br>It exports a set of React primitives that can be used to render things into documents easily and we can use CSS properties for styling and flexbox for layout. A list of supported primitives can be found <a href=\"https:\/\/react-pdf.org\/components\">here<\/a> It supports rendering text, images, SVGs and many more.<\/p>\n\n\n\n<h3><a href=\"https:\/\/dev.to\/przpiw\/react-pdf-rendering-4g7b#what-we-going-to-build-\"><\/a> What we going to build ?<\/h3>\n\n\n\n<p>Today we will be looking at how we can create and style PDF with react-pdf renderer. React-pdf package lets us create awesome looking PDFs using React. Its simple to use and the documentation is developer-friendly. We will create a simple application that dynamically updates our PDF-styled template which we render in DOM.<\/p>\n\n\n\n<p>This example will show how you can render the document in DOM and how directly save the document into the file without the need of displaying it.<\/p>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--ngvoTeb7--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/vvr35htmnh72zivmsmvf.png\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--ngvoTeb7--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880\/https:\/\/dev-to-uploads.s3.amazonaws.com\/uploads\/articles\/vvr35htmnh72zivmsmvf.png\" alt=\"Demo\"\/><\/a><\/figure>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<h3><a href=\"https:\/\/dev.to\/przpiw\/react-pdf-rendering-4g7b#1-setup\"><\/a> 1. Setup<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>npx create-react-app app &amp;&amp; cd app &amp;&amp; yarn add @react-pdf\/renderer\n<\/code><\/pre>\n\n\n\n<p>As in the time of writing tutorial react-pdf render need some extra dependencies and craco configuration.<br><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>yarn add process browserify-zlib stream-browserify util buffer assert @craco\/craco\n<\/code><\/pre>\n\n\n\n<p>Change the scripts section in package.json as below:<br><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>  \"scripts\": {\n    \"start\": \"craco start\",\n    \"build\": \"craco build\",\n    \"test\": \"craco test\",\n    \"eject\": \"react-scripts eject\"\n  },\n<\/code><\/pre>\n\n\n\n<p>Next, create a new file in the root of the project<br>craco.config.js with<br><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>const webpack = require(\"webpack\");\n\nmodule.exports = {\n  webpack: {\n    configure: {\n      resolve: {\n        fallback: {\n          process: require.resolve(\"process\/browser\"),\n          zlib: require.resolve(\"browserify-zlib\"),\n          stream: require.resolve(\"stream-browserify\"),\n          util: require.resolve(\"util\"),\n          buffer: require.resolve(\"buffer\"),\n          asset: require.resolve(\"assert\"),\n        },\n      },\n      plugins: &#91;\n        new webpack.ProvidePlugin({\n          Buffer: &#91;\"buffer\", \"Buffer\"],\n          process: \"process\/browser\",\n        }),\n      ],\n    },\n  },\n};\n\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>mkdir Components &amp;&amp; cd Components &amp;&amp; mkdir PDF &amp;&amp; cd PDF &amp;&amp; touch Preview.js &amp;&amp; touch LeftSection.js &amp;&amp; touch RightSection.js\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>\u251c\u2500\u2500 App.css\n\u251c\u2500\u2500 App.js\n\u251c\u2500\u2500 index.js\n\u251c\u2500\u2500 PDF\n\u2502   \u251c\u2500\u2500 LeftSection.js\n\u2502   \u251c\u2500\u2500 Preview.js\n\u2502   \u2514\u2500\u2500 RightSection.js\n\u2514\u2500\u2500 styles\n    \u2514\u2500\u2500 index.js\n<\/code><\/pre>\n\n\n\n<p>In our <code>App.js<\/code> we will create a state that updates on user input when changes are detected we will re-render our page.<br><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import Preview from '.\/PDF\/Preview'\nimport React, { useState } from 'react'\nfunction App() {\n  const &#91;profile, setProfile] = useState({\n    type: 'Profile',\n    name: 'John Doe',\n    profession: 'Junior Developer',\n    profileImageURL: 'https:\/\/i.imgur.com\/f6L6Y57.png',\n    display: true,\n    about: 'About...',\n  })\n\n  const handleChange = (name, value) =&gt; {\n    setProfile({ ...profile, &#91;name]: value })\n  }\n\n  return (\n    &lt;div\n      style={{\n        width: '100%',\n        height: '100vh',\n        display: 'flex',\n      }}\n    &gt;\n      &lt;div style={{ width: '50%' }}&gt;\n        &lt;div&gt;\n          &lt;label&gt;Name&lt;\/label&gt;\n          &lt;input\n            name='name'\n            defaultValue={profile.name}\n            onChange={(e) =&gt; {\n              handleChange(e.target.name, e.target.value)\n            }}\n          \/&gt;\n        &lt;\/div&gt;\n        &lt;div&gt;\n          &lt;label&gt;Profession&lt;\/label&gt;\n          &lt;input\n            name='profession'\n            defaultValue={profile.profession}\n            onChange={(e) =&gt; {\n              handleChange(e.target.name, e.target.value)\n            }}\n          \/&gt;\n        &lt;\/div&gt;\n        &lt;div&gt;\n          &lt;label&gt;ImageURL&lt;\/label&gt;\n          &lt;input\n            name='profileImageURL'\n            defaultValue={profile.profileImageURL}\n            onChange={(e) =&gt; {\n              handleChange(e.target.name, e.target.value)\n            }}\n          \/&gt;\n        &lt;\/div&gt;\n        &lt;div&gt;\n          &lt;label&gt;About&lt;\/label&gt;\n          &lt;input\n            name='about'\n            defaultValue={profile.about}\n            onChange={(e) =&gt; {\n              handleChange(e.target.name, e.target.value)\n            }}\n          \/&gt;\n        &lt;\/div&gt;\n      &lt;\/div&gt;\n      &lt;Preview profile={profile} \/&gt;\n    &lt;\/div&gt;\n  )\n}\n\nexport default App\n\n<\/code><\/pre>\n\n\n\n<p><code>Preview.js<\/code><br>This will let us render a preview on half of the page and embed the Template document that we are about to create.<br>We also have PDFDownloadLink which can be used to download pdf without the need of rendering it in the DOM.<br><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import React from 'react'\nimport { Document, Page, PDFViewer, PDFDownloadLink } from '@react-pdf\/renderer'\nimport LeftSection from '.\/LeftSection'\nimport { RightSection } from '.\/RightSection'\nimport styles from '..\/styles'\n\nconst Preview = ({ profile }) =&gt; {\n  return (\n    &lt;div style={{ flexGrow: 1 }}&gt;\n      &lt;PDFViewer\n        showToolbar={false}\n        style={{\n          width: '100%',\n          height: '95%',\n        }}\n      &gt;\n        &lt;Template profile={profile} \/&gt;\n      &lt;\/PDFViewer&gt;\n      &lt;PDFDownloadLink\n        document={&lt;Template profile={profile} \/&gt;}\n        fileName='somename.pdf'\n      &gt;\n        {({ loading }) =&gt; (loading ? 'Loading document...' : 'Download now!')}\n      &lt;\/PDFDownloadLink&gt;\n    &lt;\/div&gt;\n  )\n}\n\/\/ Create Document Component\nconst Template = ({ profile }) =&gt; {\n  return (\n    &lt;Document&gt;\n      &lt;Page size='A4' style={styles.page}&gt;\n        \/\/ We will divide our document into 2 columns\n        &lt;LeftSection profile={profile} \/&gt;\n        &lt;RightSection about={profile.about} \/&gt;\n      &lt;\/Page&gt;\n    &lt;\/Document&gt;\n  )\n}\n\nexport default Preview\n\n\n\n<\/code><\/pre>\n\n\n\n<p>We will also create folder with styles where we will keep stylesSheet for react-render primitives.<br><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>mkdir styles &amp;&amp; cd styles &amp;&amp; mkdir index.js\n<\/code><\/pre>\n\n\n\n<p>styles<br><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { StyleSheet } from '@react-pdf\/renderer'\n\nexport default StyleSheet.create({\n  page: {\n    display: 'flex',\n    flexDirection: 'row',\n  },\n  section_right: {\n    margin: 10,\n    padding: 10,\n    paddingTop: 20,\n    width: '75%',\n  },\n  section_left: {\n    width: '25%',\n    height: '100%',\n    backgroundColor: '#084c41',\n  },\n  profile_container: {\n    display: 'flex',\n    flexDirection: 'column',\n    alignItems: 'center',\n    marginTop: '20',\n    marginBottom: '20px',\n    height: '150',\n    fontFamily: 'Helvetica-Bold',\n  },\n  name_text: {\n    paddingTop: '10px',\n    paddingBottom: '5px',\n    fontSize: '14px',\n    fontWeight: '900',\n    color: 'white',\n  },\n  profession_text: {\n    color: '#d1d5db',\n    fontSize: '11px',\n  },\n  profile_img: {\n    width: '60px',\n    height: '60px',\n    borderRadius: '90',\n  },\n  profile_line: {\n    marginTop: '10px',\n    width: '10%',\n    height: '1px',\n    backgroundColor: '#FFF',\n    textAlign: 'center',\n  },\n})\n<\/code><\/pre>\n\n\n\n<p><code>LeftSection.js<\/code><br><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { View, Text, Image } from '@react-pdf\/renderer'\nimport styles from '..\/styles'\n\nexport const Profile = ({ profile }) =&gt; {\n  return (\n    &lt;View style={styles.profile_container}&gt;\n      &lt;Image style={styles.profile_img} src={profile.profileImageURL} \/&gt;\n\n      &lt;View\n        style={{\n          justifyContent: 'center',\n        }}\n      &gt;\n        &lt;Text style={styles.name_text}&gt;{profile.name}&lt;\/Text&gt;\n      &lt;\/View&gt;\n      &lt;Text style={styles.profession_text}&gt;{profile.profession}&lt;\/Text&gt;\n      &lt;View style={styles.profile_line} \/&gt;\n    &lt;\/View&gt;\n  )\n}\n\nconst LeftSection = ({ profile }) =&gt; {\n  return (\n    &lt;View style={styles.section_left}&gt;\n      &lt;Profile profile={profile} \/&gt;\n    &lt;\/View&gt;\n  )\n}\n\nexport default LeftSection\n\n<\/code><\/pre>\n\n\n\n<p><code>RightSection.js<\/code><br><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import styles from '..\/styles'\nimport { View, Text } from '@react-pdf\/renderer'\n\nexport const RightSection = ({ about }) =&gt; {\n  return (\n    &lt;View style={styles.section_right}&gt;\n      &lt;Text&gt;{about}&lt;\/Text&gt;\n    &lt;\/View&gt;\n  )\n}\n<\/code><\/pre>\n\n\n\n<p>Now you know it works you could create something yourself.<\/p>\n\n\n\n<p>More functional example of a resume builder that I built is here.<br><a href=\"https:\/\/pdfr-esume-builder.vercel.app\">Resume builder<\/a><\/p>\n\n\n\n<p>To sum up, this is only a simple demo to demonstrate how the pdf renderer can be used with react. React pdf package very cool tool that could be used to create things like resume builders, invoicing templates or tickets or receipts, etc. These could be either generated based on the existing data or dynamically updated on user input like in the case of our simple demo.<\/p>\n\n\n\n<p>I hope this article was helpful to some of you guys. Thanks for reading!<br><a href=\"https:\/\/github.com\/przpiw\/react-pdf-renderer-demo\">Github repo<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Portable Document Format (PDF) &#8211; developed 30 years ago still exists and is one of the most widely-used documents formats. There are many reasons why people still prefer to use them such as the widely supported document format which works is compatible with many devices and apps, and the content always remains the same format.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[30],"tags":[65],"_links":{"self":[{"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=\/wp\/v2\/posts\/2289"}],"collection":[{"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2289"}],"version-history":[{"count":1,"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=\/wp\/v2\/posts\/2289\/revisions"}],"predecessor-version":[{"id":2290,"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=\/wp\/v2\/posts\/2289\/revisions\/2290"}],"wp:attachment":[{"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2289"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2289"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/lvboard.infostore.in.ua\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2289"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}