How to Create PDF using React JS

How to Create PDF using React JS

Introduction

Sometimes, you need to download your app's tables or data into a PDF format for easy sharing. With React PDF Renderer, you can seamlessly convert your React components into high-quality PDFs. This blog will walk you through the process, making it simple to transform your web content into shareable PDFs.

React PDF Renderer offers its own set of components, which differ slightly from standard React components or HTML tags. However, its functionality is straightforward to grasp. Once you understand the basics, you will be able to efficiently use React PDF Renderer for creating PDFs in your React applications. Before diving into the code, we'll first explore the key components provided by React PDF Renderer and understand how they work.

Prerequisites

  1. Basic knowledge of React

  2. Node.js and npm installed on your machine

  3. Familiarity with CSS

  4. An existing React project set up(this we will cover)

With these prerequisites in place, you are ready to begin the process of converting your React components into PDFs.

React PDF Renderer Components

React PDF Renderer uses various components to help you convert React components into PDFs. Here are the key components and their uses:

  • Document: The root element for creating a PDF document.

  • Page: Represents a single page within the PDF.

  • View: A container element similar to a div in HTML.

  • Text: Used for rendering text within the PDF.

  • Image: Allows you to include images in your PDF.

  • Link: Enables clickable links within the PDF.

  1. View Component:

    • Use: Acts as a container for other components, similar to <div> in HTML.

    • Styling Format: Supports styles such as width, height, margin, padding, background color, border, etc.

         <View style={{ width: 100, height: 50, backgroundColor: 'blue' }} >
          /* pdf content */
         </View>
      
  2. Text Component:

    • Use: Renders text content within the PDF document.

    • Styling Format: Supports font size, font family, font weight, text alignment, color, and other text-related styles.

        <Text style={{ fontSize: 14, fontWeight: 'bold', color: 'black' }}>
          Hello, World!
        </Text>
      
  3. Image Component:

    • Use: Embed images into the PDF document.

    • Styling Format: Supports properties like width, height, and source URL for the image.

        <Image src="example.jpg" style={{ width: 200, height: 100 }} />
      
  4. Page Component:

    • Use: Defines individual pages within the PDF document.

    • Styling Format: Supports properties like size, orientation, and margins for each page.

        <Page size="A4" style={{ margin: 10 }}>Page Content</Page>
      
  5. Link Component:

    • Use: Creates hyperlinks within the PDF document.

    • Styling Format: Supports defining the URL and styling options for the hyperlink.

        <Link src="https://example.com" style={{ color: 'blue' }}>
          Click here
        </Link>
      
  6. Document Component:

    • Use: Represents the entire PDF document.

    • Styling Format: Supports global document settings such as page size, margins, and metadata.

        <Document title="Example Document">
          <Page>
            <Text>
                Content
            </Text>
          </Page>
        </Document>
      

These are the basic components that are used while working with React PDF. You can see a complete list of components with available valid props here.

Setting Up the Environment

You can start building your PDFs in your existing app, or you can use an online REPL specifically for React PDF. The advantage of an online React PDF REPL is that we can instantly view the preview of our code. Without this preview system, we would need to download the PDF each time to view it.

So, we will use the online REPL for React PDF because it allows us to preview our code changes instantly. This immediate feedback is great for development, as it saves time and helps us catch errors early. However, I will also cover how you can set up React PDF in your React application.

Let's create a new React application, install React PDF Renderer, and write our first line of code with it.

Open your terminal and run the following command to create a new React app using Create React App.

npx create-react-app my-react-pdf-app

This command will create a new directory named my-react-pdf-app with a basic React setup.

cd my-react-pdf-app

Use npm to install the React PDF Renderer library.

npm install @react-pdf/renderer

Open the newly created project (my-react-pdf-app) in your favorite code editor (like VSCode). Create a new file named MyDocument.js in the src directory.

// src/MyDocument.js

import React from 'react';
import { Document, Page, Text, View, StyleSheet } from '@react-pdf/renderer';

