Saltar al pie de página
HERRAMIENTAS PDF

Cómo convertir HTML a PDF en React (Tutorial para desarrolladores)

Convertir HTML a PDF en React

Convertir HTML a PDF en React se ha convertido en una característica esencial para muchas aplicaciones web. Ya sea que estés construyendo un sistema de facturación, un generador de informes o solo necesites compartir información en un formato universalmente aceptado, la generación de PDF es crucial. En este artículo, exploraremos cómo crear y estilizar archivos PDF en tu aplicación React convirtiendo HTML a PDF utilizando bibliotecas populares.

Librerías populares para la generación de PDF

Antes de sumergirnos en el proceso de convertir HTML a PDF, discutamos algunas bibliotecas populares que puedes usar para generación de PDF en tus aplicaciones React:

  1. React-pdf: Una biblioteca poderosa para crear documentos PDF en aplicaciones React. Soporta varias opciones de estilo y puede crear PDFs complejos y multipágina con facilidad.
  2. jsPDF: Una biblioteca JavaScript ampliamente utilizada para generar archivos PDF al vuelo. Ofrece una amplia gama de características, incluyendo estilo de texto, incrustación de imágenes, y más.
  3. html2canvas: Esta biblioteca te permite capturar una captura de pantalla de un elemento HTML y convertirlo a un objeto Canvas, que luego puede convertirse en un PDF usando otras bibliotecas como jsPDF.

Requisitos previos para convertir HTML a PDF en React

Familiaridad con React y su ecosistema

Antes de sumergirte en la conversión de HTML a PDF, es crucial tener un sólido entendimiento de React. Esto incluye conocimiento de JSX, gestión de estado, ciclos de vida de componentes y hooks.

Comprensión de HTML, CSS y JavaScript

Una sólida base en HTML, CSS y JavaScript es esencial para trabajar con la biblioteca React-pdf. Esto incluye conocimiento de elementos y atributos HTML, estilo y selectores CSS, y fundamentos de JavaScript como variables, funciones y bucles.

Cómo empezar con una aplicación React

Antes de proceder con la conversión de HTML a PDF en React, revisemos rápidamente cómo crear una nueva aplicación React usando la popular herramienta CLI create-react-app. Esto servirá como la base para nuestro ejemplo de generación de PDF.

Paso 1 Instalar Node.js

Asegúrate de tener Node.js instalado en tu máquina. Puedes descargar la última versión de Node.js desde el sitio oficial de Node.js.

Paso 2 Instalar create-react-app

create-react-app es una herramienta CLI ampliamente utilizada para generar aplicaciones React. Instálalo globalmente usando el siguiente comando:

npm install -g create-react-app
npm install -g create-react-app
SHELL

Paso 3 Crear una nueva aplicación React

Ahora que tienes create-react-app instalado, puedes crear una nueva aplicación React con el siguiente comando:

create-react-app my-pdf-app
create-react-app my-pdf-app
SHELL

Este comando generará una nueva aplicación React en una carpeta llamada my-pdf-app. Muévete al directorio recién creado:

cd my-pdf-app
cd my-pdf-app
SHELL

Paso 4 Iniciar el servidor de desarrollo

Para iniciar el servidor de desarrollo y ver tu nueva aplicación React en acción, ejecuta el siguiente comando:

npm start
npm start
SHELL

Paso 5 Implementación de la generación de PDF

Ahora que tienes configurada una aplicación React, puedes seguir los pasos descritos en las secciones anteriores de este artículo para implementar la conversión de HTML a PDF en React usando bibliotecas populares como React-pdf.

Presentación de la biblioteca React-pdf

React-pdf es una biblioteca popular diseñada específicamente para aplicaciones React, ofreciendo una integración perfecta con el ecosistema React. Algunas de sus características clave incluyen soporte para CSS en línea y externo, generación de PDF multipágina, estilos avanzados y compatibilidad con renderizado del lado del servidor (SSR).

Creación de archivos PDF con React-pdf

En esta sección, nos enfocaremos en el uso de React-pdf para crear archivos PDF en una aplicación React. Para comenzar, necesitarás instalar el paquete React-pdf:

