HTML zu PDF in React konvertieren mit jsPDF und html2canvas: Schritt-für-Schritt-Anleitung
In vielen Webanwendungen – sei es für Rechnungen, Berichte, Tickets oder Zertifikate – ist der Export von Webinhalten als PDF eine essenzielle Funktion.
Der beliebteste und flexibelste Ansatz in React ist die Kombination von html2canvas und jsPDF:
- html2canvas nimmt den ausgewählten HTML-Bereich und wandelt ihn in ein hochauflösendes Bild (Canvas) um.
- jsPDF nimmt dieses Bild und bettet es in ein neu erstelltes PDF-Dokument ein, das anschließend heruntergeladen werden kann.
In diesem Tutorial lernst du, wie du diese Funktionalität Schritt für Schritt in deine React-Anwendung integrierst.
1. Installation der Abhängigkeiten
Öffne dein Terminal im Root-Verzeichnis deines React-Projekts und installiere die beiden benötigten Pakete:
npm install jspdf html2canvas
Alternativ mit Yarn:
yarn add jspdf html2canvas
2. Der React-Code
Erstelle eine neue Komponente, z. B. PdfExportComponent.jsx.
Wir nutzen useRef, um das DOM-Element zu markieren, welches in das PDF konvertiert werden soll.
import React, { useRef } from 'react';
import jsPDF from 'jspdf';
import html2canvas from 'html2canvas';
const PdfExportComponent = () => {
// Referenz auf das HTML-Element, das exportiert werden soll
const pdfRef = useRef(null);
const handleDownloadPdf = async () => {
const element = pdfRef.current;
if (!element) {
return;
}
try {
// 1. HTML in ein Canvas (Bild) umwandeln
// 'scale: 2' sorgt für eine schärfere Textdarstellung im PDF
const canvas = await html2canvas(element, {
scale: 2,
useCORS: true // Wichtig, falls externe Bilder geladen werden
});
// 2. Bilddaten im PNG-Format extrahieren
const imgData = canvas.toDataURL('image/png');
// 3. Neues jsPDF-Dokument instanziieren (Format: DIN A4, Einheit: mm)
const pdf = new jsPDF('portrait', 'mm', 'a4');
// Dimensionen berechnen, um das Bild proportional anzupassen
const pdfWidth = pdf.internal.pageSize.getWidth();
const pdfHeight = (canvas.height * pdfWidth) / canvas.width;
// 4. Bild zum PDF hinzufügen (x=0, y=0)
pdf.addImage(imgData, 'PNG', 0, 0, pdfWidth, pdfHeight);
// 5. PDF herunterladen
pdf.save('mein-dokument.pdf');
} catch (error) {
console.error('Fehler beim Erstellen der PDF:', error);
}
};
return (
<div style={{ padding: '20px', fontFamily: 'sans-serif' }}>
{/* Dieser Bereich wird exportiert */}
<div
ref={pdfRef}
style={{
padding: '24px',
backgroundColor: '#ffffff',
border: '1px solid #e0e0e0',
borderRadius: '8px',
maxWidth: '600px',
margin: '0 auto'
}}
>
<h1 style={{ color: '#333' }}>Rechnung / Bericht</h1>
<p>Dies ist ein Beispielinhalt, der dynamisch in React gerendert wird.</p>
<table style={{ width: '100%', marginTop: '20px', borderCollapse: 'collapse' }}>
<thead>
<tr style={{ borderBottom: '2px solid #ccc', textAlign: 'left' }}>
<th>Position</th>
<th>Menge</th>
<th>Preis</th>
</tr>
</thead>
<tbody>
<tr style={{ borderBottom: '1px solid #eee' }}>
<td>Webentwicklung Service</td>
<td>1</td>
<td>500,00 €</td>
</tr>
<tr style={{ borderBottom: '1px solid #eee' }}>
<td>PDF-Export Feature</td>
<td>1</td>
<td>150,00 €</td>
</tr>
</tbody>
</table>
<h3 style={{ marginTop: '20px', textAlign: 'right' }}>Gesamt: 650,00 €</h3>
</div>
{/* Button zum Auslösen des Downloads */}
<div style={{ textAlign: 'center', marginTop: '20px' }}>
<button
onClick={handleDownloadPdf}
style={{
padding: '10px 20px',
fontSize: '16px',
cursor: 'pointer',
backgroundColor: '#007bff',
color: '#fff',
border: 'none',
borderRadius: '4px'
}}
>
Als PDF herunterladen
</button>
</div>
</div>
);
};
export default PdfExportComponent;
3. Funktionsweise im Detail
useRef(null): Wir hängen die Referenz an das<div>, das gedruckt werden soll. Dadurch weißhtml2canvasexakt, welcher Bereich gerendert werden muss, ohne den Rest der Seite (wie den Download-Button) mitzunehmen.scale: 2(inhtml2canvas): Browser rendern standardmäßig mit 96 DPI, was im PDF schnell pixelig wirkt. Durch die Skalierung verdoppeln wir die Auflösung für ein scharfes Druckergebnis.- Proportionale Skalierung:
const pdfHeight = (canvas.height * pdfWidth) / canvas.width;Diese Formel stellt sicher, dass das Seitenverhältnis des HTML-Inhalts auf die Seitenbreite des A4-Formats skaliert wird, ohne dass Inhalte verzerrt werden.
pdf.save('name.pdf'): Löst direkt den Browser-Download mit dem angegebenen Dateinamen aus.
4. Wichtige Tipps für die Praxis
-
Bilder und CORS: Wenn in deinem zu druckenden HTML externe Bilder liegen, aktiviere immer
useCORS: truein denhtml2canvas-Optionen. Andernfalls verweigert der Browser das Auslesen des Canvas aus Sicherheitsgründen. -
Mehrseitige Dokumente (Pagination): Wenn dein Inhalt länger als eine DIN-A4-Seite ist, wird er mit dem obigen Code unten abgeschnitten. Für mehrseitige Dokumente muss die Höhe in einer Schleife geprüft und bei Bedarf
pdf.addPage()aufgerufen werden:let heightLeft = pdfHeight; let position = 0; const pageHeight = pdf.internal.pageSize.getHeight(); pdf.addImage(imgData, 'PNG', 0, position, pdfWidth, pdfHeight); heightLeft -= pageHeight; while (heightLeft > 0) { position = heightLeft - pdfHeight; pdf.addPage(); pdf.addImage(imgData, 'PNG', 0, position, pdfWidth, pdfHeight); heightLeft -= pageHeight; } -
CSS-Einschränkungen:
html2canvasunterstützt die meisten CSS-Eigenschaften (Flexbox, Grid, Border-Radius), interpretiert manche modernen Effekte wie komplexebox-shadowoder neuartige CSS-Filter jedoch manchmal ungenau. Halte das Druck-Layout daher möglichst sauber.