How to Generate PDF from html in React Native
Tags: reactnative, pdf, html, mobile
Published: 2022-09-07 08:58:49

## Introduction

Generating PDF based on different transaction is an important part of any retail applications. today we are going to show how can we generate PDF documents in React Native.

React Native has several good NPM libraries to generate PDF but articles and blogs are very few. So, I am letting you know how can you generate PDF in React Native using the very popular React Native PDF generation library called `react-native-html-to-pdf`.

## Create a React Native Project

```bash
npx react-native init MyRNPDF --template react-native-template-typescript
```

this command will create a new react native project

## Folder Structure of a Newly created React Native Project

![Folder Structure of a React Native Project](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/di8kt30akfyhd5pxeume.png)

## Change App.tsx file to print `Hello World!`
```tsx
// App.tsx
import React from 'react';
import {StyleSheet, Text, View} from 'react-native';

function App() {
  return (
    <View style={styles.container}>
      <Text style={styles.text}>Hello World</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#aac',
    alignItems: 'center',
    justifyContent: 'center',
  },
  text: {
    fontSize: 30,
    color: '#fff',
  },
});

export default App;
```

## Build the Project and Run on an Emulator

```bash
npm run android
```

after successful build of the project you will see a `Hello World!` message on your emulator/device screen:

![Output of Emulator Screen](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/df3kc9u20bgosmym8ik7.png)
 

## Add Dependency Library for PDF generation

```bash
npm i react-native-html-to-pdf
```

we are using TypeScript in our project. So, we have to install below package too for type definition of `react-native-html-to-pdf` library.

```bash
npm i @types/react-native-html-to-pdf
```

## iOS only recommendation

React Native version >= 0.60.0, they have introduced [autolinking](https://reactnative.dev/docs/linking-libraries-ios) so we do not required to link the library but need to install pods. but only for iOS we need install dependencies via `pod`'s:

```bash
cd ios && pod install && cd ..
```

## Edit the File Path

Go directly to the source code in your 

- `node modules`
  - `react-native-html-to-pdf`
    - `android` 
      - src 
        - main
          - java
            - com
              - christopherdro
                - htmltopdf
                  - RNHTMLtoPDFModule.java 

In the `convert()` function change this code block:

```java
File path = (Environment.MEDIA_MOUNTED.equals(state)) ?
          new File(mReactContext.getExternalFilesDir(null), options.getString(DIRECTORY)) :
          new File(mReactContext.getFilesDir(), options.getString(DIRECTORY));
```


![existing code block](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v2lmibqhh7a2l2z2ex2h.png)


with below code block:
```java
File path = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), options.getString(DIRECTORY));
```


![replaced code blocks](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q89x51lg3mg4186kz3vv.png)


And that should change the file path to the appropriate location inside your emulator/device.

## Permission for Android

We are accessing external storage so we need to add two permission in `AndroidManifest.xml` file.

We are going to add the following permissions in the `AndroidManifest.xml`

- default `AndroidManifest.xml` file:

![default AndroidManifest.xml file](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/02ws5b963nuoj9i75dfr.png)

- Permission Code Block:
```xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
```


![Changed AndroidManifest.xml file](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i9l2qmowkpukcqg2wsrh.png)


## Setting PDF generation
Update `App.tsx` file as per your need with settings of `react-native-html-to-pdf` library:

```tsx
import React, {useState} from 'react';
import {Alert, Pressable, StyleSheet, Text, View} from 'react-native';
import RNHTMLtoPDF from 'react-native-html-to-pdf';

function App() {
  const [isLoading, setIsLoading] = useState(false);
  const [count, setCount] = useState(1);

  const orderLines = [
    {
      id: 1,
      product: 'Product 1',
      quantity: 1,
      price: '$10.00',
    },
    {
      id: 2,
      product: 'Product 2',
      quantity: 2,
      price: '$20.00',
    },
    {
      id: 3,
      product: 'Product 3',
      quantity: 3,
      price: '$30.00',
    },
  ];

  const generatePDF = async () => {
    setIsLoading(true);
    try {
      const html = `
        <html>
          <head>
            <style>
              body {
                font-family: 'Helvetica';
                font-size: 12px;
              }
              header, footer {
                height: 50px;
                background-color: #fff;
                color: #000;
                display: flex;
                justify-content: center;
                padding: 0 20px;
              }
              table {
                width: 100%;
                border-collapse: collapse;
              }
              th, td {
                border: 1px solid #000;
                padding: 5px;
              }
              th {
                background-color: #ccc;
              }
            </style>
          </head>
          <body>
            <header>
              <h1>Invoice for Order #${count}</h1>
            </header>
            <h1>Order Details</h1>
            <table>
              <tr>
                <th>Order ID</th>
                <td>${count}</td> 
              </tr>
              <tr>
                <th>Order Date</th>
                <td>29-Jul-2022</td>
              </tr>
              <tr>
                <th>Order Status</th>
                <td>Completed</td>
              </tr>
              <tr>
                <th>Order Total</th>
                <td>$13232</td>
              </tr>
            </table>
            <h1>Order Lines</h1>
            <table>
              <tr>
                <th>Product ID</th>
                <th>Product Name</th>
                <th>Product Qty</th>
                <th>Product Price</th>
              </tr>
              ${orderLines
                .map(
                  line => `
                <tr>
                  <td>${line.id}</td>
                  <td>${line.product}</td>
                  <td>${line.quantity}</td>
                  <td>${line.price}</td>
                </tr>
              `,
                )
                .join('')}
            </table>
            <footer>
              <p>Thank you for your business!</p>
            </footer>
          </body>
        </html>
      `;
      const options = {
        html,
        fileName: `invoice_${count}`,
        directory: 'Invoices',
      };
      const file = await RNHTMLtoPDF.convert(options);
      Alert.alert('Success', `PDF saved to ${file.filePath}`);
      setCount(count + 1);
      setIsLoading(false);
    } catch (error: any) {
      Alert.alert('Error', error.message);
    }
  };

  if (isLoading) {
    return <Text>Generating PDF...</Text>;
  }

  return (
    <View style={styles.container}>
      <Pressable style={styles.button} onPress={() => generatePDF()}>
        <Text style={styles.text}>Generate PDF</Text>
      </Pressable>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#aac',
    alignItems: 'center',
    justifyContent: 'center',
  },
  text: {
    fontSize: 24,
    color: '#fff',
  },
  button: {
    backgroundColor: '#6c8ee3',
    padding: 15,
    borderRadius: 10,
    margin: 20,
  },
});

export default App;
```

### build your project again:

```bash
npm run android
```

#### Output

- First look of our App:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a0f41g407wnyten3ep1u.png)