npm install --save @react-pdf/renderer
npm install --save @react-pdf/renderer
SHELL

Una vez instalado, puedes crear un nuevo componente React para definir la estructura de tu documento PDF:

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

// Sample invoice data
const invoiceData = {
  sender: {
    name: "John Doe",
    address: "123 Main Street",
    city: "New York",
    state: "NY",
    zip: "10001",
  },
  recipient: {
    name: "Jane Smith",
    address: "456 Elm Street",
    city: "San Francisco",
    state: "CA",
    zip: "94107",
  },
  items: [
    { description: "Item 1", quantity: 2, unitPrice: 10 },
    { description: "Item 2", quantity: 3, unitPrice: 15 },
    { description: "Item 3", quantity: 1, unitPrice: 20 },
  ],
  invoiceNumber: "INV-123456",
  date: "April 26, 2023",
};

// Define styles for PDF document
const styles = StyleSheet.create({
  page: {
    backgroundColor: "#FFF",
    padding: 30,
  },
  header: {
    fontSize: 24,
    textAlign: "center",
    marginBottom: 30,
  },
  sender: {
    marginBottom: 20,
  },
  recipient: {
    marginBottom: 30,
  },
  addressLine: {
    fontSize: 12,
    marginBottom: 2,
  },
  itemsTable: {
    display: "table",
    width: "100%",
    borderStyle: "solid",
    borderWidth: 1,
    borderRightWidth: 0,
    borderBottomWidth: 0,
  },
  tableRow: {
    margin: "auto",
    flexDirection: "row",
  },
  tableColHeader: {
    width: "25%",
    borderStyle: "solid",
    borderWidth: 1,
    borderLeftWidth: 0,
    borderTopWidth: 0,
    backgroundColor: "#F0F0F0",
  },
  tableCol: {
    width: "25%",
    borderStyle: "solid",
    borderWidth: 1,
    borderLeftWidth: 0,
    borderTopWidth: 0,
  },
  tableCell: {
    fontSize: 12,
    textAlign: "center",
    padding: 5,
  },
  total: {
    marginTop: 20,
    textAlign: "right",
  },
  totalLabel: {
    fontSize: 14,
    fontWeight: "bold",
  },
  totalValue: {
    fontSize: 14,
  },
});

const InvoiceDocument = () => {
  // Calculate total amount
  const totalAmount = invoiceData.items.reduce(
    (total, item) => total + item.quantity * item.unitPrice,
    0
  );

  return (
    <Document>
      <Page style={styles.page}>
        <Text style={styles.header}>Invoice</Text>
        <View style={styles.sender}>
          <Text>{invoiceData.sender.name}</Text>
          <Text>{invoiceData.sender.address}</Text>
          <Text>
            {invoiceData.sender.city}, {invoiceData.sender.state} {invoiceData.sender.zip}
          </Text>
        </View>
        <View style={styles.recipient}>
          <Text>{invoiceData.recipient.name}</Text>
          <Text>{invoiceData.recipient.address}</Text>
          <Text>
            {invoiceData.recipient.city}, {invoiceData.recipient.state} {invoiceData.recipient.zip}
          </Text>
        </View>
        <View style={styles.itemsTable}>
          <View style={styles.tableRow}>
            <Text style={[styles.tableColHeader, styles.tableCell]}>Description</Text>
            <Text style={[styles.tableColHeader, styles.tableCell]}>Quantity</Text>
            <Text style={[styles.tableColHeader, styles.tableCell]}>Unit Price</Text>
            <Text style={[styles.tableColHeader, styles.tableCell]}>Amount</Text>
          </View>
          {invoiceData.items.map((item, index) => (
            <View key={index} style={styles.tableRow}>
              <Text style={[styles.tableCol, styles.tableCell]}>{item.description}</Text>
              <Text style={[styles.tableCol, styles.tableCell]}>{item.quantity}</Text>
              <Text style={[styles.tableCol, styles.tableCell]}>{item.unitPrice.toFixed(2)}</Text>
              <Text style={[styles.tableCol, styles.tableCell]}>
                {(item.quantity * item.unitPrice).toFixed(2)}
              </Text>
            </View>
          ))}
        </View>
        <View style={styles.total}>
          <Text style={styles.totalLabel}>Total: ${totalAmount.toFixed(2)}</Text>
        </View>
      </Page>
    </Document>
  );
};

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