// Create styles
const styles = StyleSheet.create({
  page: {
    flexDirection: 'column',
    backgroundColor: '#E4E4E4',
  },
  section: {
    margin: 10,
    padding: 10,
    flexGrow: 1,
  },
});

// Create Document Component
const MyDocument = () => (
  <Document>
    <Page size="A4" style={styles.page}>
      <View style={styles.section}>
        <Text>Section #1</Text>
      </View>
      <View style={styles.section}>
        <Text>Section #2</Text>
      </View>
    </Page>
  </Document>
);

export default MyDocument;

Open App.js and modify it to render the PDF document.

// src/App.js

import React from 'react';
import { PDFDownloadLink } from '@react-pdf/renderer';
import MyDocument from './MyDocument';

const App = () => (
  <div className="App">
    <header className="App-header">
      <PDFDownloadLink document={<MyDocument />} fileName="mypdf.pdf">
        {({ blob, url, loading, error }) =>
          loading ? 'Loading document...' : 'Download PDF now!'
        }
      </PDFDownloadLink>
    </header>
  </div>
);

export default App;

Open your terminal, make sure you are in the project directory, and start the development server.

npm start

Your default browser should automatically open and navigate to http://localhost:3000, where you will see a link to download the PDF.

But in this blog, we will use an Online Code REPL so that we can see the output instantly. Then, we can use the same code in our React app to download it. Both methods will give the same result.

Code PDF

So, we are going to code this PDF design. With this design, we will understand how all the components work. After that, you can code any PDF design.

So, in this blog, we understand that there are three major components for React PDF:

  • Document

  • Page

  • View

This PDF design is also divided into these three main components.

So, from the above diagram, I hope you understand what we need to build first. First, we will create a document using the <Document> component. Then, we will declare a <Page>, and after that, we will declare a <View> and start defining our components there.

Steps:

Basic Setup

Start with importing basic things and components we need to use for React PDF

import React from 'react';
import { Page, Text, View, Document, StyleSheet, Image } from '@react-pdf/renderer';

Document Styling

Now we will style our document. Here, we will set how our entire document looks. We will use StyleSheet.create to define the styles for our PDF components. This is similar to CSS but written in JavaScript objects:

const styles = StyleSheet.create({
  page: {
    padding: 20,
    backgroundColor: '#ffffff'
  },
  section: {
    marginBottom: 20
  }
});
// we will add more style later on.

Here, we will use the page and section styles in our components like this.

<Page style={styles.page}>

Define Data

Define the data you want to display in the PDF document. This data can be dynamic and fetched from an API or a database:

const data = [
  {
    title: 'Attack on Titan',
    studio: 'Wit Studio',
    genre: 'Action, Dark Fantasy',
    releaseDate: '04-07-2013',
    status: 'Completed',
    rating: '9.0',
    cost: '$120'
  }
];

Create Document Component

Define the MyDocument component which will structure the PDF document. The name can be anything. It is our React component.

const MyDocument = () => {
 return (
   // Our pdf code will be here
     );
};
export default MyDocument;

The component returns JSX that describes the structure of the PDF document. So, in the return statement, we will start by using our first React PDF component, which is <Document />.

const MyDocument = () => {
 return (
     <Document>
       /* Here we will steup our page */
     </Document>
     );
};
export default MyDocument;

This creates a Black PDF Document.

Create PDF Pages

Now, let's start by creating pages for our PDF. Use the <Page> component to define pages. The number of <Page> components will determine the number of pages. For example, if you use two <Page> tags, your PDF will have two pages. If you have too much data for a single page, React PDF will automatically create additional pages as needed.

The <Page> component has several props, such as size, which defines the page size like A4, A2, A3, etc., along with many other props. You can see all page props here.

// Create Document Component
const MyDocument = () => {
  return (
    <Document>
      <Page size="A4" style={styles.page}>
        <View> 
          <Text>Hello</Text>
        </View>
      </Page>
    </Document>
  );
};

