{"id":13452065,"url":"https://github.com/schibsted/jsx-pdf","last_synced_at":"2025-04-09T17:25:43.342Z","repository":{"id":38360052,"uuid":"140302507","full_name":"schibsted/jsx-pdf","owner":"schibsted","description":"Generate PDFs using JSX! 🎯","archived":false,"fork":false,"pushed_at":"2023-01-05T14:27:39.000Z","size":1898,"stargazers_count":125,"open_issues_count":7,"forks_count":15,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-03-27T18:08:38.936Z","etag":null,"topics":["jsx","pdf","pdf-generation","pdfmake"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","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/schibsted.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-07-09T15:06:37.000Z","updated_at":"2024-11-13T00:40:14.000Z","dependencies_parsed_at":"2023-02-04T06:00:40.556Z","dependency_job_id":null,"html_url":"https://github.com/schibsted/jsx-pdf","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schibsted%2Fjsx-pdf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schibsted%2Fjsx-pdf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schibsted%2Fjsx-pdf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schibsted%2Fjsx-pdf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/schibsted","download_url":"https://codeload.github.com/schibsted/jsx-pdf/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247648976,"owners_count":20972945,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["jsx","pdf","pdf-generation","pdfmake"],"created_at":"2024-07-31T07:01:11.744Z","updated_at":"2025-04-09T17:25:43.308Z","avatar_url":"https://github.com/schibsted.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"![jsx-pdf logo](https://user-images.githubusercontent.com/11426386/43649419-0819a78a-9735-11e8-8a74-12d26e5e830b.jpg)\n\n[![npm version](https://badge.fury.io/js/jsx-pdf.svg)](https://www.npmjs.com/jsx-pdf) [![Build Status](https://travis-ci.org/schibsted/jsx-pdf.svg?branch=master)](https://travis-ci.org/schibsted/jsx-pdf) [![Coverage Status](https://coveralls.io/repos/github/schibsted/jsx-pdf/badge.svg?branch=master)](https://coveralls.io/github/schibsted/jsx-pdf?branch=master)\n\nGenerate modular PDFs via [pdfmake](http://pdfmake.org/) using JSX.\n\n```jsx\nimport PDFMake from 'pdfmake';\nimport JsxPdf from 'jsx-pdf';\nimport { OpenSans } from './font-descriptors';\n\nconst pdfMake = new PDFMake({\n  OpenSans,\n});\n\nconst stream = pdfMake.createPdfKitDocument(\n  JsxPdf.renderPdf(\n    \u003cdocument defaultStyle={{ font: 'OpenSans', fontSize: 12 }}\u003e\n      \u003ccontent\u003eThis will appear in my PDF!\u003c/content\u003e\n    \u003c/document\u003e,\n  ),\n);\n\n// write the stream to a file; this could also be streamed to an HTTP connection, stdout etc\nstream.on('end', () =\u003e console.log('PDF generated'));\nstream.pipe(fs.createWriteStream('~/Desktop/test.pdf'));\nstream.end();\n```\n\n## Quick start\n\n### Javascript\n\n- `yarn add jsx-pdf @babel/plugin-transform-react-jsx`\n- Configure the part of your build that transpiles your JSX to use `JsxPdf.createElement` as the element factory.\n  - For babel, add the configuration below to your `.babelrc`.\n  ```json\n  \"plugins\": [\n    [\n      \"@babel/plugin-transform-react-jsx\",\n      { \"pragma\": \"JsxPdf.createElement\", \"pragmaFrag\": \"JsxPdf.Fragment\" }\n    ]\n  ]\n  ```\n\n### Typescript\n\n- `yarn add -D @types/jsx-pdf`\n- For TypeScript, add the configuration below to your `tsconfig.json`. Setting `jsx` to `react` configures TypeScript to handle JSX transpiling for you, and the `jsxFactory` option specifies the element factory to use. Setting `jsxFragmentFactory` allows you to use [JSX Fragments](https://reactjs.org/docs/fragments.html#short-syntax).\n\n```json\n\"compilerOptions\": {\n  \"jsx\": \"react\",\n  \"jsxFactory\": \"JsxPdf.createElement\",\n  \"jsxFragmentFactory\": \"JsxPdf.Fragment\",\n},\n```\n\n- Code away! See the examples below.\n\nYou can also run our example script by running `yarn demo` and opening the generated pdf at `example/example.pdf`. Check the console logs for additional information.\n\n## Components\n\nSimilar to modern front-end frameworks, you can define your own components using declarative syntax.\n\n#### Basic example:\n\n```jsx\nimport JsxPdf from 'jsx-pdf';\n\nconst Greeting = ({ name }) =\u003e \u003ctext\u003eHello, {name}!\u003c/text\u003e;\n\nconst doc = (\n  \u003cdocument\u003e\n    \u003ccontent\u003e\n      \u003cGreeting name=\"Bob\" /\u003e\n    \u003c/content\u003e\n  \u003c/document\u003e\n);\n```\n\n#### List example:\n\n```jsx\nimport JsxPdf from 'jsx-pdf';\n\nconst GroupGreeting = ({ names }) =\u003e (\n  \u003c\u003e\n    {names.map((name) =\u003e (\n      \u003cGreeting name={name} /\u003e\n    ))}\n  \u003c/\u003e\n);\n\nconst doc = (\n  \u003cdocument\u003e\n    \u003ccontent\u003e\n      \u003cGroupGreeting names={['Bob', 'Alice']} /\u003e\n    \u003c/content\u003e\n  \u003c/document\u003e\n);\n```\n\n#### Inline If example:\n\n```jsx\nimport JsxPdf from 'jsx-pdf';\n\nconst Signature = () =\u003e \u003ctext\u003eJSX-PDF, Inc.\u003c/text\u003e;\n\nconst SignedGreeting = ({ name }) =\u003e (\n  \u003c\u003e\n    {name \u0026\u0026 \u003cGreeting name={name} /\u003e}\n    \u003cSignature /\u003e\n  \u003c/\u003e\n);\n\nconst doc = (\n  \u003cdocument\u003e\n    \u003ccontent\u003e\n      \u003cSignedGreeting /\u003e\n    \u003c/content\u003e\n  \u003c/document\u003e\n);\n```\n\n#### Inline If-Else example:\n\n```jsx\nimport JsxPdf from 'jsx-pdf';\n\nconst AnonymousGreeting = () =\u003e \u003ctext\u003eWe don't know you.\u003c/text\u003e;\n\nconst SignedGreeting = ({ name }) =\u003e (\n  \u003c\u003e\n    {name ? \u003cGreeting name={name} /\u003e : \u003cAnonymousGreeting /\u003e}\n    \u003cSignature /\u003e\n  \u003c/\u003e\n);\n\nconst doc = (\n  \u003cdocument\u003e\n    \u003ccontent\u003e\n      \u003cSignedGreeting /\u003e\n    \u003c/content\u003e\n  \u003c/document\u003e\n);\n```\n\n#### Element variable example:\n\n```jsx\nimport JsxPdf from 'jsx-pdf';\n\nconst SignedGreeting = ({ name }) =\u003e {\n  let greeting;\n\n  if (name) {\n    greeting = \u003cGreeting name={name} /\u003e;\n  } else {\n    greeting = \u003cAnonymousGreeting /\u003e;\n  }\n\n  return (\n    \u003c\u003e\n      {greeting}\n      \u003cSignature /\u003e\n    \u003c/\u003e\n  );\n};\n\nconst doc = (\n  \u003cdocument\u003e\n    \u003ccontent\u003e\n      \u003cSignedGreeting /\u003e\n    \u003c/content\u003e\n  \u003c/document\u003e\n);\n```\n\n### Styling\n\nStyling can be done by adding appropriate attributes to tags. It's often helpful for readability to group style-related attributes together and use the spread syntax.\n\n```jsx\nimport JsxPdf from 'jsx-pdf';\n\nconst Greeting = ({ name }) =\u003e {\n  const styles = {\n    italics: true,\n    fontSize: 10,\n  };\n\n  return \u003ctext {...styles}\u003eHello, {name}!\u003c/text\u003e;\n};\n\nconst doc = (\n  \u003cdocument\u003e\n    \u003ccontent\u003e\n      \u003cGreeting name=\"Bob\" /\u003e\n    \u003c/content\u003e\n  \u003c/document\u003e\n);\n```\n\n### Context\n\nEach component has access to global context and can update it if necessary.\n\n```jsx\nimport JsxPdf from 'jsx-pdf';\n\nconst AllowedUsersProvider = (attributes, context, updateContext) =\u003e {\n  updateContext({\n    allowedUsers: ['Alice'],\n  });\n\n  return attributes.children[0];\n};\n\nconst SecureGreeting = ({ name }, { allowedUsers }) =\u003e\n  allowedUsers.includes(name) ? (\n    \u003ctext\u003eHello, {name}!\u003c/text\u003e\n  ) : (\n    \u003ctext\u003eYou are not allowed.\u003c/text\u003e\n  );\n\nconst doc = (\n  \u003cAllowedUsersProvider\u003e\n    \u003cdocument\u003e\n      \u003ccontent\u003e\n        \u003cSecureGreeting name=\"Bob\" /\u003e\n      \u003c/content\u003e\n    \u003c/document\u003e\n  \u003c/AllowedUsersProvider\u003e\n);\n```\n\n## Document primitives\n\nThis section describes basic elements provided by the library. More information about supported attributes and advanced examples can be found [here](http://pdfmake.org/playground.html).\n\n### Top elements\n\nEach document has to be enclosed within `document` tag with nested `content`, and optional `header` and `footer`. The document is the place for configuration that affects the whole PDF, such as page margins, page size, default style, and metadata.\n\n```jsx\nimport JsxPdf from 'jsx-pdf';\n\nconst doc = (\n  \u003cdocument\n    pageMargins={[20, 20, 20, 20]}\n    pageSize=\"A4\"\n    defaultStyle={{\n      font: 'OpenSans',\n    }}\n    info={{\n      author: 'Buzz Lightyear',\n    }}\n  \u003e\n    \u003cheader\u003eGreeting\u003c/header\u003e\n    \u003ccontent\u003eHello, Bob!\u003c/content\u003e\n    \u003cfooter\u003eJSX-PDF, Inc.\u003c/footer\u003e\n  \u003c/document\u003e\n);\n```\n\n### Dynamic Header and Footer\n\nIf you want to use the [dynamic header functionality](https://pdfmake.github.io/docs/document-definition-object/headers-footers/) in pdfmake, simply pass a render function as the only child of the header or footer:\n\n```jsx\nconst doc = (\n  \u003cdocument\u003e\n    \u003cheader\u003e\n      {(currentPage, pageCount) =\u003e (\n        \u003ctext\u003e\n          Page {currentPage} of {pageCount}.\n        \u003c/text\u003e\n      )}\n    \u003c/header\u003e\n    \u003ccontent\u003e{/* ... */}\u003c/content\u003e\n  \u003c/document\u003e\n);\n```\n\nThe parameters are:\n\n- `currentPage` - the 1-indexed page for which the content is being rendered\n- `pageCount` - the total number of pages in the document\n- `pageSize` - an object containing information about the dimensions of the page.\n\n### Paragraphs\n\nParagraphs are defined using `text` tag.\n\n\u003c!-- prettier-ignore --\u003e\n```jsx\nimport JsxPdf from 'jsx-pdf';\n\nconst doc = (\n  \u003cdocument\u003e\n    \u003ccontent\u003e\n      \u003ctext\u003e\n        This sentence will be rendered as one paragraph,\n\n        even though there are\n\n        line\n\n\n        breaks.\n      \u003c/text\u003e\n      \u003ctext\u003eThis is another paragraph.\u003c/text\u003e\n    \u003c/content\u003e\n  \u003c/document\u003e\n);\n```\n\nIn order to apply styling to a group of paragraphs, they can be wrapped with a `stack` tag.\n\n```jsx\nimport JsxPdf from 'jsx-pdf';\n\nconst doc = (\n  \u003cdocument\u003e\n    \u003ccontent\u003e\n      \u003cstack color=\"red\"\u003e\n        \u003ctext\u003eFirst red paragraph.\u003c/text\u003e\n        \u003ctext\u003eSecond red paragraph.\u003c/text\u003e\n      \u003c/stack\u003e\n      \u003ctext color=\"blue\"\u003eBlue parahraph.\u003c/text\u003e\n    \u003c/content\u003e\n  \u003c/document\u003e\n);\n```\n\n### Columns\n\nElements nested in `columns` tag will be stacked horizontally.\n\n```jsx\nimport JsxPdf from 'jsx-pdf';\n\nconst doc = (\n  \u003cdocument\u003e\n    \u003ccontent\u003e\n      \u003ccolumns columnGap={10}\u003e\n        \u003ccolumn width={100}\u003eFixed width column\u003c/column\u003e\n        \u003ccolumn width=\"10%\"\u003ePercentage width column\u003c/column\u003e\n        \u003ccolumn width=\"auto\"\u003e\n          Column that adjusts width based on the content\n        \u003c/column\u003e\n        \u003ccolumn width=\"*\"\u003eColumn that fills the remaining space\u003c/column\u003e\n      \u003c/columns\u003e\n    \u003c/content\u003e\n  \u003c/document\u003e\n);\n```\n\n### Lists\n\nBoth ordered and unordered lists are supported.\n\n```jsx\nimport JsxPdf from 'jsx-pdf';\n\nconst docWithOrderedList = (\n  \u003cdocument\u003e\n    \u003ccontent\u003e\n      \u003col reversed start={10} separator={['(', ')']} type=\"lower-roman\"\u003e\n        \u003ctext\u003eItem 1\u003c/text\u003e\n        \u003ctext\u003eItem 2\u003c/text\u003e\n        \u003ctext\u003eItem 3\u003c/text\u003e\n      \u003c/ol\u003e\n    \u003c/content\u003e\n  \u003c/document\u003e\n);\n\nconst docWithUnorderedList = (\n  \u003cdocument\u003e\n    \u003ccontent\u003e\n      \u003cul color=\"blue\" markerColor=\"red\" type=\"square\"\u003e\n        \u003ctext\u003eItem 1\u003c/text\u003e\n        \u003ctext\u003eItem 2\u003c/text\u003e\n        \u003ctext\u003eItem 3\u003c/text\u003e\n      \u003c/ul\u003e\n    \u003c/content\u003e\n  \u003c/document\u003e\n);\n```\n\n### Tables\n\n`table` tag provides a simple way of creating table layouts.\n\n```jsx\nconst leftCellStyle = {\n  color: 'grey',\n};\n\nconst doc = (\n  \u003cdocument\u003e\n    \u003ccontent\u003e\n      \u003ctable widths={[100, '*', 'auto']} headerRows={1} layout=\"headerLineOnly\"\u003e\n        \u003crow\u003e\n          \u003ccell\u003eFixed width column\u003c/cell\u003e\n          \u003ccell\u003eColumn that fills the remaining space\u003c/cell\u003e\n          \u003ccell\u003eColumn that adjusts width based on the content\u003c/cell\u003e\n        \u003c/row\u003e\n        \u003crow\u003e\n          \u003ccell {...leftCellStyle}\u003eCell 1.1\u003c/cell\u003e\n          \u003ccell\u003eCell 1.2\u003c/cell\u003e\n          \u003ccell\u003eCell 1.3\u003c/cell\u003e\n        \u003c/row\u003e\n        \u003crow\u003e\n          \u003ccell {...leftCellStyle}\u003eCell 2.1\u003c/cell\u003e\n          \u003ccell\u003eCell 2.2\u003c/cell\u003e\n          \u003ccell\u003eCell 2.3\u003c/cell\u003e\n        \u003c/row\u003e\n      \u003c/table\u003e\n    \u003c/content\u003e\n  \u003c/document\u003e\n);\n```\n\n### Images\n\n`image` supports JPEG and PNG formats.\n\n```jsx\nimport JsxPdf from 'jsx-pdf';\n\nconst doc = (\n  \u003cdocument\u003e\n    \u003ccontent\u003e\n      \u003cimage src=\"/home/bob/photos/Bob.png\" width={150} height={150} /\u003e\n    \u003c/content\u003e\n  \u003c/document\u003e\n);\n```\n\n### SVGs\n\nThe `svg` tag can be used to render SVG images. The `width`, `height` and `fill` attributes can be used to control the size of the image as described in the [pdfmake docs](https://pdfmake.github.io/docs/document-definition-object/svgs/).\n\n```jsx\nimport JsxPdf from 'jsx-pdf';\n\nconst doc = (\n  \u003cdocument\u003e\n    \u003ccontent\u003e\n      \u003csvg\n        content={`\n          \u003csvg viewBox=\"0 0 100 100\" xmlns=\"http://www.w3.org/2000/svg\"\u003e\n            \u003ccircle fill=\"red\" cx=\"50\" cy=\"50\" r=\"50\"/\u003e\n          \u003c/svg\u003e\n        `}\n      /\u003e\n    \u003c/content\u003e\n  \u003c/document\u003e\n);\n```\n\n### QR Codes\n\nThe `qr` tag can be used to render QR codes. There are various options available as described in the [pdfmake docs](https://pdfmake.github.io/docs/0.1/document-definition-object/qr/).\n\n```jsx\nimport JsxPdf from 'jsx-pdf';\n\nconst doc = (\n  \u003cdocument\u003e\n    \u003ccontent\u003e\n      \u003cqr content=\"My text\" /\u003e\n    \u003c/content\u003e\n  \u003c/document\u003e\n);\n```\n\n## API\n\n### renderPdf\n\nAccepts JSX and returns a PDF JSON representation in the format expected by pdfmake.\n\n### createElement\n\nThis function converts JSX to object representation. Every time JSX syntax is used, the function has to be made available. The functionality depends on the babel plugin `@babel/plugin-transform-react-jsx` (or equivalent), and Babel must be set up in the project in order to transpile the JSX correctly.\n\nExample `.babelrc` file:\n\n```json\n{\n  \"presets\": [\n    [\n      \"@babel/preset-env\",\n      {\n        \"targets\": {\n          \"node\": \"current\"\n        }\n      }\n    ]\n  ],\n  \"plugins\": [\n    [\n      \"@babel/plugin-transform-react-jsx\",\n      { \"pragma\": \"JsxPdf.createElement\", \"pragmaFrag\": \"JsxPdf.Fragment\" }\n    ]\n  ]\n}\n```\n\n## Disclaimer\n\nCopyright 2018 Schibsted\n\nUnless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.\n\n## License\n\nBy contributing to this project, you agree that your contributions will be licensed under its MIT license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fschibsted%2Fjsx-pdf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fschibsted%2Fjsx-pdf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fschibsted%2Fjsx-pdf/lists"}