{"id":45719473,"url":"https://github.com/danmolitor/forme","last_synced_at":"2026-05-19T21:01:47.115Z","repository":{"id":340382922,"uuid":"1160410096","full_name":"danmolitor/forme","owner":"danmolitor","description":"PDF generation with JSX. Page breaks that actually work.","archived":false,"fork":false,"pushed_at":"2026-04-29T13:08:41.000Z","size":20205,"stargazers_count":122,"open_issues_count":1,"forks_count":6,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-15T19:53:17.715Z","etag":null,"topics":["developer-tools","jsx","pdf","pdf-generation","react","rust","typescript","wasm"],"latest_commit_sha":null,"homepage":"https://www.formepdf.com","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/danmolitor.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"danmolitor"}},"created_at":"2026-02-17T22:49:17.000Z","updated_at":"2026-05-13T13:40:32.000Z","dependencies_parsed_at":null,"dependency_job_id":"c1c76489-a5ff-47f6-8213-38ed89ff8e34","html_url":"https://github.com/danmolitor/forme","commit_stats":null,"previous_names":["formepdf/forme"],"tags_count":29,"template":false,"template_full_name":null,"purl":"pkg:github/danmolitor/forme","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danmolitor%2Fforme","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danmolitor%2Fforme/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danmolitor%2Fforme/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danmolitor%2Fforme/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/danmolitor","download_url":"https://codeload.github.com/danmolitor/forme/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danmolitor%2Fforme/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33233081,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-19T15:49:41.270Z","status":"ssl_error","status_checked_at":"2026-05-19T15:49:22.917Z","response_time":58,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["developer-tools","jsx","pdf","pdf-generation","react","rust","typescript","wasm"],"created_at":"2026-02-25T05:30:23.736Z","updated_at":"2026-05-19T21:01:47.109Z","avatar_url":"https://github.com/danmolitor.png","language":"Rust","funding_links":["https://github.com/sponsors/danmolitor"],"categories":[],"sub_categories":[],"readme":"# forme\n\nPDF generation with JSX. Page breaks that actually work.\n\n![Forme dev server](./assets/dev-server.gif)\n\n## Why\n\nEvery PDF tool makes you choose: fight with CSS page breaks or use an editor that can't handle dynamic data. Forme is a layout engine built for pages. No headless browser. No Chrome. Renders in milliseconds. Runs anywhere — Node, the browser, or at the edge.\n\n**[Try it in the playground](https://playground.formepdf.com/)**\n\n## Quick Start\n\n```bash\nnpm install @formepdf/cli @formepdf/react @formepdf/core\n```\n\n```tsx\nimport { Document, Page, View, Text } from '@formepdf/react';\nimport { renderDocument } from '@formepdf/core';\n\nconst pdf = await renderDocument(\n  \u003cDocument\u003e\n    \u003cPage size=\"Letter\" margin={36}\u003e\n      \u003cText style={{ fontSize: 24, fontWeight: 'bold' }}\u003eInvoice #2024-001\u003c/Text\u003e\n      \u003cView style={{ flexDirection: 'row', justifyContent: 'space-between', marginTop: 24 }}\u003e\n        \u003cText\u003eWidget Pro\u003c/Text\u003e\n        \u003cText\u003e$49.00\u003c/Text\u003e\n      \u003c/View\u003e\n    \u003c/Page\u003e\n  \u003c/Document\u003e\n);\n\n// pdf is a Uint8Array: save it, serve it, email it\n```\n\n## Dev Server\n\n```bash\nnpx forme dev invoice.tsx --data sample.json\n```\n\nLive preview with debug overlays. Click any element to inspect its computed styles.\n\n## VS Code Extension\n\nInstall [Forme PDF Preview](https://marketplace.visualstudio.com/items?itemName=formepdf.forme-pdf) from the VS Code Marketplace.\n\n- Live PDF preview in a webview panel\n- Component tree in the sidebar with hover-to-highlight\n- Inspector panel with box model, computed styles, and source navigation\n- Click any element on the canvas to select it in the tree and inspector\n\n## Features\n\n- **Page-native layout**: Content flows into pages, not onto an infinite canvas. Page breaks happen at the right place, every time.\n- **React components**: Document, Page, View, Text, Image, Table. If you know React, you know Forme.\n- **Live preview**: `forme dev` shows your PDF updating in real time as you edit.\n- **Click-to-inspect**: Select any element in the browser or VS Code to see its box model, computed styles, and position.\n- **Debug overlays**: Toggle bounding boxes, margins, and page break points.\n- **Fast**: Rust engine compiled to WASM. Renders in milliseconds, not seconds.\n- **OpenType shaping**: Real GSUB/GPOS shaping via rustybuzz. Ligatures (fi, ffi), kerning (AV), and contextual forms render correctly with custom fonts.\n- **Optimal line breaking**: Knuth-Plass algorithm (the same one TeX uses) considers the entire paragraph to minimize awkward spacing. Falls back to greedy when needed.\n- **Hyphenation**: Automatic hyphenation in 35+ languages. Set `hyphens: 'auto'` and a `lang` tag. Uses the hypher crate with language-specific dictionaries.\n- **BiDi text**: Right-to-left text (Arabic, Hebrew) with automatic direction detection. Mixed LTR/RTL paragraphs reorder correctly. Set `direction: 'rtl'` or `direction: 'auto'`.\n- **CSS Grid**: 2D grid layout with `display: 'grid'`. Fixed, fractional (`fr`), and auto track sizing. Explicit placement, auto-placement, column/row spanning, and row-level page breaks.\n- **Flex wrap + align-content**: Flex containers wrap across pages correctly. `align-content` distributes wrapped lines (`center`, `space-between`, `space-around`, `space-evenly`, `flex-end`, `stretch`).\n- **Widow/orphan control**: Text paragraphs never leave a single orphan line at the bottom of a page or a single widow line at the top. Configurable via `minWidowLines` and `minOrphanLines`.\n- **Table overflow**: Table cells with content taller than a page are preserved across page breaks, not silently clipped.\n- **Absolute positioning**: `position: 'absolute'` with `top`, `right`, `bottom`, `left` relative to the parent View.\n- **Column flex**: `justifyContent` and `alignItems` work in both row and column directions.\n- **SVG**: Inline SVG rendering with support for `rect`, `circle`, `ellipse`, `line`, `polyline`, `polygon`, and `path` elements. Supports `opacity`, `fill-opacity`, and `stroke-opacity`. Pass SVG as a `content` string or as JSX children.\n- **QR codes**: Built-in `\u003cQrCode\u003e` component. Vector-based, crisp at any zoom level.\n- **Barcodes**: Built-in `\u003cBarcode\u003e` component. Code 128, Code 39, EAN-13, EAN-8, Codabar. Vector-based.\n- **Text overflow**: `textOverflow: 'ellipsis'` truncates single-line text with \"...\" when it exceeds available width. Also supports `'clip'`.\n- **Builtin Unicode support**: Noto Sans is bundled - Cyrillic, Greek, and other non-Latin scripts work out of the box without registering fonts.\n- **Font fallback chains**: `fontFamily: \"Inter, Helvetica\"` tries each font in order, falling back automatically.\n- **Custom fonts**: TrueType font embedding with automatic subsetting.\n- **Links**: Add `href` to any `\u003cText\u003e`, `\u003cView\u003e`, `\u003cImage\u003e`, or `\u003cSvg\u003e` for clickable PDF links.\n- **Bookmarks**: Add `bookmark` to any element for PDF outline entries. Navigate long documents from the bookmark panel.\n- **Inline text styling**: Nest `\u003cText\u003e` inside `\u003cText\u003e` to bold a word, change colors mid-sentence, or apply strikethrough.\n- **Images**: JPEG, PNG, and WebP with transparency support. `alt` text for accessibility.\n- **CSS shorthands**: `border: \"1px solid #000\"`, `padding: \"8 16\"`, `margin: [20, 40]` — CSS-style shorthand strings and arrays parse automatically.\n- **Visual style properties**: `opacity` cascades to children, `wordSpacing`, `boxShadow`, ubiquitous `borderRadius` (rounded clipping when `overflow: hidden`), and `background` accepting CSS gradient strings — `linear-gradient(135deg, #667eea, #764ba2)`, `radial-gradient(circle, #10b981, #059669)`. Multi-stop gradients supported.\n- **Page backgrounds**: `\u003cPage backgroundImage=\"...\" backgroundSize=\"cover\" backgroundOpacity={0.08} /\u003e` for watermark-style overlays. Sizes: `fill` / `cover` / `contain`.\n- **Document language**: `\u003cDocument lang=\"en-US\"\u003e` sets the PDF `/Lang` tag for accessibility.\n- **Dynamic page numbers**: `{{pageNumber}}` and `{{totalPages}}` in any text element.\n- **Embedded data**: Attach structured JSON to any PDF. Recipients can extract the original data programmatically — invoices carry their line items, reports carry their datasets.\n- **Browser rendering**: Import `@formepdf/core/browser` to generate PDFs entirely client-side. Same engine, same templates — no server required.\n- **Tailwind CSS**: `tw(\"p-4 text-lg font-bold bg-blue-500\")` converts Tailwind classes to Forme style objects. Full color palette, grid, arbitrary values, negative values, fractions.\n- **Fillable forms**: AcroForm components — `\u003cTextField\u003e`, `\u003cCheckbox\u003e`, `\u003cDropdown\u003e`, `\u003cRadioButton\u003e`. Fill and flatten for non-editable delivery.\n- **PDF/UA accessibility**: `\u003cDocument pdfUa\u003e` generates PDF/UA-1 compliant documents with structure tree, tab order, role map, and artifact tagging.\n- **PDF/A archival**: `\u003cDocument pdfa=\"2b\"\u003e` for long-term preservation. Supports PDF/A-2b and PDF/A-2a.\n- **Digital certification**: PKCS#7 certification with X.509 certificates via the `certification` prop or `/v1/certify` API endpoint.\n- **PDF redaction**: True content removal with metadata scrubbing. Text-search, regex, presets, and saved templates.\n- **PDF merging**: Combine 2-20 PDFs into one via `/v1/merge`.\n- **PDF rasterization**: Convert pages to PNG images via `/v1/rasterize`, powered by PDFium.\n\n## Browser Usage\n\nGenerate PDFs in the browser with zero server dependencies:\n\n```tsx\nimport { renderDocument } from '@formepdf/core/browser';\nimport { Document, Page, Text } from '@formepdf/react';\n\nconst pdfBytes = await renderDocument(\n  \u003cDocument\u003e\n    \u003cPage size=\"Letter\" margin={36}\u003e\n      \u003cText style={{ fontSize: 24 }}\u003eGenerated in the browser\u003c/Text\u003e\n    \u003c/Page\u003e\n  \u003c/Document\u003e\n);\n\n// Download, display in an iframe, or upload\nconst blob = new Blob([pdfBytes], { type: 'application/pdf' });\nconst url = URL.createObjectURL(blob);\nwindow.open(url);\n```\n\nWorks with Vite, Next.js, Remix, or any bundler that handles WASM. The only difference from server-side usage is the import path.\n\n## Custom Fonts\n\nRegister TrueType fonts globally or per-document:\n\n```tsx\nimport { Font, Document, Text } from '@formepdf/react';\nimport { renderDocument } from '@formepdf/core';\n\n// Global registration (works like react-pdf)\nFont.register({\n  family: 'Inter',\n  src: './fonts/Inter-Regular.ttf',\n});\n\nFont.register({\n  family: 'Inter',\n  src: './fonts/Inter-Bold.ttf',\n  fontWeight: 'bold',\n});\n\nconst pdf = await renderDocument(\n  \u003cDocument\u003e\n    \u003cText style={{ fontFamily: 'Inter', fontSize: 16 }}\u003e\n      Regular text\n    \u003c/Text\u003e\n    \u003cText style={{ fontFamily: 'Inter', fontSize: 16, fontWeight: 'bold' }}\u003e\n      Bold text\n    \u003c/Text\u003e\n  \u003c/Document\u003e\n);\n```\n\nOr pass fonts directly on the Document:\n\n```tsx\n\u003cDocument fonts={[\n  { family: 'Roboto', src: './fonts/Roboto-Regular.ttf' },\n  { family: 'Roboto', src: './fonts/Roboto-Italic.ttf', fontStyle: 'italic' },\n]}\u003e\n```\n\nFont sources can be file paths, data URIs, or `Uint8Array`. Fonts are automatically subsetted — only glyphs used in the document are embedded.\n\n## Components\n\n| Component | Description |\n|-----------|-------------|\n| `\u003cDocument\u003e` | Root element. `title`, `author`, `lang`, `fonts`, `style`. |\n| `\u003cPage\u003e` | A page. `size`, `margin` (number, string, array, or edges). |\n| `\u003cView\u003e` | Container. Flexbox layout. `href`, `bookmark`. |\n| `\u003cText\u003e` | Text content. Fonts, sizes, colors. `href`, `bookmark`. |\n| `\u003cImage\u003e` | JPEG or PNG. `href`, `alt`. Aspect ratio preserved. |\n| `\u003cTable\u003e` | Table with column definitions. |\n| `\u003cRow\u003e` | Table row. `header` for repeating on page breaks. |\n| `\u003cCell\u003e` | Table cell. `colSpan`, `rowSpan`. |\n| `\u003cSvg\u003e` | Inline SVG graphics. `content` string or JSX children. `href`, `alt`. |\n| `\u003cQrCode\u003e` | QR code. `data`, `size`, `color`. Vector-based. |\n| `\u003cBarcode\u003e` | 1D barcode. `data`, `format`, `width`, `height`, `color`. Code 128, Code 39, EAN-13, EAN-8, Codabar. |\n| `\u003cCanvas\u003e` | Arbitrary vector drawing via `draw` callback. |\n| `\u003cBarChart\u003e` | Bar chart. `data`, `color`, `showGrid`, `showValues`, `title`. |\n| `\u003cLineChart\u003e` | Multi-series line chart. `series`, `labels`, `showPoints`, `showGrid`, `title`. |\n| `\u003cPieChart\u003e` | Pie/donut chart. `data`, `donut`, `showLegend`, `title`. |\n| `\u003cAreaChart\u003e` | Multi-series area chart. `series`, `labels`, `showGrid`, `title`. |\n| `\u003cDotPlot\u003e` | Scatter plot. `groups`, `xLabel`, `yLabel`, `showLegend`, `dotSize`. |\n| `\u003cWatermark\u003e` | Rotated text behind page content. `text`, `fontSize`, `color`, `angle`. |\n| `\u003cTextField\u003e` | Form text input. `name`, `value`, `width`, `multiline`, `password`, `readOnly`. |\n| `\u003cCheckbox\u003e` | Form checkbox. `name`, `checked`. |\n| `\u003cDropdown\u003e` | Form select dropdown. `name`, `options`, `value`, `width`. |\n| `\u003cRadioButton\u003e` | Form radio button. `name`, `value`, `checked`. |\n| `\u003cFixed\u003e` | Repeating header or footer. |\n| `\u003cPageBreak\u003e` | Force a page break. |\n\n## Comparison\n\n| | Forme | react-pdf | Puppeteer |\n|---|---|---|---|\n| Page breaks | Page-native (widow/orphan aware) | Broken for 7 years | CSS `page-break` (fragile) |\n| Table header repetition | Automatic on every page | Not built in | Inconsistent `\u003cthead\u003e` |\n| Line breaking | Knuth-Plass optimal (TeX algorithm) | Greedy | Browser engine |\n| Hyphenation | 35+ languages, automatic | Via callback | Browser engine |\n| Text shaping | OpenType GSUB/GPOS (ligatures, kerning) | Basic | Full browser shaping |\n| BiDi text | RTL, mixed LTR/RTL, auto-detection | No | Full browser BiDi |\n| CSS Grid | `display: 'grid'` with fr/auto/fixed tracks | No | Full CSS Grid |\n| Live preview | Built-in dev server | Render to file | Run script, open file |\n| Click-to-inspect | VS Code, Cursor, WebStorm | No | No |\n| Render speed | ~28ms (4-page report) | ~100-500ms | ~1-5s (Chrome boot) |\n| Memory per render | No browser process (WASM) | ~50-100MB | ~50-200MB |\n| SVG | Basic shapes and paths | Yes | Full browser SVG |\n| Links | `href` prop on Text/View/Image/Svg | `\u003cLink\u003e` component | HTML `\u003ca\u003e` tags |\n| Bookmarks | `bookmark` prop on any element | Yes | No |\n| QR codes | Built-in `\u003cQrCode\u003e` component | No | Via HTML/JS libraries |\n| Barcodes | Built-in `\u003cBarcode\u003e` (5 formats) | No | Via HTML/JS libraries |\n| Charts | Engine-native BarChart, LineChart, PieChart, AreaChart, DotPlot | No | Via HTML/JS libraries |\n| VS Code extension | Native sidebar panels | No | No |\n| Canvas drawing | `\u003cCanvas draw={...}\u003e` for custom vector graphics | No | HTML Canvas (raster) |\n| Watermarks | Built-in `\u003cWatermark\u003e` component | No | Manual positioning |\n| Embedded data | Attach JSON to PDF, extract later | No | No |\n| Text overflow | `textOverflow: 'ellipsis'` | No | CSS `text-overflow` |\n| Font fallback | `fontFamily: \"Inter, Helvetica\"` | Single family only | Full CSS font stack |\n| Custom fonts | TTF with OpenType shaping | Yes | Yes |\n| Browser rendering | Yes (`@formepdf/core/browser`) | Yes (client-side) | No (server only) |\n| Tailwind CSS | `tw(\"p-4 text-lg font-bold\")` utility | No | No |\n| Fillable forms | AcroForm (TextField, Checkbox, Dropdown, Radio) | No | HTML `\u003cform\u003e` (not PDF forms) |\n| PDF/UA accessibility | `\u003cDocument pdfUa\u003e` | No | No |\n| PDF/A archival | `\u003cDocument pdfa=\"2b\"\u003e` | No | No |\n| Digital certification | PKCS#7 via `certification` prop or API | No | No |\n| Redaction | True content removal + metadata scrubbing | No | No |\n| PDF merging | Combine multiple PDFs | No | No |\n| Rasterization | PDF → PNG via PDFium | No | No |\n| Dependencies | None (WASM) | yoga-layout | Chrome/Chromium |\n| Runs in-process | Yes | Yes | No (subprocess) |\n\n## Templates\n\nSee the [templates/](./templates) directory for production-ready examples:\n- Invoice\n- Product Catalog\n- Receipt\n- Report\n- Shipping Label\n- Typography\n- Grid Dashboard\n- Charts Showcase\n- Event Ticket\n\n## Tailwind CSS\n\nStyle Forme components with Tailwind utility classes via `@formepdf/tailwind`:\n\n```bash\nnpm install @formepdf/tailwind\n```\n\n```tsx\nimport { tw } from '@formepdf/tailwind';\n\n\u003cView style={tw(\"flex-row items-center gap-4 p-6 bg-slate-100 rounded-lg\")}\u003e\n  \u003cText style={tw(\"text-2xl font-bold text-slate-900\")}\u003eInvoice\u003c/Text\u003e\n  \u003cText style={tw(\"text-sm text-slate-500\")}\u003eDraft\u003c/Text\u003e\n\u003c/View\u003e\n```\n\nSupports spacing, typography, colors (full Tailwind palette), flexbox, grid, borders, opacity, arbitrary values (`w-[200]`, `bg-[#f00]`), negative values (`-mt-4`), fraction widths (`w-1/2`), and `self-*` alignment.\n\n## Documentation\n\nFull docs at [docs.formepdf.com](https://docs.formepdf.com):\n- [Forms](https://docs.formepdf.com/forms) — fillable AcroForm components\n- [Accessibility](https://docs.formepdf.com/accessibility) — PDF/UA-1 compliance\n- [Archival](https://docs.formepdf.com/archival) — PDF/A compliance\n- [Digital Certification](https://docs.formepdf.com/concepts/digital-certification) — PKCS#7 certification\n\n## Contributing\n\nIssues and PRs welcome.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanmolitor%2Fforme","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdanmolitor%2Fforme","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanmolitor%2Fforme/lists"}