En esta página:
Github
En ocasiones necesitamos exportar un contenido de nuestra página HTML a PDF con la librería React.
Para hacer esto debes seguir ciertos pasos importantes.
En este tutorial te enseñaré a Cómo Convertir HTML a PDF en React, vamos con ello.
Convirtiendo HTML a PDF con React
Sigue los pasos que te indico a continuación para que todo salga bien:
Creación de nuevo proyecto
Crearé un nuevo proyecto de React con la herramienta Vite, ejecutando el siguiente comando (He colocado comentarios para explicar paso a paso el proceso de creación del proyecto):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# Comando para crear el proyecto npm create vite@latest > npx > create-vite # Le damos un nombre al proyecto ? Project name: » vite-project miapp √ Project name: ... miapp # Seleccionamos React ? Select a framework: » - Use arrow-keys. Return to submit. Vanilla Vue > React Preact Lit Svelte Solid Qwik Others √ Select a framework: » React # Elijo TypeScript + SWC ? Select a variant: » - Use arrow-keys. Return to submit. TypeScript > TypeScript + SWC JavaScript JavaScript + SWC Remix ↗ √ Select a variant: » TypeScript + SWC |
Puedes ver que al final elegí la variante TypeScript + SWC.
Esta variante es muy potente, en este artículo te explico porque lo és.
Ingresamos al directorio del proyecto e instalamos las dependencias necesarias:
1 2 3 4 5 6 7 8 9 10 |
# Ingresamos al directorio del proyecto cd miapp # Instalamos las dependencias npm install # Verificar que el proyecto se creo correctamente (Iniciar servidor de Vite) npm run dev |
Puedes ver que sobre el final he colocado el comando npm run dev.
Puedes ejecutarlo, para verificar que todo este bien.
Convertir HTML a PDF con React
Instalamos la librería React-pdf, ejecutando el siguiente comando:
1 2 3 4 5 6 7 8 9 10 |
npm install @react-pdf/renderer --save added 61 packages, and audited 206 packages in 5s 40 packages are looking for funding run `npm fund` for details found 0 vulnerabilities |
Al comando anterior le he pasado la opción –save para registrar la dependencia en el archivo package.json del proyecto.
De esta manera tenemos un control de lo que instalamos en nuestro proyecto.
Importamos React
Abrimos el archivo App.tsx y comenzamos importando React:
1 2 3 4 5 6 |
// Importamos React y lo hacemos global import React from 'react' import { render } from 'react-dom' window.React = React |
Imagen y Fuente para el PDF
Importamos una imagen y un tipo de letra para el contenido del PDF:
1 2 3 4 5 |
// Importamos una imagen local y una fuente import miimagen from './assets/images/como-usar-axios-y-angular.jpg' import mifuente from './assets/fonts/SUSE-VariableFont_wght.ttf' |
Instanciamos React-pdf
Importamos la librería React-pdf algunos elementos necesarios:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// Importamos 'React-pdf' con sus elementos necesarios import { Document, Page, Text, Image, Font, StyleSheet, PDFViewer, PDFDownloadLink, View, } from "@react-pdf/renderer"; |
Configuración de la fuente para el PDF
Definimos la fuente que usaremos el texto del PDF:
1 2 3 4 5 6 7 |
// Personalizamos la fuente del PDF Font.register({ family: 'SUSE', src: mifuente }); |
Estilos para el PDF
Le damos algunos estilos CSS a nuestro PDF:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
// Estilos CSS para nuestro PDF const estilos = StyleSheet.create({ page: { backgroundColor: "#d11fb6", color: "white", }, section: { margin: 10, padding: 10, }, viewer: { width: 800, height: 400, marginBottom: 30, }, body: { paddingTop: 35, paddingBottom: 65, paddingHorizontal: 35, }, title: { fontSize: 24, textAlign: 'center', fontFamily: 'SUSE' }, author: { fontSize: 12, textAlign: 'center', marginBottom: 40, }, subtitle: { fontSize: 18, margin: 12, fontFamily: 'SUSE' }, text: { margin: 12, fontSize: 14, textAlign: 'justify', fontFamily: 'Times-Roman' }, image: { marginVertical: 15, marginHorizontal: 100, }, header: { fontSize: 12, marginBottom: 20, textAlign: 'center', color: 'grey', }, pageNumber: { position: 'absolute', fontSize: 12, bottom: 30, left: 0, right: 0, textAlign: 'center', color: 'grey', }, }); |
Contenido del PDF
Agregamos los elementos que tendrá el contenido del PDF:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
// Función para el contenido del PDF en el Visor function DocumentoPDF() { return ( <PDFViewer style={estilos.viewer}> {/* Iniciamos el documento */} <Document> {/* Renderizamos las páginas del PDF */} <Page style={estilos.body} size="A4"> <View> {/* Página 1 */} <Text style={estilos.title}>Mi Bonito PDF</Text> <Text style={estilos.author}>Por Nube Colectiva</Text> <Image style={estilos.image} src={miimagen} /> <Text style={estilos.subtitle}> Introducción </Text> <Text style={estilos.text}> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus varius varius convallis. Cras vel nibh rhoncus eros consequat varius. Phasellus imperdiet dapibus purus a condimentum. Curabitur vehicula, massa vitae pulvinar laoreet, enim enim facilisis augue, eget fringilla ipsum urna sit amet risus. Maecenas consequat nulla sit amet quam bibendum, sit amet elementum odio hendrerit. Nunc eget congue risus, ut posuere mi. Nullam vehicula tellus elit, at varius dui ultricies eu. Nullam scelerisque in sem a egestas. Aenean convallis mauris eu lacus rutrum lobortis. Vestibulum vulputate efficitur augue, in rhoncus risus bibendum eu. Suspendisse vel mollis urna, placerat tempus magna. Integer ex tellus, vulputate non dictum ac, posuere vel justo. </Text> <Text style={estilos.text}> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus varius varius convallis. Cras vel nibh rhoncus eros consequat varius. Phasellus imperdiet dapibus purus a condimentum. Curabitur vehicula, massa vitae pulvinar laoreet, enim enim facilisis augue, eget fringilla ipsum urna sit amet risus. Maecenas consequat nulla sit amet quam bibendum, sit amet elementum odio hendrerit. Nunc eget congue risus, ut posuere mi. Nullam vehicula tellus elit, at varius dui ultricies eu. Nullam scelerisque in sem a egestas. Aenean convallis mauris eu lacus rutrum lobortis. Vestibulum vulputate efficitur augue, in rhoncus risus bibendum eu. Suspendisse vel mollis urna, placerat tempus magna. Integer ex tellus, vulputate non dictum ac, posuere vel justo. </Text> {/* Página 2 */} {/* Con 'break' colocamos el contenido en la siguiente página del PDF */} <Text style={estilos.subtitle} break> Contenido </Text> <Text style={estilos.text}> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus varius varius convallis. Cras vel nibh rhoncus eros consequat varius. Phasellus imperdiet dapibus purus a condimentum. Curabitur vehicula, massa vitae pulvinar laoreet, enim enim facilisis augue, eget fringilla ipsum urna sit amet risus. Maecenas consequat nulla sit amet quam bibendum, sit amet elementum odio hendrerit. Nunc eget congue risus, ut posuere mi. Nullam vehicula tellus elit, at varius dui ultricies eu. Nullam scelerisque in sem a egestas. Aenean convallis mauris eu lacus rutrum lobortis. Vestibulum vulputate efficitur augue, in rhoncus risus bibendum eu. Suspendisse vel mollis urna, placerat tempus magna. Integer ex tellus, vulputate non dictum ac, posuere vel justo. </Text> <Image style={estilos.image} src={miimagen} /> <Text style={estilos.text}> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus varius varius convallis. Cras vel nibh rhoncus eros consequat varius. Phasellus imperdiet dapibus purus a condimentum. Curabitur vehicula, massa vitae pulvinar laoreet, enim enim facilisis augue, eget fringilla ipsum urna sit amet risus. Maecenas consequat nulla sit amet quam bibendum, sit amet elementum odio hendrerit. Nunc eget congue risus, ut posuere mi. Nullam vehicula tellus elit, at varius dui ultricies eu. Nullam scelerisque in sem a egestas. Aenean convallis mauris eu lacus rutrum lobortis. Vestibulum vulputate efficitur augue, in rhoncus risus bibendum eu. Suspendisse vel mollis urna, placerat tempus magna. Integer ex tellus, vulputate non dictum ac, posuere vel justo. </Text> {/* Página 3 (Final) */} {/* Con 'break' colocamos el contenido en la siguiente página del PDF */} <Text style={estilos.subtitle} break> Final </Text> <Text style={estilos.text}> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus varius varius convallis. Cras vel nibh rhoncus eros consequat varius. Phasellus imperdiet dapibus purus a condimentum. Curabitur vehicula, massa vitae pulvinar laoreet, enim enim facilisis augue, eget fringilla ipsum urna sit amet risus. Maecenas consequat nulla sit amet quam bibendum, sit amet elementum odio hendrerit. Nunc eget congue risus, ut posuere mi. Nullam vehicula tellus elit, at varius dui ultricies eu. Nullam scelerisque in sem a egestas. Aenean convallis mauris eu lacus rutrum lobortis. Vestibulum vulputate efficitur augue, in rhoncus risus bibendum eu. Suspendisse vel mollis urna, placerat tempus magna. Integer ex tellus, vulputate non dictum ac, posuere vel justo. </Text> <Image style={estilos.image} src={miimagen} /> <Text style={estilos.text}> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus varius varius convallis. Cras vel nibh rhoncus eros consequat varius. Phasellus imperdiet dapibus purus a condimentum. Curabitur vehicula, massa vitae pulvinar laoreet, enim enim facilisis augue, eget fringilla ipsum urna sit amet risus. Maecenas consequat nulla sit amet quam bibendum, sit amet elementum odio hendrerit. Nunc eget congue risus, ut posuere mi. Nullam vehicula tellus elit, at varius dui ultricies eu. Nullam scelerisque in sem a egestas. Aenean convallis mauris eu lacus rutrum lobortis. Vestibulum vulputate efficitur augue, in rhoncus risus bibendum eu. Suspendisse vel mollis urna, placerat tempus magna. Integer ex tellus, vulputate non dictum ac, posuere vel justo. </Text> <Text style={estilos.pageNumber} render={({ pageNumber, totalPages }) => ( `${pageNumber} / ${totalPages}` )} fixed /> </View> </Page> {/* End of the document*/} </Document> </PDFViewer> ); } |
Renderizamos el PDF
Mostramos el PDF en la vista:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
function App() { const [count, setCount] = useState(0) return ( <> <div> <a href="https://vitejs.dev" target="_blank"> <img src={viteLogo} className="logo" alt="Vite logo" /> </a> <a href="https://react.dev" target="_blank"> <img src={reactLogo} className="logo react" alt="React logo" /> </a> </div> <h1>Vite + React</h1> <div className="card"> <button onClick={() => setCount((count) => count + 1)}> count is {count} </button> <p> Edit <code>src/App.jsx</code> and save to test HMR </p> </div> <p className="read-the-docs"> Click on the Vite and React logos to learn more </p> <DocumentoPDF /> </> ) } |
Eso es todo, ya tenemos nuestro PDF listo creado con React.
Probando el PDF
Iniciamos el servidor de Vite con el siguiente comando:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
npm run dev > miapp@0.0.0 dev > vite VITE v5.4.3 ready in 289 ms ➜ Local: http://localhost:5173/ ➜ Network: use --host to expose ➜ press h + enter to show help |
Si abrimos la ruta local http://localhost:5173/ en el navegador.
Podemos ver que nuestro PDF carga sin problemas:
Botón Para Descargar el PDF
Creamos una función para descargar el PDF con su contenido:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
// Función para Descargar el PDF function DescargarPDF() { return ( <Document> {/* Renderizamos las páginas del PDF */} <Page style={estilos.body} size="A4"> <View> {/* Página 1 */} <Text style={estilos.title}>Mi Bonito PDF</Text> <Text style={estilos.author}>Por Nube Colectiva</Text> <Image style={estilos.image} src={miimagen} /> <Text style={estilos.subtitle}> Introducción </Text> <Text style={estilos.text}> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus varius varius convallis. Cras vel nibh rhoncus eros consequat varius. Phasellus imperdiet dapibus purus a condimentum. Curabitur vehicula, massa vitae pulvinar laoreet, enim enim facilisis augue, eget fringilla ipsum urna sit amet risus. Maecenas consequat nulla sit amet quam bibendum, sit amet elementum odio hendrerit. Nunc eget congue risus, ut posuere mi. Nullam vehicula tellus elit, at varius dui ultricies eu. Nullam scelerisque in sem a egestas. Aenean convallis mauris eu lacus rutrum lobortis. Vestibulum vulputate efficitur augue, in rhoncus risus bibendum eu. Suspendisse vel mollis urna, placerat tempus magna. Integer ex tellus, vulputate non dictum ac, posuere vel justo. </Text> <Text style={estilos.text}> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus varius varius convallis. Cras vel nibh rhoncus eros consequat varius. Phasellus imperdiet dapibus purus a condimentum. Curabitur vehicula, massa vitae pulvinar laoreet, enim enim facilisis augue, eget fringilla ipsum urna sit amet risus. Maecenas consequat nulla sit amet quam bibendum, sit amet elementum odio hendrerit. Nunc eget congue risus, ut posuere mi. Nullam vehicula tellus elit, at varius dui ultricies eu. Nullam scelerisque in sem a egestas. Aenean convallis mauris eu lacus rutrum lobortis. Vestibulum vulputate efficitur augue, in rhoncus risus bibendum eu. Suspendisse vel mollis urna, placerat tempus magna. Integer ex tellus, vulputate non dictum ac, posuere vel justo. </Text> {/* Página 2 */} {/* Con 'break' colocamos el contenido en la siguiente página del PDF */} <Text style={estilos.subtitle} break> Contenido </Text> <Text style={estilos.text}> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus varius varius convallis. Cras vel nibh rhoncus eros consequat varius. Phasellus imperdiet dapibus purus a condimentum. Curabitur vehicula, massa vitae pulvinar laoreet, enim enim facilisis augue, eget fringilla ipsum urna sit amet risus. Maecenas consequat nulla sit amet quam bibendum, sit amet elementum odio hendrerit. Nunc eget congue risus, ut posuere mi. Nullam vehicula tellus elit, at varius dui ultricies eu. Nullam scelerisque in sem a egestas. Aenean convallis mauris eu lacus rutrum lobortis. Vestibulum vulputate efficitur augue, in rhoncus risus bibendum eu. Suspendisse vel mollis urna, placerat tempus magna. Integer ex tellus, vulputate non dictum ac, posuere vel justo. </Text> <Image style={estilos.image} src={miimagen} /> <Text style={estilos.text}> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus varius varius convallis. Cras vel nibh rhoncus eros consequat varius. Phasellus imperdiet dapibus purus a condimentum. Curabitur vehicula, massa vitae pulvinar laoreet, enim enim facilisis augue, eget fringilla ipsum urna sit amet risus. Maecenas consequat nulla sit amet quam bibendum, sit amet elementum odio hendrerit. Nunc eget congue risus, ut posuere mi. Nullam vehicula tellus elit, at varius dui ultricies eu. Nullam scelerisque in sem a egestas. Aenean convallis mauris eu lacus rutrum lobortis. Vestibulum vulputate efficitur augue, in rhoncus risus bibendum eu. Suspendisse vel mollis urna, placerat tempus magna. Integer ex tellus, vulputate non dictum ac, posuere vel justo. </Text> {/* Página 3 (Final) */} {/* Con 'break' colocamos el contenido en la siguiente página del PDF */} <Text style={estilos.subtitle} break> Final </Text> <Text style={estilos.text}> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus varius varius convallis. Cras vel nibh rhoncus eros consequat varius. Phasellus imperdiet dapibus purus a condimentum. Curabitur vehicula, massa vitae pulvinar laoreet, enim enim facilisis augue, eget fringilla ipsum urna sit amet risus. Maecenas consequat nulla sit amet quam bibendum, sit amet elementum odio hendrerit. Nunc eget congue risus, ut posuere mi. Nullam vehicula tellus elit, at varius dui ultricies eu. Nullam scelerisque in sem a egestas. Aenean convallis mauris eu lacus rutrum lobortis. Vestibulum vulputate efficitur augue, in rhoncus risus bibendum eu. Suspendisse vel mollis urna, placerat tempus magna. Integer ex tellus, vulputate non dictum ac, posuere vel justo. </Text> <Image style={estilos.image} src={miimagen} /> <Text style={estilos.text}> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus varius varius convallis. Cras vel nibh rhoncus eros consequat varius. Phasellus imperdiet dapibus purus a condimentum. Curabitur vehicula, massa vitae pulvinar laoreet, enim enim facilisis augue, eget fringilla ipsum urna sit amet risus. Maecenas consequat nulla sit amet quam bibendum, sit amet elementum odio hendrerit. Nunc eget congue risus, ut posuere mi. Nullam vehicula tellus elit, at varius dui ultricies eu. Nullam scelerisque in sem a egestas. Aenean convallis mauris eu lacus rutrum lobortis. Vestibulum vulputate efficitur augue, in rhoncus risus bibendum eu. Suspendisse vel mollis urna, placerat tempus magna. Integer ex tellus, vulputate non dictum ac, posuere vel justo. </Text> <Text style={estilos.pageNumber} render={({ pageNumber, totalPages }) => ( `${pageNumber} / ${totalPages}` )} fixed /> </View> </Page> {/* End of the document*/} </Document> ) } |
Luego agregamos el botón para descargar el PDF debajo del visor del PDF:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
function App() { const [count, setCount] = useState(0) return ( <> <div> <a href="https://vitejs.dev" target="_blank"> <img src={viteLogo} className="logo" alt="Vite logo" /> </a> <a href="https://react.dev" target="_blank"> <img src={reactLogo} className="logo react" alt="React logo" /> </a> </div> <h1>Vite + React</h1> <div className="card"> <button onClick={() => setCount((count) => count + 1)}> count is {count} </button> <p> Edit <code>src/App.jsx</code> and save to test HMR </p> </div> <p className="read-the-docs"> Click on the Vite and React logos to learn more </p> <DocumentoPDF /> <div> <PDFDownloadLink document={<DescargarPDF />} fileName="archivo.pdf"> {({ loading}) => loading ? 'Cargando documento...' : 'Descargar PDF' } </PDFDownloadLink> </div> </> ) } |
Si abrimos nuevamente la ruta local http://localhost:5173/ en el navegador.
Podemos ver que debajo del PDF hemos creado un botón para descargarlo:
Así de fácil puedes convertir HTML a PDF con React.
Conclusión
En este tutorial has aprendido a Cómo Convertir HTML a PDF en React.
Te servirá de ayuda para crear archivos PDF en tus proyectos con React.
Practica mucho, así serás un experto en React.
Nota(s)
- No olvides que debemos usar la Tecnología para hacer cosas Buenas por el Mundo.
Síguenos en las Redes Sociales para que no te pierdas nuestros próximos contenidos.