{"id":28169,"date":"2023-06-08T07:00:00","date_gmt":"2023-06-08T14:00:00","guid":{"rendered":"http:\/\/convert-images-to-pdf-files-with-react-to-pdf"},"modified":"2025-10-21T08:43:02","modified_gmt":"2025-10-21T15:43:02","slug":"convert-images-to-pdf-files-with-react-to-pdf","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/convert-images-to-pdf-files-with-react-to-pdf","title":{"rendered":"Convert Images to PDF Files With React-to-PDF"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><p>From conveying deep messages to preserving memories and everything in between, images have become integral to the human experience. In this article, we\u2019ll look at how to save uploaded images into a PDF file with the image to PDF React converter, making it easier to share multiple images without spamming the recipient while taking up less memory. This feature can be used in an application that generates photo albums or brochures for users on the fly.<\/p>\n<p>For UI components in our application, we\u2019ll use Ant Design (antd), while react-to-pdf will be used to create a PDF document containing the images rendered by our React component.<\/p>\n<p>Dig in and play around with the demo in CodeSandbox below. Use the \u201cOpen Sandbox\u201d link in the tool to open the demo in a new tab.<\/p>\n<\/div>\n\n\n  <div class=\"wp-block-cloudinary-code-sandbox \">\n    <iframe\n      src=\"https:\/\/codesandbox.io\/embed\/react-to-pdf-demo-uhd9xz?theme=dark&amp;codemirror=1&amp;highlights=&amp;editorsize=50&amp;fontsize=14&amp;expanddevtools=0&amp;hidedevtools=0&amp;eslint=0&amp;forcerefresh=0&amp;hidenavigation=0&amp;initialpath=%2F&amp;module=&amp;moduleview=0&amp;previewwindow=&amp;view=&amp;runonclick=1\"\n      height=\"500\"\n      style=\"width: 100%;\"\n      title=\"react-to-pdf-demo-uhd9xz\"\n      loading=\"lazy\"\n      allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n      sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n    ><\/iframe>\n  <\/div>\n\n\n<div class=\"wp-block-cloudinary-markdown \"><h2>React to PDF Converter for Images Project Setup<\/h2>\n<p>Create a <a href=\"https:\/\/reactjs.org\/\">React<\/a> app using the following command:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">npx create-react-app react-pdf_demo\n<\/code><\/span><\/pre>\n<p>Next, add the project dependencies using the following command:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">npm<\/span> <span class=\"hljs-selector-tag\">install<\/span> <span class=\"hljs-selector-tag\">antd<\/span> <span class=\"hljs-keyword\">@ant-design<\/span>\/icons react-to-pdf\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Next, we need to import the antd CSS. To do this, open your <code>src\/App.css<\/code> file and edit its content to match the following:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-keyword\">@import<\/span> <span class=\"hljs-string\">\"~antd\/dist\/antd.css\"<\/span>;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<h2>Add Hook<\/h2>\n<p>We\u2019ll create a hook that will contain the code to provide the necessary functionality associated with file selection. This makes for better abstraction of code as well as leaner components.<\/p>\n<p>In the <code>src<\/code> folder, create a new folder named <code>hooks<\/code>. In the <code>src\/hooks<\/code> folder, create a new file called <code>useFileSelection.js<\/code> and add the following to it.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> { useCallback, useEffect, useState } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react\"<\/span>;\n\n<span class=\"hljs-keyword\">const<\/span> useFileSelection = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n  <span class=\"hljs-keyword\">const<\/span> &#91;selectedFiles, setSelectedFiles] = useState(&#91;]);\n  <span class=\"hljs-keyword\">const<\/span> &#91;base64Strings, setBase64Strings] = useState(&#91;]);\n  <span class=\"hljs-keyword\">const<\/span> &#91;isLoading, setIsLoading] = useState(<span class=\"hljs-literal\">false<\/span>);\n  <span class=\"hljs-keyword\">const<\/span> addFile = <span class=\"hljs-function\">(<span class=\"hljs-params\">file<\/span>) =&gt;<\/span> {\n    setSelectedFiles(<span class=\"hljs-function\">(<span class=\"hljs-params\">currentSelection<\/span>) =&gt;<\/span> &#91;...currentSelection, file]);\n  };\n\n  <span class=\"hljs-keyword\">const<\/span> removeFile = <span class=\"hljs-function\">(<span class=\"hljs-params\">file<\/span>) =&gt;<\/span> {\n    setSelectedFiles(<span class=\"hljs-function\">(<span class=\"hljs-params\">currentSelection<\/span>) =&gt;<\/span> {\n      <span class=\"hljs-keyword\">const<\/span> fileIndex = currentSelection.indexOf(file);\n      <span class=\"hljs-keyword\">const<\/span> newSelection = currentSelection.slice();\n      newSelection.splice(fileIndex, <span class=\"hljs-number\">1<\/span>);\n      <span class=\"hljs-keyword\">return<\/span> newSelection;\n    });\n  };\n\n  <span class=\"hljs-keyword\">const<\/span> getBase64Representation = <span class=\"hljs-function\">(<span class=\"hljs-params\">file<\/span>) =&gt;<\/span>\n    <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Promise<\/span>(<span class=\"hljs-function\">(<span class=\"hljs-params\">resolve, reject<\/span>) =&gt;<\/span> {\n      <span class=\"hljs-keyword\">const<\/span> reader = <span class=\"hljs-keyword\">new<\/span> FileReader();\n      reader.readAsDataURL(file);\n      reader.onload = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> resolve(reader.result);\n      reader.onerror = <span class=\"hljs-function\">(<span class=\"hljs-params\">error<\/span>) =&gt;<\/span> reject(error);\n    });\n\n  <span class=\"hljs-keyword\">const<\/span> getBase64Strings = useCallback(<span class=\"hljs-keyword\">async<\/span> () =&gt; {\n    setIsLoading(<span class=\"hljs-literal\">true<\/span>);\n    <span class=\"hljs-keyword\">const<\/span> base64Strings = <span class=\"hljs-keyword\">await<\/span> <span class=\"hljs-built_in\">Promise<\/span>.all(\n      selectedFiles.map(<span class=\"hljs-function\">(<span class=\"hljs-params\">file<\/span>) =&gt;<\/span> getBase64Representation(file))\n    );\n    setBase64Strings(base64Strings);\n    setIsLoading(<span class=\"hljs-literal\">false<\/span>);\n  }, &#91;selectedFiles]);\n\n  useEffect(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n    getBase64Strings().catch(<span class=\"hljs-built_in\">console<\/span>.error);\n  }, &#91;getBase64Strings]);\n  <span class=\"hljs-keyword\">return<\/span> &#91;addFile, removeFile, base64Strings, isLoading];\n};\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> useFileSelection;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This hook contains three state variables. <code>selectedFiles<\/code> keeps track of the files the user has selected, <code>base64Strings<\/code> holds the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Base64\">base64<\/a> encoded string for each selected file, and the <code>isLoading<\/code> state variable is used to indicate whether or not the encoding process is ongoing. Next, we declare two functions, <code>addFile<\/code> and <code>removeFile<\/code>, which are used to update the file selection.<\/p>\n<p>The <code>getBase64Representation<\/code> function takes a file and generates the base64 encoding of the provided file. This process is asynchronous, and as a result, the function returns a promise. This function is used in the <code>getBase64Strings<\/code> to update the base64 strings whenever the <code>selectedFiles<\/code> state variable changes. Finally, with the <code>useEffect<\/code> hook, we call the <code>getBase64Strings<\/code> whenever the list of selected files changes.<\/p>\n<p>The last thing we do is export an array containing the <code>addFile<\/code>, <code>removeFile<\/code> functions, and the <code>base64Strings<\/code> and <code>isLoading<\/code> variables.<\/p>\n<h2>Add <code>UploadButton<\/code> Component<\/h2>\n<p>Next, we need a component to handle the selection of images. In the <code>src<\/code> directory, create a new folder named <code>components<\/code>. In the <code>src\/components<\/code> directory, create a new file named <code>UploadButton.js<\/code> and add the following to it:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> { UploadOutlined } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@ant-design\/icons\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { Button, Upload } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"antd\"<\/span>;\n\n<span class=\"hljs-keyword\">const<\/span> UploadButton = <span class=\"hljs-function\">(<span class=\"hljs-params\">{ addFile, removeFile, loading }<\/span>) =&gt;<\/span> {\n  <span class=\"hljs-keyword\">const<\/span> beforeUpload = <span class=\"hljs-function\">(<span class=\"hljs-params\">file<\/span>) =&gt;<\/span> {\n    addFile(file);\n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-literal\">false<\/span>;\n  };\n  <span class=\"hljs-keyword\">const<\/span> props = {\n    <span class=\"hljs-attr\">onRemove<\/span>: removeFile,\n    <span class=\"hljs-attr\">multiple<\/span>: <span class=\"hljs-literal\">true<\/span>,\n    <span class=\"hljs-attr\">showUploadList<\/span>: <span class=\"hljs-literal\">false<\/span>,\n    beforeUpload,\n    <span class=\"hljs-attr\">accept<\/span>: <span class=\"hljs-string\">\"image\/*\"<\/span>,\n  };\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Upload<\/span> {<span class=\"hljs-attr\">...props<\/span>}&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Button<\/span> <span class=\"hljs-attr\">loading<\/span>=<span class=\"hljs-string\">{loading}<\/span> <span class=\"hljs-attr\">icon<\/span>=<span class=\"hljs-string\">{<\/span>&lt;<span class=\"hljs-attr\">UploadOutlined<\/span> \/&gt;<\/span>} type=\"primary\" ghost&gt;\n        Click to Upload\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Button<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Upload<\/span>&gt;<\/span><\/span>\n  );\n};\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> UploadButton;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This component renders an antd <a href=\"https:\/\/ant.design\/components\/upload\/\">Upload<\/a> component that provides the <code>addFile<\/code>, <code>removeFile<\/code> functions, and <code>isLoading<\/code> boolean received as props. Additionally, we declared a <code>beforeUpload<\/code> function which overrides <a href=\"https:\/\/ant.design\/\">antd\u2019s<\/a> default behavior of trying to upload the image to a server.\nIn our case, we want the new file to be added to our state variable and nothing else; hence the <code>beforeUpload<\/code> function returns <code>false<\/code>.<\/p>\n<h2>Putting Everything Together<\/h2>\n<p>The last thing we need to do is update our <code>src\/App.js<\/code> file to render our upload button and display a grid of images (which are targeted and used in the pdf generation). To do this, open your <code>src\/App.js<\/code> file and update it to match the following:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">\".\/App.css\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { useRef } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> useFileSelection <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\".\/hooks\/useFileSelection\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> UploadButton <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\".\/components\/UploadButton\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { Button, Row, Col } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"antd\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> Pdf <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react-to-pdf\"<\/span>;\n\n<span class=\"hljs-keyword\">const<\/span> App = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n  <span class=\"hljs-keyword\">const<\/span> &#91;addFile, removeFile, base64Strings, isLoading] = useFileSelection();\n  <span class=\"hljs-keyword\">const<\/span> ref = useRef();\n\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">style<\/span>=<span class=\"hljs-string\">{{<\/span> <span class=\"hljs-attr\">margin:<\/span> \"<span class=\"hljs-attr\">2<\/span>%\" }}&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Row<\/span> <span class=\"hljs-attr\">justify<\/span>=<span class=\"hljs-string\">\"center\"<\/span> <span class=\"hljs-attr\">style<\/span>=<span class=\"hljs-string\">{{<\/span> <span class=\"hljs-attr\">marginBottom:<\/span> \"<span class=\"hljs-attr\">10px<\/span>\" }}&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Col<\/span> <span class=\"hljs-attr\">span<\/span>=<span class=\"hljs-string\">{6}<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">UploadButton<\/span>\n            <span class=\"hljs-attr\">addFile<\/span>=<span class=\"hljs-string\">{addFile}<\/span>\n            <span class=\"hljs-attr\">removeFile<\/span>=<span class=\"hljs-string\">{removeFile}<\/span>\n            <span class=\"hljs-attr\">loading<\/span>=<span class=\"hljs-string\">{isLoading}<\/span>\n          \/&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Col<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Col<\/span> <span class=\"hljs-attr\">span<\/span>=<span class=\"hljs-string\">{6}<\/span>&gt;<\/span>\n          {base64Strings.length &gt;= 1 &amp;&amp; (\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Pdf<\/span>\n              <span class=\"hljs-attr\">targetRef<\/span>=<span class=\"hljs-string\">{ref}<\/span>\n              <span class=\"hljs-attr\">filename<\/span>=<span class=\"hljs-string\">\"images.pdf\"<\/span>\n              <span class=\"hljs-attr\">options<\/span>=<span class=\"hljs-string\">{{<\/span> <span class=\"hljs-attr\">orientation:<\/span> \"<span class=\"hljs-attr\">landscape<\/span>\" }}\n              <span class=\"hljs-attr\">scale<\/span>=<span class=\"hljs-string\">{0.9}<\/span>\n            &gt;<\/span>\n              {({ toPdf }) =&gt; (\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Button<\/span> <span class=\"hljs-attr\">danger<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{toPdf}<\/span>&gt;<\/span>\n                  Generate Pdf\n                <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Button<\/span>&gt;<\/span>\n              )}\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Pdf<\/span>&gt;<\/span>\n          )}\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Col<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Row<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">ref<\/span>=<span class=\"hljs-string\">{ref}<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Row<\/span> <span class=\"hljs-attr\">gutter<\/span>=<span class=\"hljs-string\">{&#91;0,<\/span> <span class=\"hljs-attr\">16<\/span>]} <span class=\"hljs-attr\">justify<\/span>=<span class=\"hljs-string\">\"center\"<\/span>&gt;<\/span>\n          {base64Strings.map((base64String, index) =&gt; (\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Col<\/span> <span class=\"hljs-attr\">span<\/span>=<span class=\"hljs-string\">{5}<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">img<\/span>\n                <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">{base64String}<\/span>\n                <span class=\"hljs-attr\">key<\/span>=<span class=\"hljs-string\">{index}<\/span>\n                <span class=\"hljs-attr\">style<\/span>=<span class=\"hljs-string\">{{<\/span> <span class=\"hljs-attr\">height:<\/span> \"<span class=\"hljs-attr\">200px<\/span>\", <span class=\"hljs-attr\">width:<\/span> \"<span class=\"hljs-attr\">250px<\/span>\" }}\n              \/&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Col<\/span>&gt;<\/span>\n          ))}\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Row<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n  );\n};\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> App;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>First, we retrieve the functions and variables to help with the file selection process from our previously declared <code>useFileSelection<\/code> hook. Next, we create a mutable ref object using the <code>useRef<\/code> hook.\nThe rendered component consists of two rows. The first row holds the button to upload images and another to generate the pdf file from the uploaded images &#8211; the latter which is wrapped in a PDF component. The PDF component has four props, namely:<\/p>\n<ol>\n<li>\n<code>targetRef<\/code> &#8211; This is the ref for the target component (in our case, the div element wrapping the second row).<\/li>\n<li>\n<code>filename<\/code> &#8211; This is the name that should be given to the generated pdf document.<\/li>\n<li>\n<code>options<\/code> &#8211; You can view the complete list of available options <a href=\"https:\/\/rawgit.com\/MrRio\/jsPDF\/master\/docs\/\">here<\/a>. For our use case, we change the page orientation to landscape. This provides more real estate for our images and allows us to fit more into the page.<\/li>\n<li>\n<code>scale<\/code> &#8211; We used this to scale down the image to 0.9 of the original size.<\/li>\n<\/ol>\n<p>With everything in place, run your application using the following command:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">    npm start\n<\/code><\/span><\/pre>\n<p>By default, the application should be available at <a href=\"http:\/\/localhost:3000\/\">http:\/\/localhost:3000\/<\/a>. The final result will look like the gif shown below.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams\/s_C422BE538444E3A47B153B392632E7B3EA97BF31C5B41AB480E761E6C214E724_1655907879717_CleanShot+2022-06-22+at+15.24.08.gif\" alt=\"GIF image showing the image to pdf react process\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"800\" height=\"362\"\/><\/p>\n<p>Find the complete project <a href=\"https:\/\/github.com\/ifeoma-imoh\/react-pdf-demo\">here<\/a> on GitHub.<\/p>\n<h2>Keeping it Simple<\/h2>\n<p>While the above method is great for more advanced applications, especially ones requiring multiple image uploads, we\u2019ll also explore a simpler approach that allows users to upload a single image and then generate a PDF file from that image. This method involves direct saving to the local file system, and the use of a basic HTML input for image upload. It also provides a simple button to generate the PDF. This can be beneficial for applications that don\u2019t require complex setups or multiple image uploads.<\/p>\n<p>Here\u2019s an example of how to convert a single image to PDF using React:<\/p>\n<pre class=\"js-syntax-highlighted\"><code>import React, { useState } from &quot;react&quot;;\nimport PDF from &quot;react-to-pdf&quot;;\n\nconst App = () =&gt; {\n  const [imageData, setImageData] = useState(null);\n\n  const handleImageChange = (e) =&gt; {\n    const file = e.target.files[0];\n    const reader = new FileReader();\n    reader.onload = (e) =&gt; {\n      setImageData(e.target.result);\n    };\n    reader.readAsDataURL(file);\n  };\n\n  const handleGeneratePDF = () =&gt; {\n    const pdf = new PDF();\n    pdf.addPage(imageData);\n    pdf.save(&quot;image.pdf&quot;);\n  };\n\n  return (\n    &lt;div&gt;\n      &lt;input type=&quot;file&quot; onChange={handleImageChange} \/&gt;\n      &lt;button onClick={handleGeneratePDF}&gt;Generate PDF&lt;\/button&gt;\n    &lt;\/div&gt;\n  );\n};\n\nexport default App;\n<\/code><\/pre>\n<p>This more streamlined method offers a way to quickly integrate image-to-PDF functionality without relying heavily on external UI components. Do remember to always use code with caution and adapt wherever you see fit.<\/p>\n<h2>Conclusion<\/h2>\n<p>In this article, we looked at the image to PDF React converter that allows you to convert images into a PDF document on the fly using the react-to-pdf library (within the react to pdf converter tool). We rendered a grid of images for our demonstration, which we eventually converted to a PDF document. This is just one area of application as we could also use this functionality to render, edit and save brochures or posters, or any other graphic content for printing or further dissemination.<\/p>\n<p>If you\u2019re a developer, we recommend you take a look at how <a href=\"https:\/\/cloudinary.com\/image-api\">Cloudinary makes working with images simple with powerful AI tools<\/a> (and we provide a <a href=\"https:\/\/cloudinary.com\/users\/register_free\">free for life<\/a> account, too!).<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":87,"featured_media":29517,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[134,370,246],"class_list":["post-28169","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-guest-post","tag-image","tag-react"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>How to Use the React to PDF Converter for Images<\/title>\n<meta name=\"description\" content=\"Learn how to easily save uploaded images into a PDF file using the React to PDF converter for free.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/convert-images-to-pdf-files-with-react-to-pdf\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Convert Images to PDF Files With React-to-PDF\" \/>\n<meta property=\"og:description\" content=\"Learn how to easily save uploaded images into a PDF file using the React to PDF converter for free.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/convert-images-to-pdf-files-with-react-to-pdf\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2023-06-08T14:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-10-21T15:43:02+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1684790771\/Blog-convert-jpg-to-pdf-nextjs\/Blog-convert-jpg-to-pdf-nextjs.jpg?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"2000\" \/>\n\t<meta property=\"og:image:height\" content=\"1100\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"melindapham\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/convert-images-to-pdf-files-with-react-to-pdf#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/convert-images-to-pdf-files-with-react-to-pdf\"},\"author\":{\"name\":\"melindapham\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9\"},\"headline\":\"Convert Images to PDF Files With React-to-PDF\",\"datePublished\":\"2023-06-08T14:00:00+00:00\",\"dateModified\":\"2025-10-21T15:43:02+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/convert-images-to-pdf-files-with-react-to-pdf\"},\"wordCount\":7,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/convert-images-to-pdf-files-with-react-to-pdf#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1684790771\/Blog-convert-jpg-to-pdf-nextjs\/Blog-convert-jpg-to-pdf-nextjs.jpg?_i=AA\",\"keywords\":[\"Guest Post\",\"Image\",\"React\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2023\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/convert-images-to-pdf-files-with-react-to-pdf\",\"url\":\"https:\/\/cloudinary.com\/blog\/convert-images-to-pdf-files-with-react-to-pdf\",\"name\":\"How to Use the React to PDF Converter for Images\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/convert-images-to-pdf-files-with-react-to-pdf#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/convert-images-to-pdf-files-with-react-to-pdf#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1684790771\/Blog-convert-jpg-to-pdf-nextjs\/Blog-convert-jpg-to-pdf-nextjs.jpg?_i=AA\",\"datePublished\":\"2023-06-08T14:00:00+00:00\",\"dateModified\":\"2025-10-21T15:43:02+00:00\",\"description\":\"Learn how to easily save uploaded images into a PDF file using the React to PDF converter for free.\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/convert-images-to-pdf-files-with-react-to-pdf#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/convert-images-to-pdf-files-with-react-to-pdf\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/convert-images-to-pdf-files-with-react-to-pdf#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1684790771\/Blog-convert-jpg-to-pdf-nextjs\/Blog-convert-jpg-to-pdf-nextjs.jpg?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1684790771\/Blog-convert-jpg-to-pdf-nextjs\/Blog-convert-jpg-to-pdf-nextjs.jpg?_i=AA\",\"width\":2000,\"height\":1100,\"caption\":\"Image showing graphic representation of the react to pdf converter including a screenshot of images of puppies and the code that converted the images to PDF\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/convert-images-to-pdf-files-with-react-to-pdf#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Convert Images to PDF Files With React-to-PDF\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9\",\"name\":\"melindapham\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g\",\"caption\":\"melindapham\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"How to Use the React to PDF Converter for Images","description":"Learn how to easily save uploaded images into a PDF file using the React to PDF converter for free.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cloudinary.com\/blog\/convert-images-to-pdf-files-with-react-to-pdf","og_locale":"en_US","og_type":"article","og_title":"Convert Images to PDF Files With React-to-PDF","og_description":"Learn how to easily save uploaded images into a PDF file using the React to PDF converter for free.","og_url":"https:\/\/cloudinary.com\/blog\/convert-images-to-pdf-files-with-react-to-pdf","og_site_name":"Cloudinary Blog","article_published_time":"2023-06-08T14:00:00+00:00","article_modified_time":"2025-10-21T15:43:02+00:00","og_image":[{"width":2000,"height":1100,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1684790771\/Blog-convert-jpg-to-pdf-nextjs\/Blog-convert-jpg-to-pdf-nextjs.jpg?_i=AA","type":"image\/jpeg"}],"author":"melindapham","twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/convert-images-to-pdf-files-with-react-to-pdf#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/convert-images-to-pdf-files-with-react-to-pdf"},"author":{"name":"melindapham","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9"},"headline":"Convert Images to PDF Files With React-to-PDF","datePublished":"2023-06-08T14:00:00+00:00","dateModified":"2025-10-21T15:43:02+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/convert-images-to-pdf-files-with-react-to-pdf"},"wordCount":7,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/convert-images-to-pdf-files-with-react-to-pdf#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1684790771\/Blog-convert-jpg-to-pdf-nextjs\/Blog-convert-jpg-to-pdf-nextjs.jpg?_i=AA","keywords":["Guest Post","Image","React"],"inLanguage":"en-US","copyrightYear":"2023","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/convert-images-to-pdf-files-with-react-to-pdf","url":"https:\/\/cloudinary.com\/blog\/convert-images-to-pdf-files-with-react-to-pdf","name":"How to Use the React to PDF Converter for Images","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/convert-images-to-pdf-files-with-react-to-pdf#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/convert-images-to-pdf-files-with-react-to-pdf#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1684790771\/Blog-convert-jpg-to-pdf-nextjs\/Blog-convert-jpg-to-pdf-nextjs.jpg?_i=AA","datePublished":"2023-06-08T14:00:00+00:00","dateModified":"2025-10-21T15:43:02+00:00","description":"Learn how to easily save uploaded images into a PDF file using the React to PDF converter for free.","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/convert-images-to-pdf-files-with-react-to-pdf#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/convert-images-to-pdf-files-with-react-to-pdf"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/convert-images-to-pdf-files-with-react-to-pdf#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1684790771\/Blog-convert-jpg-to-pdf-nextjs\/Blog-convert-jpg-to-pdf-nextjs.jpg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1684790771\/Blog-convert-jpg-to-pdf-nextjs\/Blog-convert-jpg-to-pdf-nextjs.jpg?_i=AA","width":2000,"height":1100,"caption":"Image showing graphic representation of the react to pdf converter including a screenshot of images of puppies and the code that converted the images to PDF"},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/convert-images-to-pdf-files-with-react-to-pdf#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Convert Images to PDF Files With React-to-PDF"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9","name":"melindapham","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g","caption":"melindapham"}}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1684790771\/Blog-convert-jpg-to-pdf-nextjs\/Blog-convert-jpg-to-pdf-nextjs.jpg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28169","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/87"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=28169"}],"version-history":[{"count":8,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28169\/revisions"}],"predecessor-version":[{"id":38946,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28169\/revisions\/38946"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/29517"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=28169"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=28169"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=28169"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}