Instalação
npm install json-pdf-designer
Peer deps: react e react-dom (^18.0.0 || ^19.0.0) mais o
react-rnd (lib de arrastar/redimensionar do canvas) — todos marcados
optional em peerDependenciesMeta, então uma instalação só de backend
nunca força eles (ver Uso só no servidor). Usar o
lado <Designer> do pacote significa instalar os três:
npm install react react-dom react-rnd
O pdfjs-dist também é peer dependency opcional — necessário só pro
preview do PDF, que mora atrás do entry point
json-pdf-designer/preview. Instale se for usar o preview:
npm install pdfjs-dist
Deixar de instalar economiza ~35MB no seu node_modules; <Designer>,
generatePdf e downloadPdf nunca tocam no pdf.js. Ver
Componentes de UI prontos pro preview e o
examples/no-preview pra um app que nunca o instala.
Importe o CSS do pacote uma vez, no entrypoint do seu app — ele
estiliza o próprio <Designer> (painel de propriedades, toolbar, abas):
import "json-pdf-designer/theme.css";
O theme.css é CSS escrito à mão e independente — sem build step, sem
Tailwind em ponta nenhuma, e ele importa o reset do pacote por dentro,
então esta única linha é tudo. Não importar é modo suportado, não
erro: as classes .jpd-* e os atributos data-* continuam no DOM, e
você os estiliza com o que usar. Veja Tema e CSS pro
contrato de classe e de token, e o json-pdf-designer/reset.css se você
quiser o reset sem a nossa aparência.
O json-pdf-designer/style.css morreu e não tem alias — o import antigo
falha com ERR_PACKAGE_PATH_NOT_EXPORTED. Veja
Migrando pra 3.0.0.
Uso básico
import { useState } from "react";
import { Designer, generatePdf, downloadPdf, type Template, type Binding } from "json-pdf-designer";
import "json-pdf-designer/theme.css";
const initialTemplate: Template = {
page: { width: 210, height: 297 }, // A4 em mm
schemas: [],
};
function Report() {
const [template, setTemplate] = useState<Template>(initialTemplate);
const [bindings, setBindings] = useState<Binding[]>([]);
async function handleGenerate() {
const data = await fetchMyData(); // o JSON de verdade que popula os campos
const pdfBytes = await generatePdf(template, data, bindings);
downloadPdf(pdfBytes, "relatorio.pdf");
}
return (
<>
<Designer
template={template}
onChangeTemplate={setTemplate}
bindings={bindings}
onChangeBindings={setBindings}
/>
<button onClick={handleGenerate}>Gerar PDF</button>
</>
);
}
onChangeTemplate/onChangeBindings aceitam a forma funcional do
setState do React ((prev) => next) — use direto o setter do
useState, como no exemplo, pra não perder um campo se dois forem
adicionados em sequência rápida.