Certificados de conclusão, prêmios de mérito e diplomas de participação são essenciais para cursos online, workshops, conferências e programas de treinamento corporativo. Em vez de projetar cada certificado manualmente em uma ferramenta como o Canva, você pode construir uma aplicação web que os gera automaticamente a partir de um template. Neste tutorial, vamos construir um gerador de certificados baseado em React que produz certificados PDF profissionais usando o TongoRender.
O Que Vamos Construir
Nossa aplicação terá três partes:
- Um template de certificado projetado com HTML e CSS
- Um formulário React para inserir dados do destinatário
- Uma rota de API que renderiza o certificado como PDF
Passo 1: Design do Template de Certificado
Certificados precisam parecer elegantes. Usamos orientação paisagem A4 com borda decorativa, fontes cursivas e um layout formal:
export function certificateTemplate({ recipientName, courseName, completionDate, instructorName, certificateId }) {
return `
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<link href="https://fonts.googleapis.com/css2?family=Great+Vibes&family=Montserrat:wght@300;400;600&display=swap" rel="stylesheet">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { width: 297mm; height: 210mm; font-family: 'Montserrat', sans-serif; }
.certificate {
width: 100%; height: 100%;
border: 3px solid #1a365d; padding: 15mm;
background: linear-gradient(135deg, #fefefe 0%, #f7fafc 100%);
}
.inner-border {
width: 100%; height: 100%;
border: 1px solid #c9a84c; padding: 15mm;
display: flex; flex-direction: column;
align-items: center; justify-content: center; text-align: center;
}
.title { font-family: 'Great Vibes', cursive; font-size: 48pt; color: #1a365d; }
.subtitle { font-size: 14pt; color: #4a5568; letter-spacing: 4px; text-transform: uppercase; margin: 10mm 0 5mm; }
.recipient { font-family: 'Great Vibes', cursive; font-size: 36pt; color: #c9a84c; margin: 5mm 0; }
.description { font-size: 12pt; color: #4a5568; max-width: 500px; line-height: 1.6; }
</style>
</head>
<body>
<div class="certificate">
<div class="inner-border">
<div class="title">Certificado de Conclusão</div>
<div class="subtitle">Este certificado é conferido a</div>
<div class="recipient">${recipientName}</div>
<div class="description">
Por concluir com sucesso o curso
<strong>${courseName}</strong>
em ${completionDate}.
</div>
</div>
</div>
</body>
</html>`;
}
Passo 2: Construir o Formulário React
import { useState } from 'react';
export default function CertificateForm() {
const [formData, setFormData] = useState({
recipientName: '', courseName: '', completionDate: '', instructorName: '',
});
const [loading, setLoading] = useState(false);
const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true);
const response = await fetch('/api/generate-certificate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData),
});
const blob = await response.blob();
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `certificado-${formData.recipientName.replace(/\s+/g, '-')}.pdf`;
a.click();
setLoading(false);
};
return (
<form onSubmit={handleSubmit}>
<input placeholder="Nome do Destinatário" required
value={formData.recipientName}
onChange={e => setFormData({...formData, recipientName: e.target.value})} />
<input placeholder="Nome do Curso" required
value={formData.courseName}
onChange={e => setFormData({...formData, courseName: e.target.value})} />
<input type="date" required
value={formData.completionDate}
onChange={e => setFormData({...formData, completionDate: e.target.value})} />
<input placeholder="Nome do Instrutor" required
value={formData.instructorName}
onChange={e => setFormData({...formData, instructorName: e.target.value})} />
<button type="submit" disabled={loading}>
{loading ? 'Gerando...' : 'Gerar Certificado'}
</button>
</form>
);
}
Passo 3: Criar a Rota de API
// pages/api/generate-certificate.js (Next.js)
import { certificateTemplate } from '../../templates/certificate';
import { randomUUID } from 'crypto';
export default async function handler(req, res) {
const { recipientName, courseName, completionDate, instructorName } = req.body;
const certificateId = randomUUID().split('-')[0].toUpperCase();
const html = certificateTemplate({ recipientName, courseName, completionDate, instructorName, certificateId });
const pdfResponse = await fetch('https://api.tongorender.io/v1/pdf', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': process.env.TONGORENDER_API_KEY,
},
body: JSON.stringify({
html, format: 'A4', landscape: true,
margin: { top: '0mm', bottom: '0mm', left: '0mm', right: '0mm' },
printBackground: true,
}),
});
const pdfBuffer = Buffer.from(await pdfResponse.arrayBuffer());
res.setHeader('Content-Type', 'application/pdf');
res.send(pdfBuffer);
}
Passo 4: Geração em Lote
const csv = require('csv-parse/sync');
async function batchGenerate(csvPath) {
const records = csv.parse(fs.readFileSync(csvPath), { columns: true });
for (const record of records) {
const pdf = await generateCertificate(record);
fs.writeFileSync(`certificates/${record.name.replace(/\s+/g, '-')}.pdf`, pdf);
console.log(`Certificado gerado para ${record.name}`);
}
}
Dicas de Design para Certificados
- Use fontes decorativas com moderação — Fontes cursivas como Great Vibes funcionam para nomes e títulos, mas o texto do corpo deve ser limpo e legível.
- Inclua um ID único — Torna certificados verificáveis. Você pode vincular o ID a uma página de verificação no seu site.
- Imprima cores de fundo — Defina
printBackground: truenas opções da API. - Teste com nomes longos — Alguns destinatários têm nomes muito longos. Use dimensionamento responsivo de fonte.
- Adicione um QR code — Vincule-o a uma URL de verificação para maior autenticidade.
O TongoRender renderiza web fonts, gradientes CSS e layouts complexos fielmente, tornando-o ideal para geração de certificados.
Construa seu gerador de certificados com o TongoRender — 100 renderizações gratuitas por mês, sem necessidade de cartão de crédito.