// Sample invoice data
const invoiceData = {
  sender: {
    name: "John Doe",
    address: "123 Main Street",
    city: "New York",
    state: "NY",
    zip: "10001",
  },
  recipient: {
    name: "Jane Smith",
    address: "456 Elm Street",
    city: "San Francisco",
    state: "CA",
    zip: "94107",
  },
  items: [
    { description: "Item 1", quantity: 2, unitPrice: 10 },
    { description: "Item 2", quantity: 3, unitPrice: 15 },
    { description: "Item 3", quantity: 1, unitPrice: 20 },
  ],
  invoiceNumber: "INV-123456",
  date: "April 26, 2023",
};

// Define styles for PDF document
const styles = StyleSheet.create({
  page: {
    backgroundColor: "#FFF",
    padding: 30,
  },
  header: {
    fontSize: 24,
    textAlign: "center",
    marginBottom: 30,
  },
  sender: {
    marginBottom: 20,
  },
  recipient: {
    marginBottom: 30,
  },
  addressLine: {
    fontSize: 12,
    marginBottom: 2,
  },
  itemsTable: {
    display: "table",
    width: "100%",
    borderStyle: "solid",
    borderWidth: 1,
    borderRightWidth: 0,
    borderBottomWidth: 0,
  },
  tableRow: {
    margin: "auto",
    flexDirection: "row",
  },
  tableColHeader: {
    width: "25%",
    borderStyle: "solid",
    borderWidth: 1,
    borderLeftWidth: 0,
    borderTopWidth: 0,
    backgroundColor: "#F0F0F0",
  },
  tableCol: {
    width: "25%",
    borderStyle: "solid",
    borderWidth: 1,
    borderLeftWidth: 0,
    borderTopWidth: 0,
  },
  tableCell: {
    fontSize: 12,
    textAlign: "center",
    padding: 5,
  },
  total: {
    marginTop: 20,
    textAlign: "right",
  },
  totalLabel: {
    fontSize: 14,
    fontWeight: "bold",
  },
  totalValue: {
    fontSize: 14,
  },
});

const InvoiceDocument = () => {
  // Calculate total amount
  const totalAmount = invoiceData.items.reduce(
    (total, item) => total + item.quantity * item.unitPrice,
    0
  );

  return (
    <Document>
      <Page style={styles.page}>
        <Text style={styles.header}>Invoice</Text>
        <View style={styles.sender}>
          <Text>{invoiceData.sender.name}</Text>
          <Text>{invoiceData.sender.address}</Text>
          <Text>
            {invoiceData.sender.city}, {invoiceData.sender.state} {invoiceData.sender.zip}
          </Text>
        </View>
        <View style={styles.recipient}>
          <Text>{invoiceData.recipient.name}</Text>
          <Text>{invoiceData.recipient.address}</Text>
          <Text>
            {invoiceData.recipient.city}, {invoiceData.recipient.state} {invoiceData.recipient.zip}
          </Text>
        </View>
        <View style={styles.itemsTable}>
          <View style={styles.tableRow}>
            <Text style={[styles.tableColHeader, styles.tableCell]}>Description</Text>
            <Text style={[styles.tableColHeader, styles.tableCell]}>Quantity</Text>
            <Text style={[styles.tableColHeader, styles.tableCell]}>Unit Price</Text>
            <Text style={[styles.tableColHeader, styles.tableCell]}>Amount</Text>
          </View>
          {invoiceData.items.map((item, index) => (
            <View key={index} style={styles.tableRow}>
              <Text style={[styles.tableCol, styles.tableCell]}>{item.description}</Text>
              <Text style={[styles.tableCol, styles.tableCell]}>{item.quantity}</Text>
              <Text style={[styles.tableCol, styles.tableCell]}>{item.unitPrice.toFixed(2)}</Text>
              <Text style={[styles.tableCol, styles.tableCell]}>
                {(item.quantity * item.unitPrice).toFixed(2)}
              </Text>
            </View>
          ))}
        </View>
        <View style={styles.total}>
          <Text style={styles.totalLabel}>Total: ${totalAmount.toFixed(2)}</Text>
        </View>
      </Page>
    </Document>
  );
};