- Click the Button to generate PDF file and you'll see an Alert:

![PDF Success Message](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2u03yh0dpe8x4o5cmn1v.png)


Visit the location which is showing in Success Alert and see generated PDF file.

- On Emulator:


![Generated PDF File Location](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ky3vlckyyp5wsa15c6c5.png)


On your real device you can see the file on your external device folder:

1. Generate PDF on Real Device:

![PDF Generation on Real Device](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x92h70eddtcsb9s500sn.gif)

2. Locate the generated PDF file:


![Locate PDF File from external storage](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/79e1fzzhusc4kwevc6lu.gif)
 

## Resources
- [How to generate PDF from html in React Native](https://www.youtube.com/watch?v=YrGWWPEYxpg)
- [Example to Make PDF in React Native from HTML Text](https://aboutreact.com/make-pdf-in-react-native-from-html-text/)
- [Stack Overflow QA: How to print/save pdf in react native?](https://stackoverflow.com/questions/70821290/how-to-print-save-pdf-in-react-native)
- [Stack Overflow QA: pdf created by react native html to pdf is not showing in provided path](https://stackoverflow.com/questions/67806154/pdf-created-by-react-native-html-to-pdf-is-not-showing-in-provided-path)
- [The PDF file is NOT Created - Wrong filePath](https://lightrun.com/answers/christopherdro-react-native-html-to-pdf-the-pdf-file-is-not-created---wrong-filepath)
- [Stack Overflow QA: Pdf file not created using react-native-html-to-pdf](https://stackoverflow.com/questions/71943905/pdf-file-not-created-using-react-native-html-to-pdf)
- [React Native HTML to PDF](https://github.com/christopherdro/react-native-html-to-pdf)

## Credit
- Cover Photo by <a href="https://unsplash.com/@2hmedia?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">2H Media</a> on <a href="https://unsplash.com/s/photos/document?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>