tsara-pdf
v1.0.1
Published
TsaraPDF - Convertit du HTML en PDF paginé avec preview et telechargement
Maintainers
Readme
TsaraPDF
HTML → paginated PDF with built-in preview, customizable headers/footers, and download. Zero runtime dependencies (pure TypeScript + Canvas API).
Features
- HTML → PDF: pass a CSS selector, an ID, or an
HTMLElement. - Automatic pagination: splits content into
A4 / A3 / A5 / Letter / Legalpages (portrait or landscape) or a custom size. - Overflow handled: tables, lists, and long text — tags are closed and reopened on the next page so the markup stays valid.
- Headers / Footers: static HTML or a
(page, total) => stringfunction. - Built-in viewer: paginated preview with zoom, print, and download.
- 3 distribution modes: npm package (ESM), CDN bundle, Chrome MV3 extension.
- Built-in i18n: EN / FR / ES / DE / RU (viewer, errors, extension)
— customizable via
setLang/langoption /translations. - No runtime dependencies — only
typescriptas a devDependency.
Project structure
TsaraPDF/
├── src/ TypeScript source
│ ├── index.ts Public API (export / preview / toBlob / toDataURL)
│ ├── paginator.ts Splits HTML → pages
│ ├── renderer.ts HTML → canvas → PDF blob
│ ├── viewer.ts Built-in preview UI
│ └── types.ts Types + PAGE_SIZES + DEFAULT_OPTIONS
├── dist/ Build output (tsc + bundler)
├── chrome-extension/ Chrome MV3 extension
├── demo/ Standalone HTML demo
├── scripts/bundle.js CDN bundler (dist/tsara-pdf.min.js)
└── package.jsonInstallation
NPM
npm install tsara-pdfimport TsaraPDF from 'tsara-pdf';
TsaraPDF.export('#content', { filename: 'report.pdf' });CDN / script tag
<script src="path/to/dist/tsara-pdf.min.js"></script>
<script>
TsaraPDF.export('#content');
</script>Chrome extension
- Open
chrome://extensions - Enable Developer mode
- Load unpacked extension → select the chrome-extension/ folder
- The icon appears in the toolbar: click it to export the current page or the current selection to PDF.
API
// Export with viewer (default)
await TsaraPDF.export('#content', options);
// Alias: same as export({ ...options, showViewer: true })
await TsaraPDF.preview('#content', options);
// Produce a PDF Blob without any UI
const blob = await TsaraPDF.toBlob('#content', options);
// Produce a data URL (base64)
const url = await TsaraPDF.toDataURL('#content', options);The first argument accepts:
- a CSS selector (
'#content','.report','main > article') - or an options object with
sourceIdorsourceElement
Internationalization
Viewer toolbar, error messages, and the Chrome extension are translated into
English, French, Spanish, German, and Russian. By default, TsaraPDF
detects navigator.language; you can also force the language globally or
per call.
Global language
import TsaraPDF from 'tsara-pdf';
TsaraPDF.setLang('fr'); // 'en' | 'fr' | 'es' | 'de' | 'ru'
TsaraPDF.getLang(); // → 'fr'Per-call override
TsaraPDF.export('#content', {
lang: 'de', // this export will be in German, global untouched
filename: 'bericht.pdf',
});Custom translations
To keep a base language but patch a few labels:
TsaraPDF.export('#content', {
lang: 'fr',
translations: {
download: 'Récupérer mon document',
print: 'Envoyer à l\'imprimante',
},
});Or define a full custom language:
TsaraPDF.export('#content', {
translations: {
print: 'Drukuj',
download: 'Pobierz PDF',
close: 'Zamknij',
zoomIn: 'Powiększ',
zoomOut: 'Pomniejsz',
pagesCount: (n) => `${n} stron`,
elementNotFound: (s) => `nie znaleziono elementu "${s}"`,
sourceRequired: 'wymagane sourceId lub sourceElement',
renderError: (e) => `błąd renderowania: ${e}`,
},
});Available keys
| Key | Type | Usage |
|-------------------|--------------------------------|-------|
| print | string | "Print" button |
| download | string | "Download" button |
| close | string | Close-cross tooltip / aria-label |
| zoomIn | string | Zoom-in button tooltip |
| zoomOut | string | Zoom-out button tooltip |
| pagesCount | (n: number) => string | Pluralized page counter (N pages) |
| elementNotFound | (selector: string) => string | "Selector not found" error |
| sourceRequired | string | Missing sourceId / sourceElement error |
| renderError | (err: string) => string | HTML render error |
Chrome extension
The extension popup includes a language selector (top-right corner). The
choice is persisted in localStorage and forwarded to TsaraPDF.export
when exporting.
Options
| Option | Type | Default | Description |
|----------------|-----------------------------------|-------------------------------|-------------|
| filename | string | 'document.pdf' | Name of the downloaded file. |
| pageSize | 'A4' \| 'A3' \| 'A5' \| 'Letter' \| 'Legal' \| {width, height} | 'A4' | Page format. Dimensions in mm when passed as an object. |
| orientation | 'portrait' \| 'landscape' | 'portrait' | Page orientation. |
| margin | {top, right, bottom, left} | {15, 15, 20, 15} | Margins in mm. |
| header | string \| (page, total) => string | '' | HTML repeated at the top of every page. |
| footer | string \| (page, total) => string | ${page} / ${total} (centered) | HTML repeated at the bottom of every page. |
| scale | number | 2 | Render scale (2 = retina). |
| imageQuality | number (0–1) | 0.95 | JPEG quality for pages. |
| css | string | '' | Extra CSS injected before render (no <style> wrapper needed). |
| showViewer | boolean | true | Show the preview after generation. |
| onProgress | (current, total) => void | — | Callback invoked for each rendered page. |
| lang | 'en' \| 'fr' \| 'es' \| 'de' \| 'ru' | auto (navigator.language) | Language for this export (overrides the global setLang). |
| translations | Partial<Translations> | — | Label overrides (see Internationalization). |
| viewMode | 'all' \| 'single' | 'all' | Initial viewer mode. See Navigation. |
Navigation
The viewer offers two display modes, switchable from the toolbar:
- All pages (
'all', default) — continuous vertical scroll. - Page by page (
'single') — one page at a time with a nav bar:- ◀ Previous / Next ▶ buttons
- Numeric input to jump to a specific page (press
Enterto apply) - Keyboard shortcuts:
←/→,PageUp/PageDown,Space(next),Home/End,Esc(close)
Start directly in page-by-page mode:
TsaraPDF.export('#content', { viewMode: 'single' });Labels Previous / Next / Page X of Y follow the active language (see Internationalization).
Examples
Dynamic header / footer
TsaraPDF.export('#report', {
filename: 'report-Q1.pdf',
pageSize: 'A4',
margin: { top: 25, right: 15, bottom: 25, left: 15 },
header: (page, total) =>
`<div style="font-size:10px;color:#666">Q1 Report — page ${page}/${total}</div>`,
footer: (page) =>
`<div style="text-align:right;font-size:9px;color:#999">© 2026 — ${page}</div>`,
});No viewer, with progress
await TsaraPDF.export('#content', {
showViewer: false,
onProgress: (current, total) => {
console.log(`Rendering page ${current}/${total}`);
},
});Server-friendly generation (no UI)
const blob = await TsaraPDF.toBlob('#invoice', { pageSize: 'A4' });
const formData = new FormData();
formData.append('file', blob, 'invoice.pdf');
await fetch('/upload', { method: 'POST', body: formData });Custom format
TsaraPDF.export('#ticket', {
pageSize: { width: 80, height: 200 }, // 80mm ticket
margin: { top: 5, right: 5, bottom: 5, left: 5 },
showViewer: false,
});Demo
npm run demo
# or
open demo/index.htmlBuild
npm install
npm run build # tsc + bundler → dist/tsara-pdf.min.js
npm run dev # tsc --watchArtifacts generated in dist/:
index.js+*.js.map(compiled ES modules)*.d.ts(TypeScript declarations)tsara-pdf.min.js(CDN IIFE bundle, auto-exposeswindow.TsaraPDF)
Requirements
- Node 18+ and npm (for the build)
- Modern browser with Canvas API support (recent Chrome/Firefox/Safari/Edge)
License
MIT © Abraham Mahasongona