export default MyDocument;

Here, we use the <Page> component and add a size prop, giving it a value. We also use the style defined in our style object. Inside the <Page> component, we are using the <View> component, and within that, we are using the <Text> component to display the text "Hello." The output will look like this:

So, the View component works just like a div. For example, if you want a big box in your PDF divided into specific columns, and you want to give each column a different color, you just need a few View components and some styling. If you need to add text, use the Text component. To add an image, use the Image component. Check the code and output below.

// Create styles
const styles = StyleSheet.create({
  page: {
    padding: 20,
    backgroundColor: '#ffffff'
  },
  section: {
    marginBottom: 20
  },
  bigBox: {
    flexDirection: 'row',
    marginBottom: 20,
    borderWidth: 1,
    borderColor: '#000',
  },
  column: {
    flex: 1,
    padding: 10,
    borderWidth: 1,
    borderColor: '#000',
  },
  column1: {
    backgroundColor: '#ffcccc',
  },
  column2: {
    backgroundColor: '#ccffcc',
  },
  column3: {
    backgroundColor: '#ccccff',
  },
  text: {
    fontSize: 12,
  },
  image: {
    width: "auto",
    height: 100,
  },
  canvas: {
    width: '100%',
    height: 100,
    borderWidth: 1,
    borderColor: '#000',
    backgroundColor: '#e0e0e0',
  }
});

// Create Document Component
const MyDocument = () => {
  return (
      <Document>
    <Page size="A4" style={styles.page}>
      <View style={[styles.bigBox]}>
        <View style={[styles.column, styles.column1]}>
          <Text style={styles.text}>This is a text column</Text>
        </View>
        <View style={[styles.column, styles.column2]}>
          <Image
            style={styles.image}
            src="https://t3.ftcdn.net/jpg/07/24/53/02/360_F_724530208_783brjeXb7pllU2HefNMxNc1TynemreM.jpg"
          />
        </View>
        <View style={[styles.column, styles.column3]}>
          <View style={styles.canvas}>
            <Text style={styles.text}>Canvas section (Placeholder)</Text>
          </View>
        </View>
      </View>
    </Page>
  </Document>
  );
};

export default MyDocument;

Explanation

  • styles.bigBox: This style defines the main container that holds the three columns.

  • styles.column: This style defines the base style for each column, including padding and borders.

  • styles.column1, styles.column2, styles.column3: These styles define the background colors for each column.

  • styles.text: This style is used for the text inside the first column.

  • styles.image: This style is used for the image inside the second column.

  • styles.canvas: This style defines the placeholder canvas section inside the third column.

Here, each column is given a different background color for visual separation. The first column contains text, the second contains an image, and the third contains a placeholder for a canvas section.

So, for this, we just used the View, Text, and Image components. I hope you now understand that to create any component, we only need a few components to create a PDF in React. Now, let's return to our main design. We will use the same components and add some styling like flex, border styling, font styling, etc.

Let's create the header first. We need to use a View component as the header, apply some styles using flex, and add Image and Text components to it.

// src/MyDocument.js
import React from 'react';
import { Page, Text, View, Document, StyleSheet, Image } from '@react-pdf/renderer';

// Create styles
const styles = StyleSheet.create({
  page: {
    padding: 20,
    backgroundColor: '#ffffff'
  },
  section: {
    marginBottom: 20
  },
  headerContainer: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    marginBottom: 20
  },
  headerText: {
    fontSize: 20,
    fontWeight: 'bold'
  },
  image: {
    width: 50,
    height: 50
  },
  date: {
    fontSize: 12,
    textAlign: 'right'
  },
});
// Create Document Component
const MyDocument = () => {
  return (
        <Document>
      <Page size="A4" style={styles.page}>
        <View style={styles.section}>
          <View style={styles.headerContainer}>
            <Image style={styles.image} src="https://static.vecteezy.com/system/resources/thumbnails/013/993/061/small/mugiwara-the-illustration-vector.jpg" />
            <Text style={styles.headerText}>Anime Report</Text>
            <Text style={styles.date}>{new Date().toLocaleDateString()}</Text>
            </View>
          </View>
      </Page>
    </Document>
  );
};

