Component Library Support
EasyPdf captures the live DOM exactly as the browser renders it. This means any styling the browser applies — regardless of how it was injected — appears in the PDF. CSS classes, inline styles, CSS-in-JS (Emotion, styled-components), Tailwind utilities, MUI theme tokens — all of it.
There is no configuration required. Just render your components and call downloadPDF.
Tailwind CSS
Tailwind classes are applied to the DOM as computed styles, which EasyPdf captures directly. No special setup needed.
import { useEasyPdf } from "@easypdf/react";
function Report() {
const { pdfRef, downloadPDF, isLoading } = useEasyPdf();
return (
<div>
<button onClick={() => downloadPDF(pdfRef)} disabled={isLoading}>
{isLoading ? "Generating..." : "Download PDF"}
</button>
<div ref={pdfRef} className="max-w-2xl mx-auto p-8 font-sans bg-white">
<h1 className="text-3xl font-bold text-gray-900 mb-2">Sales Report</h1>
<p className="text-sm text-gray-500 mb-6">Q1 2024</p>
<div className="grid grid-cols-3 gap-4 mb-8">
{[
{ label: "Revenue", value: "$84,254" },
{ label: "Users", value: "3,842" },
{ label: "Churn", value: "2.1%" },
].map((stat) => (
<div key={stat.label} className="border border-gray-200 rounded-lg p-4">
<p className="text-xs text-gray-500 uppercase tracking-wide">{stat.label}</p>
<p className="text-2xl font-semibold text-gray-900 mt-1">{stat.value}</p>
</div>
))}
</div>
<table className="w-full text-sm">
<thead>
<tr className="border-b border-gray-200">
<th className="text-left py-2 text-gray-500 font-medium">Product</th>
<th className="text-right py-2 text-gray-500 font-medium">Revenue</th>
</tr>
</thead>
<tbody>
<tr className="border-b border-gray-100">
<td className="py-2 text-gray-900">Pro License</td>
<td className="py-2 text-right font-medium text-gray-900">$62,000</td>
</tr>
<tr className="border-b border-gray-100">
<td className="py-2 text-gray-900">Enterprise Suite</td>
<td className="py-2 text-right font-medium text-gray-900">$22,254</td>
</tr>
</tbody>
</table>
</div>
</div>
);
}MUI (Material UI)
MUI v5 uses Emotion for CSS-in-JS. EasyPdf resolves all Emotion-injected styles at capture time via getComputedStyle, so MUI components render with full layout, color, and typography in the PDF.
import { useEasyPdf } from "@easypdf/react";
import {
Box, Typography, Paper, Table, TableBody,
TableCell, TableContainer, TableHead, TableRow, Chip,
} from "@mui/material";
function MuiReport() {
const { pdfRef, downloadPDF, isLoading } = useEasyPdf({
pageSize: "A4",
margins: { top: 20, right: 20, bottom: 20, left: 20 },
});
const rows = [
{ product: "Pro License", revenue: "$62,000", status: "Active" },
{ product: "Enterprise Suite", revenue: "$22,254", status: "Active" },
{ product: "Starter Kit", revenue: "$13,140", status: "Pending" },
];
return (
<div>
<button onClick={() => downloadPDF(pdfRef)} disabled={isLoading}>
{isLoading ? "Generating..." : "Download PDF"}
</button>
<Box ref={pdfRef} sx={{ p: 4, bgcolor: "#fafafa" }}>
<Paper elevation={2} sx={{ p: 3, mb: 3, bgcolor: "#1976d2", color: "white" }}>
<Typography variant="h5">Sales Report</Typography>
<Typography variant="body2" sx={{ opacity: 0.85, mt: 0.5 }}>Q1 2024</Typography>
</Paper>
<Paper variant="outlined" className="no-break">
<TableContainer>
<Table size="small">
<TableHead>
<TableRow sx={{ bgcolor: "#fafafa" }}>
{["Product", "Revenue", "Status"].map((h) => (
<TableCell key={h} sx={{ fontWeight: 600, fontSize: "0.75rem", color: "#9e9e9e", textTransform: "uppercase" }}>
{h}
</TableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{rows.map((row) => (
<TableRow key={row.product}>
<TableCell>{row.product}</TableCell>
<TableCell sx={{ fontWeight: 500 }}>{row.revenue}</TableCell>
<TableCell>
<Chip
label={row.status}
size="small"
color={row.status === "Active" ? "success" : "warning"}
variant="outlined"
/>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</Paper>
</Box>
</div>
);
}shadcn/ui
shadcn/ui components use Tailwind CSS and CSS custom properties (CSS variables) for theming. EasyPdf copies all CSS variables from :root into the capture context, so shadcn themes and colors render correctly.
import { useEasyPdf } from "@easypdf/react";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
function ShadcnReport() {
const { pdfRef, downloadPDF, isLoading } = useEasyPdf();
return (
<div>
<button onClick={() => downloadPDF(pdfRef)} disabled={isLoading}>
{isLoading ? "Generating..." : "Download PDF"}
</button>
<div ref={pdfRef} className="p-8 bg-background">
<h1 className="text-2xl font-semibold tracking-tight text-foreground mb-6">
Sales Report
</h1>
<div className="grid grid-cols-3 gap-4 mb-6">
{[
{ label: "Total Revenue", value: "$84,254" },
{ label: "Active Users", value: "3,842" },
{ label: "Churn Rate", value: "2.1%" },
].map((stat) => (
<Card key={stat.label} className="no-break">
<CardHeader className="pb-2">
<p className="text-sm text-muted-foreground">{stat.label}</p>
</CardHeader>
<CardContent>
<p className="text-2xl font-bold">{stat.value}</p>
</CardContent>
</Card>
))}
</div>
<Card className="no-break">
<CardHeader>
<CardTitle>Recent Orders</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-2">
{[
{ name: "Olivia Martin", amount: "+$1,999", status: "Success" },
{ name: "Jackson Lee", amount: "-$39", status: "Processing" },
{ name: "Isabella Nguyen", amount: "+$299", status: "Success" },
].map((row) => (
<div key={row.name} className="flex items-center justify-between py-1">
<span className="text-sm font-medium">{row.name}</span>
<div className="flex items-center gap-3">
<Badge variant={row.status === "Success" ? "default" : "secondary"}>
{row.status}
</Badge>
<span className="text-sm font-semibold">{row.amount}</span>
</div>
</div>
))}
</div>
</CardContent>
</Card>
</div>
</div>
);
}Tips for All Libraries
Prevent elements from splitting across pages
Add the no-break class to any element that should always stay on one page:
<Card className="no-break">
{/* This card will never be split across pages */}
</Card>The following element types are automatically treated as unbreakable: <table>, <figure>, <img>, <pre>, <code>, <ul>, <ol>.
Fix layout width
Pin a container width so the PDF layout is consistent regardless of the browser window size:
const { pdfRef, downloadPDF } = useEasyPdf({
container: {
style: { width: "800px" },
},
});External images
Add crossOrigin="anonymous" to any <img> that loads from a different domain:
<img src="https://example.com/logo.png" crossOrigin="anonymous" alt="Logo" />