export default InvoiceDocument;
JAVASCRIPT

Ahora, puedes usar el componente PDFDownloadLink de React-pdf para descargar el archivo PDF generado:

import React from 'react';
import { PDFDownloadLink } from '@react-pdf/renderer';
import InvoiceDocument from './InvoiceDocument';
import './App.css';

const App = () => (
  <div className="app-container">
    <PDFDownloadLink
      document={<InvoiceDocument />}
      fileName="invoice.pdf"
      className="download-button"
    >
      {({ loading }) =>
        loading ? 'Loading document...' : 'Download Invoice'
      }
    </PDFDownloadLink>
  </div>
);

export default App;
import React from 'react';
import { PDFDownloadLink } from '@react-pdf/renderer';
import InvoiceDocument from './InvoiceDocument';
import './App.css';

const App = () => (
  <div className="app-container">
    <PDFDownloadLink
      document={<InvoiceDocument />}
      fileName="invoice.pdf"
      className="download-button"
    >
      {({ loading }) =>
        loading ? 'Loading document...' : 'Download Invoice'
      }
    </PDFDownloadLink>
  </div>
);

export default App;
JAVASCRIPT

Añade estilos CSS en App.css para una UI personalizada:

.app-container {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
  background-color: #d1e8ff;
}

.download-button {
  display: inline-block;
  background-color: #5a8fd5;
  color: #fff;
  font-size: 18px;
  font-weight: bold;
  padding: 12px 24px;
  border-radius: 4px;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.3s ease;
}

.download-button:hover {
  background-color: #3a68b7;
}

Abre localhost:3000 en tu navegador. Cuando hagas clic en el botón de Descarga, el archivo PDF se descargará.

Estilización de archivos PDF

La biblioteca React-pdf soporta una amplia gama de opciones de estilo, similares a CSS. Aquí hay algunas propiedades de estilo comunes que puedes usar para personalizar la apariencia de tus archivos PDF:

  • color: Establece el color del texto.
  • fontSize: Establece el tamaño de fuente del texto.
  • fontFamily: Establece la familia de fuentes del texto.
  • textAlign: Establece la alineación del texto (por ejemplo, 'izquierda', 'derecha', 'centro' o 'justificar').
  • margin: Establece el margen alrededor de un elemento.
  • padding: Establece el relleno dentro de un elemento.
  • border: Establece el borde alrededor de un elemento.
  • backgroundColor: Establece el color de fondo de un elemento.

Librería PDF alternativa para desarrolladores de React

IronPDF para Node.js es una excelente alternativa para convertir HTML a PDF en React. Desarrollada por Iron Software, es una poderosa biblioteca que permite a los desarrolladores generar y manipular documentos PDF directamente desde sus aplicaciones Node.js. Una de sus características destacadas es su capacidad para manejar la ejecución de JavaScript dentro del contenido HTML durante la generación de PDF, permitiendo la creación de PDF dinámicos e interactivos.

Con soporte para varias plataformas, incluyendo Windows, MacOS, Linux, Docker y plataformas en la nube como Azure y AWS, IronPDF garantiza compatibilidad multiplataforma. Su API amigable para el usuario permite a los desarrolladores integrar rápidamente la generación y manipulación de PDFs en sus proyectos Node.js.

React es una biblioteca JavaScript para construir interfaces de usuario, y dado que IronPDF está construido para Node.js, puedes integrar IronPDF en tus aplicaciones React utilizando su API de Node.js.

Aquí hay un esquema de cómo puedes usar IronPDF con React:

  1. Instalar IronPDF: Puedes instalar IronPDF en tu proyecto React usando npm o yarn.
npm install @ironsoftware/ironpdf
npm install @ironsoftware/ironpdf
SHELL
  1. Integrar con Componentes de React: Puedes crear componentes React que utilicen IronPDF para generar y manipular PDFs. Por ejemplo, puedes tener un componente que toma contenido HTML como entrada y lo convierte en un PDF usando la API de IronPDF.