export default MyDocument;

You see, it's easy to grasp.

Let's code the table. To create tables using React PDF Renderer, we just need to use flex styling and the View and Text components. Each View component will contain one Text component, but you can add more Text components if needed.

The Main Structure

This code will create a table in a PDF document.

<View style={styles.table}>
  {/* Table Header */}
  <View style={styles.tableRow}>
    {/* Each Column Header */}
    <View style={styles.tableColHeader}>
      <Text style={styles.tableCellHeader}>Title</Text>
    </View>
    {/* More column headers... */}
  </View>

  {/* Table Rows */}
  {data.map((item, index) => (
    <View style={styles.tableRow} key={index}>
      {/* Each Column in a Row */}
      <View style={styles.tableCol}>
        <Text style={styles.tableCell}>{item.title}</Text>
      </View>
      {/* More columns... */}
    </View>
  ))}
</View>
  1. Table Container

     <View style={styles.table}>
    

    This View acts as the main container for the entire table. The styles.table style will define how the table is displayed, like borders, padding, etc.

  2. Table Header Row

     <View style={styles.tableRow}>
    

    This View represents a row in the table. The styles.tableRow style will apply to both the header row and each data row.

  3. Column Headers

     <View style={styles.tableColHeader}>
       <Text style={styles.tableCellHeader}>Title</Text>
     </View>
    

    Each View inside the header row is a column header. The styles.tableColHeader style will define how the header cells look, such as their background color, borders, and text alignment. The Text component inside it contains the column's title and uses the styles.tableCellHeader style for text styling.

    Repeat this for each column header (e.g., Title, Studio, Genre, Release Date, Status, Rating, Cost).

  4. Data Rows

     {data.map((item, index) => (
       <View style={styles.tableRow} key={index}>
         {/* Columns for each row */}
       </View>
     ))}
    

    Here, we use the map function to loop over an array called data. For each item in the array, it creates a new row in the table. The key attribute helps React manage the list of items efficiently.

  5. Columns in Data Rows

     <View style={styles.tableCol}>
       <Text style={styles.tableCell}>{item.title}</Text>
     </View>
    

    Each View inside the data row is a column. The styles.tableCol style will define the appearance of the cells in the data rows, and the Text component inside displays the actual data. The styles.tableCell style is applied to the text for consistent styling.

    Repeat this for each column in the data row (e.g., item.title, item.studio, item.genre, item.releaseDate, item.status, item.rating, item.cost).

  6. Table Code

// React PDF Renderer Component
import React from 'react';
import { Page, Text, View, Document, StyleSheet } from '@react-pdf/renderer';

// Create styles
const styles = StyleSheet.create({
// after date styling....
  table: {
    display: "table",
    width: "auto",
    borderStyle: "solid",
    borderWidth: 1,
    borderColor: '#bfbfbf'
  },
  tableRow: {
    flexDirection: "row"
  },
  tableColHeader: {
    width: "15%",
    borderStyle: "solid",
    borderWidth: 1,
    borderColor: '#bfbfbf',
    backgroundColor: '#f0f0f0'
  },
  tableCol: {
    width: "15%",
    borderStyle: "solid",
    borderWidth: 1,
    borderColor: '#bfbfbf'
  },
  tableCellHeader: {
    margin: 5,
    fontSize: 10,
    fontWeight: "bold"
  },
  tableCell: {
    margin: 5,
    fontSize: 10
  },
  footerContainer: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    marginTop: 20
  },
  footerText: {
    fontSize: 12
  },
  totalCost: {
    fontSize: 12,
    fontWeight: 'bold'
  }
});

