JavaScript Framework Templates
Create dynamic and complex document templates using React, Vue, Angular, Svelte, or any JavaScript framework
JavaScript Framework Templates
Pogodoc allows you to leverage the power and flexibility of React, Vue, Angular, Svelte, or any JavaScript framework to create dynamic and complex document templates. This guide will walk you through the process of setting up a JavaScript framework project to be used as a Pogodoc template.
Any JavaScript framework that builds to static HTML works! This guide uses React as an example, but the same principles apply to Vue, Angular, Svelte, and others.
Overview
Unlike simple template strings (like EJS or HTML), JavaScript framework templates require:
- A build process to compile your components
- Packaging the build output as a ZIP file
- Uploading the ZIP to Pogodoc
Project Setup
While you can use any React setup (like Create React App, Next.js in static export mode, or a custom webpack configuration), we recommend using Vite for a fast and straightforward setup.
Create a new React project with TypeScript using Vite:
npm create vite@latest my-react-template -- --template react-ts
cd my-react-template
npm installnpm create vite@latest my-vue-template -- --template vue-ts
cd my-vue-template
npm installnpm create vite@latest my-svelte-template -- --template svelte-ts
cd my-svelte-template
npm installThis creates a new directory with a basic project structure.
Accessing Template Data
When Pogodoc renders your template, it injects the JSON data you provide into the window object under the __POGODOC_DATA__ property. To access this data in a type-safe way, create a helper file.
Create src/config.ts:
declare global {
interface Window {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
__POGODOC_DATA__: any;
}
}
export const pogodocData = window.__POGODOC_DATA__;This declares a global __POGODOC_DATA__ property on the window object and exports the data for easy use throughout your application.
You can also create a proper TypeScript interface for your data instead of using any for better type safety.
Create Your Template
Now you can import and use the data in any of your components.
import { pogodocData } from './config';
function App() {
return (
<div style={{ fontFamily: 'Arial', padding: '40px' }}>
<h1>Invoice for {pogodocData.customer.name}</h1>
<table style={{ width: '100%', borderCollapse: 'collapse' }}>
<thead>
<tr>
<th style={{ textAlign: 'left', borderBottom: '2px solid #333' }}>Item</th>
<th style={{ textAlign: 'right', borderBottom: '2px solid #333' }}>Price</th>
</tr>
</thead>
<tbody>
{pogodocData.items.map((item: any, i: number) => (
<tr key={i}>
<td style={{ padding: '8px 0' }}>{item.name}</td>
<td style={{ textAlign: 'right' }}>\${item.price.toFixed(2)}</td>
</tr>
))}
</tbody>
</table>
<h2 style={{ textAlign: 'right', marginTop: '20px' }}>
Total: \${pogodocData.total.toFixed(2)}
</h2>
</div>
);
}
export default App;<script setup lang="ts">
import { pogodocData } from './config';
</script>
<template>
<div style="font-family: Arial; padding: 40px">
<h1>Invoice for {{ pogodocData.customer.name }}</h1>
<table style="width: 100%; border-collapse: collapse">
<thead>
<tr>
<th style="text-align: left; border-bottom: 2px solid #333">Item</th>
<th style="text-align: right; border-bottom: 2px solid #333">Price</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, i) in pogodocData.items" :key="i">
<td style="padding: 8px 0">{{ item.name }}</td>
<td style="text-align: right">\${{ item.price.toFixed(2) }}</td>
</tr>
</tbody>
</table>
<h2 style="text-align: right; margin-top: 20px">
Total: \${{ pogodocData.total.toFixed(2) }}
</h2>
</div>
</template><script lang="ts">
import { pogodocData } from './config';
</script>
<div style="font-family: Arial; padding: 40px">
<h1>Invoice for {pogodocData.customer.name}</h1>
<table style="width: 100%; border-collapse: collapse">
<thead>
<tr>
<th style="text-align: left; border-bottom: 2px solid #333">Item</th>
<th style="text-align: right; border-bottom: 2px solid #333">Price</th>
</tr>
</thead>
<tbody>
{#each pogodocData.items as item, i}
<tr>
<td style="padding: 8px 0">{item.name}</td>
<td style="text-align: right">\${item.price.toFixed(2)}</td>
</tr>
{/each}
</tbody>
</table>
<h2 style="text-align: right; margin-top: 20px">
Total: \${pogodocData.total.toFixed(2)}
</h2>
</div>Build Your Template
After creating your template, build it to generate the static HTML, CSS, and JavaScript files.
Run the build command:
npm run buildThis creates a dist directory containing your bundled application.
Package as ZIP
Zip the contents of the dist folder (not the dist folder itself).
cd dist
zip -r ../my-template.zip .
cd ..Important: Only the contents of the dist folder should be zipped, not the dist folder itself. The root of your ZIP should contain index.html, not a dist/ folder.
Upload to Pogodoc
Save your template to your Pogodoc account.
Follow "Creating Templates". Or, save templates through the SDKs or our API.
Generate Documents
Now you can generate documents using the templateId of your saved template.
Best Practices
1. Inline Styles
For documents (especially PDFs), use inline styles instead of CSS classes:
// ✅ Good - inline styles
<div style={{ color: '#333', fontSize: '14px' }}>Content</div>
// ❌ Bad - CSS classes might not work
<div className="text-gray-700 text-sm">Content</div>2. Absolute Units
Use absolute units (px, pt, cm) instead of relative units (rem, em, %) for consistent sizing:
// ✅ Good - absolute units
<div style={{ padding: '20px', fontSize: '14px' }}>Content</div>
// ❌ Bad - relative units
<div style={{ padding: '2rem', fontSize: '1em' }}>Content</div>3. Avoid External Resources
Include all assets (images, fonts) in your ZIP or use data URLs:
// ✅ Good - base64 image
<img src="data:image/png;base64,iVBORw0KGgo..." alt="Logo" />
// ❌ Bad - external URL might not load
<img src="https://example.com/logo.png" alt="Logo" />4. Test Locally
Before uploading, test your template locally:
npm run build
npm run developMake sure it renders correctly in the browser before uploading to Pogodoc.
Pro Tip: To preview how Pogodoc will render a PDF document you can use
Ctrl/Cmd + P in your browser and preview how it would look like.
Framework-Specific Tips
React
- Use
create-react-apporvitefor setup - Avoid hooks that depend on browser APIs (like
useEffectwith timers) - Use React 18+ for best compatibility
Vue
- Use
create-vueorvitefor setup - Avoid lifecycle hooks that depend on browser timing
- Use Vue 3+ for best compatibility
Angular
- Use Angular CLI for setup
- Configure for production build with
ng build --prod - Disable animations that might not work in PDF rendering
Svelte
- Use
vitewith Svelte template - Avoid stores that depend on browser APIs
- Use Svelte 3+ for best compatibility
Troubleshooting
Template Not Rendering
- Check that
index.htmlis at the root of your ZIP - Verify
window.__POGODOC_DATA__is being accessed correctly - Check browser console for errors in preview
Styling Issues
- Ensure all styles are inline or in
<style>tags - Use absolute units (px, pt) instead of relative (rem, em)
- Test with different page sizes (A4, Letter, etc.)
Build Size Too Large
- Minimize dependencies
- Use code splitting
- Remove unused code with tree shaking
- Compress images before including
Examples
Invoice Template (React)
Complete invoice template with line items and totals
Report Template (Vue)
Multi-page report with charts and tables
Certificate Template (Svelte)
Certificate of completion with custom styling