import React from 'react';
import { PdfDocument } from '@ironsoftware/ironpdf';

const HTMLToPDFComponent = () => {
    const convertHTMLToPDF = async (htmlContent) => {
        try {
            const pdf = await PdfDocument.fromHtml(htmlContent);
            await pdf.saveAs('generated_pdf.pdf');
            alert('PDF generated successfully!');
        } catch (error) {
            console.error('Error generating PDF:', error);
        }
    };

    return (
        <div>
            {/* Input HTML content */}
            <textarea onChange={(e) => convertHTMLToPDF(e.target.value)} />
        </div>
    );
};

export default HTMLToPDFComponent;
import React from 'react';
import { PdfDocument } from '@ironsoftware/ironpdf';

const HTMLToPDFComponent = () => {
    const convertHTMLToPDF = async (htmlContent) => {
        try {
            const pdf = await PdfDocument.fromHtml(htmlContent);
            await pdf.saveAs('generated_pdf.pdf');
            alert('PDF generated successfully!');
        } catch (error) {
            console.error('Error generating PDF:', error);
        }
    };

    return (
        <div>
            {/* Input HTML content */}
            <textarea onChange={(e) => convertHTMLToPDF(e.target.value)} />
        </div>
    );
};

export default HTMLToPDFComponent;
JAVASCRIPT
  1. Manejar la Generación de PDF: Utiliza la funcionalidad de IronPDF dentro de tus componentes React para manejar la generación, manipulación y guardar PDFs. Puedes usar los métodos de IronPDF para convertir cadenas HTML, URLs o imágenes a PDFs.
  2. Renderizar PDFs: Una vez que hayas generado PDFs usando IronPDF, puedes renderizarlos dentro de tu aplicación React usando componentes o bibliotecas apropiadas para mostrar documentos PDF.
import React from 'react';

const PDFViewerComponent = () => {
    return (
        <div>
            {/* Render PDF using appropriate component or library */}
            <iframe src="generated_pdf.pdf" width="100%" height="600px" title="PDF Viewer" />
        </div>
    );
};

export default PDFViewerComponent;
import React from 'react';

const PDFViewerComponent = () => {
    return (
        <div>
            {/* Render PDF using appropriate component or library */}
            <iframe src="generated_pdf.pdf" width="100%" height="600px" title="PDF Viewer" />
        </div>
    );
};

export default PDFViewerComponent;
JAVASCRIPT

Con IronPDF, los desarrolladores pueden generar eficientemente documentos PDF de nivel profesional desde diversas fuentes, personalizarlos para satisfacer sus requerimientos específicos, e integrar de manera fluida capacidades de generación de PDF en sus aplicaciones .NET. IronPDF también soporta características avanzadas como CSS, JavaScript y fuentes personalizadas, asegurando que los archivos PDF generados coincidan con el diseño y requerimientos de tu aplicación.

Conclusión

En este artículo, hemos cubierto el proceso de convertir HTML a PDF en React usando la biblioteca React-pdf. Discutimos bibliotecas populares para generación de PDF, cómo crear y estilizar archivos PDF usando React-pdf, y opciones adicionales para generar documentos PDF más complejos.

Siguiendo esta guía, ahora deberías tener un sólido entendimiento de cómo generar archivos PDF en tus aplicaciones React, permitiéndote generar PDFs de alta calidad y satisfacer las necesidades de varios casos de uso.

IronPDF ofrece una versión de prueba gratuita, la cual te permite probar la biblioteca y determinar si cumple con tus necesidades antes de comprometerte a una compra. Después del período de prueba, las licencias de compra de IronPDF comienzan desde $799, que incluye soporte prioritario y actualizaciones. Además, IronPDF está disponible para otros lenguajes como C# .NET, Java, y Python. Descarga la biblioteca IronPDF empezando con IronPDF para Node.js y pruébala.

Darrius Serrant
Ingeniero de Software Full Stack (WebOps)

Darrius Serrant tiene una licenciatura en Ciencias de la Computación de la Universidad de Miami y trabaja como Ingeniero de Marketing WebOps Full Stack en Iron Software. Atraído por la programación desde joven, vio la computación como algo misterioso y accesible, convirtiéndolo en el ...

Leer más