const data = [
  {
    title: 'Attack on Titan',
    studio: 'Wit Studio',
    genre: 'Action, Dark Fantasy',
    releaseDate: '04-07-2013',
    status: 'Completed',
    rating: '9.0',
    cost: '$120'
  },
// You can add more or fetch data from an API or database
];

// Create Document Component
const MyDocument = () => (
  <Document>
    <Page size="A4">
       /* After header code */
      <View style={styles.table}>
        <View style={styles.tableRow}>
          <View style={styles.tableColHeader}>
            <Text style={styles.tableCellHeader}>Title</Text>
          </View>
          <View style={styles.tableColHeader}>
            <Text style={styles.tableCellHeader}>Studio</Text>
          </View>
          <View style={styles.tableColHeader}>
            <Text style={styles.tableCellHeader}>Genre</Text>
          </View>
          <View style={styles.tableColHeader}>
            <Text style={styles.tableCellHeader}>Release Date</Text>
          </View>
          <View style={styles.tableColHeader}>
            <Text style={styles.tableCellHeader}>Status</Text>
          </View>
          <View style={styles.tableColHeader}>
            <Text style={styles.tableCellHeader}>Rating</Text>
          </View>
          <View style={styles.tableColHeader}>
            <Text style={styles.tableCellHeader}>Cost</Text>
          </View>
        </View>
        {data.map((item, index) => (
          <View style={styles.tableRow} key={index}>
            <View style={styles.tableCol}>
              <Text style={styles.tableCell}>{item.title}</Text>
            </View>
            <View style={styles.tableCol}>
              <Text style={styles.tableCell}>{item.studio}</Text>
            </View>
            <View style={styles.tableCol}>
              <Text style={styles.tableCell}>{item.genre}</Text>
            </View>
            <View style={styles.tableCol}>
              <Text style={styles.tableCell}>{item.releaseDate}</Text>
            </View>
            <View style={styles.tableCol}>
              <Text style={styles.tableCell}>{item.status}</Text>
            </View>
            <View style={styles.tableCol}>
              <Text style={styles.tableCell}>{item.rating}</Text>
            </View>
            <View style={styles.tableCol}>
              <Text style={styles.tableCell}>{item.cost}</Text>
            </View>
          </View>
        ))}
      </View>
    </Page>
  </Document>
);

export default MyDocument;

Here, we've created a simple table with headers and data rows. Each item in the data array becomes a row in the table, and each property of the item becomes a cell in that row. The styling makes sure the table looks neat and professional in the PDF document.

Now, at the end, we can code a footer. The code below creates a footer with an image and a text displaying the total cost.

// style code after table styles...

  footerContainer: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    marginTop: 20
  },
  footerText: {
    fontSize: 12
  },
  totalCost: {
    fontSize: 12,
    fontWeight: 'bold'
  }

//... After table code add footer

<View style={styles.footerContainer}>
  <Image style={styles.image} src="https://static.vecteezy.com/system/resources/thumbnails/013/993/061/small/mugiwara-the-illustration-vector.jpg" />
  <Text style={styles.totalCost}>Total Cost: ${calculateTotalCost()}</Text>
</View>

This View acts as the main container for the footer. The styles.footerContainer style defines how the footer is displayed, including its layout, padding, margin, and alignment. The Image component displays an image, while the Text component shows the total cost.

Conclusion

In this blog, we covered how to use React PDF Renderer to convert React components into high-quality PDFs. We covered the key components, including Document, Page, View, Text, Image, and Link, and explained their uses and styling. We covered, creating a basic PDF document, adding pages, styling, and building complex structures like tables and footers. By following this, you can easily transform your web content into shareable PDFs using React.

Thanks for reading this blog. If you learned something from it, please like and share it with your friends and community. I write blogs and share content on JavaScript, TypeScript, Open Source, and other web development-related topics. Feel free to follow me on my socials. I'll see you in the next one. Thank You :)

Official React PDF Renderer Docs

React PDF Renderer NPM

Complete Code

Did you find this article valuable?

Support Shivam Katare's Blog by becoming a sponsor. Any amount is appreciated!