Glyph vs jsPDF for PDF Generation
jsPDF is a popular client-side library for generating PDFs in JavaScript. It has been the go-to solution for developers who need PDFs without server-side rendering. But Glyph takes a fundamentally different approach: HTML templates + AI-native customization instead of manual coordinate-based drawing.
This guide provides an objective comparison to help you choose the right tool for your use case.
Quick Comparison
Section titled “Quick Comparison”| Feature | Glyph | jsPDF |
|---|---|---|
| Approach | HTML templates + AI | Coordinate-based drawing |
| Setup complexity | 2 lines of code | Learn coordinate system |
| Template modification | Natural language (“make header blue”) | Manual coordinate math |
| Learning curve | Low (describe what you want) | High (x, y coordinates, units) |
| Runtime | API-based (server) | Client-side JavaScript |
| Design quality | Professional templates included | Manual styling from scratch |
| User-facing editor | Built-in web component | Build your own |
| AI-powered customization | Native | Not available |
| Complex layouts | CSS Grid/Flexbox | Manual positioning |
| Images | HTML img tags | Base64 + coordinates |
Code Complexity Comparison
Section titled “Code Complexity Comparison”Generating a Simple Invoice PDF
Section titled “Generating a Simple Invoice PDF”// 3 lines to generate a professional invoiceconst response = await fetch('https://api.glyph.you/v1/create', { method: 'POST', headers: { 'Authorization': 'Bearer gk_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ template: 'invoice-clean', data: { client: { name: 'Acme Corp', email: 'billing@acme.com' }, lineItems: [ { description: 'Consulting', quantity: 10, unitPrice: 150, total: 1500 }, { description: 'Development', quantity: 20, unitPrice: 125, total: 2500 } ], totals: { subtotal: 4000, tax: 360, total: 4360 } } })});
const { url } = await response.json();// Done. Professional PDF hosted at `url`const { jsPDF } = require('jspdf');
function generateInvoicePDF(data) { const doc = new jsPDF();
// Header - manual positioning required doc.setFontSize(24); doc.setFont('helvetica', 'bold'); doc.text('INVOICE', 20, 30);
// Company info - calculate every position doc.setFontSize(10); doc.setFont('helvetica', 'normal'); doc.text('Your Company Name', 20, 45); doc.text('123 Business St', 20, 50); doc.text('City, State 12345', 20, 55);
// Client info doc.setFont('helvetica', 'bold'); doc.text('Bill To:', 120, 45); doc.setFont('helvetica', 'normal'); doc.text(data.client.name, 120, 50); doc.text(data.client.email, 120, 55);
// Line items table - manual table drawing let y = 80; doc.setFillColor(240, 240, 240); doc.rect(20, y - 5, 170, 10, 'F'); doc.setFont('helvetica', 'bold'); doc.text('Description', 25, y); doc.text('Qty', 100, y); doc.text('Price', 130, y); doc.text('Total', 160, y);
y += 15; doc.setFont('helvetica', 'normal'); data.lineItems.forEach(item => { doc.text(item.description, 25, y); doc.text(String(item.quantity), 100, y); doc.text(`$${item.unitPrice}`, 130, y); doc.text(`$${item.total}`, 160, y); y += 10; });
// Totals - more coordinate math y += 10; doc.line(120, y, 190, y); y += 10; doc.text('Subtotal:', 130, y); doc.text(`$${data.totals.subtotal}`, 160, y); y += 7; doc.text('Tax:', 130, y); doc.text(`$${data.totals.tax}`, 160, y); y += 7; doc.setFont('helvetica', 'bold'); doc.text('Total:', 130, y); doc.text(`$${data.totals.total}`, 160, y);
return doc.output('blob');
// And this is a SIMPLE invoice. // Adding styling, colors, logos, or complex layouts // requires exponentially more coordinate calculations.}Lines of code: Glyph ~15 vs jsPDF ~60+ (and jsPDF produces a basic layout)
Adding an Image (Logo)
Section titled “Adding an Image (Logo)”// Just include in your dataconst response = await fetch('https://api.glyph.you/v1/create', { method: 'POST', headers: { 'Authorization': 'Bearer gk_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ template: 'invoice-clean', data: { company: { logo: 'https://yoursite.com/logo.png', // Just a URL name: 'Acme Corp' }, // ... rest of data } })});// Template handles positioning, sizing, responsive scalingconst { jsPDF } = require('jspdf');
async function addLogoToPDF(doc, imageUrl) { // First, fetch and convert to base64 const response = await fetch(imageUrl); const blob = await response.blob();
return new Promise((resolve) => { const reader = new FileReader(); reader.onloadend = () => { const base64 = reader.result.split(',')[1];
// Determine image format const format = imageUrl.endsWith('.png') ? 'PNG' : 'JPEG';
// Add to PDF with manual coordinates // x, y, width, height - all manual calculation doc.addImage(base64, format, 20, 10, 40, 20);
// If image aspect ratio doesn't match 40x20, // it will be stretched/squished. // Maintaining aspect ratio requires more code.
resolve(); }; reader.readAsDataURL(blob); });}
// Usageconst doc = new jsPDF();await addLogoToPDF(doc, 'https://yoursite.com/logo.png');// Now manually position everything else around the logoThe difference: Glyph templates handle layout automatically. jsPDF requires manual image loading, format detection, coordinate calculations, and aspect ratio management.
Creating a Multi-Page Document
Section titled “Creating a Multi-Page Document”// Glyph handles pagination automaticallyconst response = await fetch('https://api.glyph.you/v1/create', { method: 'POST', headers: { 'Authorization': 'Bearer gk_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ template: 'invoice-clean', data: { lineItems: generateManyLineItems(50), // 50 line items // Template CSS handles page breaks automatically // Headers/footers repeat on each page } })});// Multi-page PDF generated with proper page breaksfunction generateMultiPageInvoice(doc, lineItems) { const pageHeight = doc.internal.pageSize.height; const margin = 20; const headerHeight = 60; const footerHeight = 30; const lineHeight = 10; let y = headerHeight; let pageNum = 1;
function addHeader() { doc.setFontSize(16); doc.text('INVOICE', 20, 30); doc.setFontSize(10); doc.text(`Page ${pageNum}`, 180, 30); // Draw table header... y = headerHeight; }
function addFooter() { doc.setFontSize(8); doc.text('Company Name | Address | Phone', 105, pageHeight - 15, { align: 'center' }); }
function checkPageBreak() { if (y > pageHeight - footerHeight - lineHeight) { addFooter(); doc.addPage(); pageNum++; addHeader(); } }
addHeader();
lineItems.forEach(item => { checkPageBreak(); doc.text(item.description, 25, y); doc.text(String(item.quantity), 100, y); doc.text(`$${item.total}`, 160, y); y += lineHeight; });
addFooter();
// This is the minimal implementation. // Handling orphan/widow control, table splitting, // and dynamic content is far more complex.}The difference: Glyph uses CSS @page rules and break-inside: avoid for intelligent pagination. jsPDF requires manual page break tracking and content repositioning.
Modifying a Document with User Input
Section titled “Modifying a Document with User Input”// User says "make the total section stand out more"const response = await fetch('https://api.glyph.you/v1/modify', { method: 'POST', headers: { 'Authorization': 'Bearer gk_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ sessionId: 'existing-session-id', prompt: 'Make the total section stand out more', region: 'totals' })});
const { html, changes } = await response.json();// AI adds bold text, larger font, maybe a background color// All changes validated by self-checking guardrails// jsPDF has no concept of document modification// You must:// 1. Parse user intent (requires NLP/AI integration)// 2. Identify which drawing commands to change// 3. Store the entire document state// 4. Re-execute all drawing commands with modifications
// There's no built-in way to:// - Identify "the total section"// - Understand "stand out more"// - Apply changes to existing content
// You'd need to build an entire editing layer// on top of jsPDF from scratch.The difference: Glyph understands document semantics and natural language. jsPDF is a one-way drawing API with no modification capability.
Providing End-User Editing
Section titled “Providing End-User Editing”<!-- Drop-in web component --><script src="https://sdk.glyph.you/glyph.min.js"></script>
<glyph-editor api-key="gk_your_key" template="invoice-clean" data='{"client": {"name": "Acme Corp"}}'></glyph-editor>
<!-- Users can click any region, describe changes, see preview, download PDF -->// jsPDF is generation-only, not editing.// To build a user editing experience, you need:
// 1. A canvas or HTML preview layer// 2. Click detection and region mapping// 3. An editing UI (inputs, pickers, etc.)// 4. State management for all document properties// 5. Real-time re-rendering on changes// 6. Synchronization between preview and jsPDF output// 7. Download functionality
// This is a completely separate application// that would take weeks to build properly.When to Use jsPDF
Section titled “When to Use jsPDF”jsPDF remains the right choice when you need:
- Client-side only - No server calls allowed, everything in browser
- Simple documents - Basic text and shapes, no complex layouts
- Offline capability - PDFs must generate without internet
- No dependencies - Zero external service requirements
- Small file sizes - jsPDF produces compact files for simple docs
- Existing investment - You have working jsPDF code to maintain
When to Use Glyph
Section titled “When to Use Glyph”Glyph is the better choice when:
- Design quality matters - Professional templates, not hand-drawn layouts
- Complex layouts - Tables, images, multi-column, pagination
- Users need customization - End-users should modify documents
- AI-native workflows - Documents should respond to natural language
- Development speed - Ship in hours, not weeks
- Maintainability - HTML/CSS templates vs coordinate spaghetti
- Scaling concerns - Complex PDFs slow down client-side generation
Feature Deep Dive
Section titled “Feature Deep Dive”Layout Capabilities
Section titled “Layout Capabilities”| Layout Feature | Glyph | jsPDF |
|---|---|---|
| CSS Grid | Full support | Not available |
| Flexbox | Full support | Not available |
| Tables | HTML tables | Manual row/column math |
| Responsive images | CSS object-fit | Manual aspect ratio |
| Page breaks | CSS break rules | Manual tracking |
| Headers/footers | Template includes | Manual per-page |
Text Handling
Section titled “Text Handling”| Text Feature | Glyph | jsPDF |
|---|---|---|
| Rich formatting | HTML/CSS | Multiple draw calls |
| Line wrapping | Automatic | Manual splitTextToSize() |
| Fonts | Web fonts via CSS | Limited, manual loading |
| International text | Full Unicode | Requires font embedding |
| Alignment | CSS text-align | Manual positioning |
Development Experience
Section titled “Development Experience”| Aspect | Glyph | jsPDF |
|---|---|---|
| Time to first PDF | 5 minutes | 1-2 hours |
| Design iteration | Edit HTML/CSS | Adjust coordinates |
| Debugging | Browser DevTools | Trial and error |
| Template reuse | Built-in system | Copy-paste code |
| Documentation | Comprehensive | API reference |
Migration Guide: jsPDF to Glyph
Section titled “Migration Guide: jsPDF to Glyph”Step 1: Analyze Your jsPDF Code
Section titled “Step 1: Analyze Your jsPDF Code”Identify the document structure from your drawing commands:
// jsPDF code analysisdoc.text('INVOICE', 20, 30); // -> headerdoc.text('Bill To:', 120, 45); // -> client sectiondoc.rect(...); // -> table structuredoc.text(item.description, ...); // -> line itemsStep 2: Create HTML Template
Section titled “Step 2: Create HTML Template”Convert the implicit structure to explicit HTML:
<html><head> <style> .header { font-size: 24px; font-weight: bold; } .client-section { margin-left: 50%; } .line-items { width: 100%; border-collapse: collapse; } .line-items th { background: #f0f0f0; } </style></head><body> <div class="header" data-glyph-region="header">INVOICE</div>
<div class="client-section" data-glyph-region="client"> <strong>Bill To:</strong><br> {{client.name}}<br> {{client.email}} </div>
<table class="line-items" data-glyph-region="items"> <thead> <tr><th>Description</th><th>Qty</th><th>Price</th><th>Total</th></tr> </thead> <tbody> {{#lineItems}} <tr> <td>{{description}}</td> <td>{{quantity}}</td> <td>${{unitPrice}}</td> <td>${{total}}</td> </tr> {{/lineItems}} </tbody> </table>
<div class="totals" data-glyph-region="totals"> <div>Subtotal: ${{totals.subtotal}}</div> <div>Tax: ${{totals.tax}}</div> <div><strong>Total: ${{totals.total}}</strong></div> </div></body></html>Step 3: Create Schema
Section titled “Step 3: Create Schema”{ "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": ["client", "lineItems", "totals"], "properties": { "client": { "type": "object", "properties": { "name": { "type": "string" }, "email": { "type": "string" } } }, "lineItems": { "type": "array", "items": { "type": "object", "properties": { "description": { "type": "string" }, "quantity": { "type": "number" }, "unitPrice": { "type": "number" }, "total": { "type": "number" } } } }, "totals": { "type": "object", "properties": { "subtotal": { "type": "number" }, "tax": { "type": "number" }, "total": { "type": "number" } } } }}Step 4: Upload and Use
Section titled “Step 4: Upload and Use”# Upload custom templatecurl -X POST https://api.glyph.you/v1/templates \ -H "Authorization: Bearer gk_your_api_key" \ -F "name=my-invoice" \ -F "template=@./template.html" \ -F "schema=@./schema.json"// Before (jsPDF)function generate(data) { const doc = new jsPDF(); // 50+ lines of coordinate-based drawing return doc.output('blob');}
// After (Glyph)async function generate(data) { const response = await fetch('https://api.glyph.you/v1/create', { method: 'POST', headers: { 'Authorization': 'Bearer gk_your_api_key', 'Content-Type': 'application/json' }, body: JSON.stringify({ template: 'my-invoice', data }) }); return response.json();}Step 5: Add User Editing (Bonus)
Section titled “Step 5: Add User Editing (Bonus)”What was impossible with jsPDF is now trivial:
<glyph-editor api-key="gk_your_key" template="my-invoice" :data="invoiceData"></glyph-editor>Cost Comparison
Section titled “Cost Comparison”| Factor | Glyph | jsPDF |
|---|---|---|
| Library cost | $0-129/mo based on volume | $0 (open source) |
| Development time | Hours | Days to weeks |
| Design cost | $0 (templates included) | Designer or DIY |
| Maintenance | Zero | Ongoing coordinate updates |
| User editing | Included | Build from scratch (weeks) |
Common Migration Questions
Section titled “Common Migration Questions””Can I still generate PDFs client-side?”
Section titled “”Can I still generate PDFs client-side?””Glyph is API-based, so PDFs generate on our servers. This provides:
- Consistent rendering across browsers
- No client performance impact
- Access to server-side fonts and resources
- CDN-hosted output files
If you absolutely need client-side generation (offline apps), jsPDF may still be appropriate for simple documents.
”What about bundle size?”
Section titled “”What about bundle size?””jsPDF adds ~300KB to your bundle. Glyph SDK is ~15KB (API calls only). Your bundle gets smaller while gaining more capabilities.
”Can I use my existing jsPDF code alongside Glyph?”
Section titled “”Can I use my existing jsPDF code alongside Glyph?””Yes. You can migrate incrementally. Use Glyph for new documents and complex layouts while maintaining existing jsPDF code for simple PDFs.
Summary
Section titled “Summary”Choose Glyph if you want professional-quality documents, complex layouts, user editing capabilities, AI-powered customization, and faster development.
Choose jsPDF if you need purely client-side generation, have simple layout requirements, need offline capability, or have existing working code.
jsPDF is a capable low-level tool for programmatic PDF drawing. Glyph is a high-level platform for document generation and customization. They serve different needs at different levels of abstraction.
Next Steps
Section titled “Next Steps”- Quick Start - Generate your first PDF in 5 minutes
- Templates - Browse professional templates
- Custom Templates - Create your own templates
- SDK Overview - Add user editing to your app