@unlayer/react-elements 0.1.21 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @unlayer/react-elements
2
2
 
3
- React components for building emails, pages, and documents with Unlayer Elements. Full SSR support — works with `renderToHtml`, `renderToString`, Next.js, Remix, and any server-side framework.
3
+ React component library for transactional emails, email templates, landing pages, invoices, reports, documents, and PDFs. Render email-safe HTML, responsive web HTML, and print-ready HTML for PDF from the same React components. Full SSR support — works with `renderToHtml`, `renderToString`, Next.js, Remix, and any server-side framework.
4
4
 
5
5
  ## Installation
6
6
 
@@ -47,6 +47,8 @@ function WelcomeEmail() {
47
47
  }
48
48
  ```
49
49
 
50
+ **Try it in your browser:** the [Elements Playground](https://examples.unlayer.com/examples/elements-playground/) renders Elements code as an email, page, or document with nothing to install, and can open the result in the Unlayer builder.
51
+
50
52
  ## Using with AI agents (Claude, Cursor, etc.)
51
53
 
52
54
  Assembling these templates in code is something AI coding agents do well. The official **`unlayer-elements`** skill teaches them the strict structure, the canonical prop shapes, the image-sizing model, and the patterns that make generated emails actually look good:
@@ -57,6 +59,21 @@ npx skills add unlayer/unlayer-skills
57
59
 
58
60
  This installs the `unlayer-elements` skill (alongside the other Unlayer skills). Your agent then knows how to build emails, pages, and documents with these components and render them via `renderToHtml` / `renderToJson`. See [unlayer/unlayer-skills](https://github.com/unlayer/unlayer-skills).
59
61
 
62
+ Agents can also preview Elements code without installing anything through the [Elements Playground](https://examples.unlayer.com/examples/elements-playground/):
63
+
64
+ - Open `https://examples.unlayer.com/examples/elements-playground/#code=<base64url of the code>` to render a snippet. Add `&mode=email|page|document` to pick the output and `&view=preview` to hide the editor.
65
+ - In browsers with [WebMCP](https://webmachinelearning.github.io/webmcp/), the page registers `render_elements` (code to HTML, design JSON, or plain text) and `show_elements_preview` tools.
66
+
67
+ ## Task guides and runnable examples
68
+
69
+ - [Transactional email in React](https://github.com/unlayer/elements/blob/main/packages/react/docs/transactional-email.md): render HTML and plain text, then send a receipt.
70
+ - [Resend, AWS SES, Postmark, SendGrid, and Nodemailer](https://github.com/unlayer/elements/blob/main/packages/react/docs/email-providers.md): complete provider integrations.
71
+ - [One React template to email, web, and PDF](https://github.com/unlayer/elements/blob/main/packages/react/docs/one-template-email-web-pdf.md): shared invoice content with output-specific roots.
72
+ - [React invoice PDF with Playwright](https://github.com/unlayer/elements/blob/main/packages/react/docs/react-to-pdf.md): generate actual PDF bytes from document HTML.
73
+ - [React to Unlayer visual editing](https://github.com/unlayer/elements/blob/main/packages/react/docs/visual-editing.md): `renderToJson()`, editor loading, export, and supported tree constraints.
74
+
75
+ See [when to choose Elements](https://github.com/unlayer/elements/blob/main/packages/react/docs/README.md) and the [runnable example](https://github.com/unlayer/elements/tree/main/examples/content-workflows).
76
+
60
77
  ## Critical Rules
61
78
 
62
79
  These props have non-obvious shapes that **must** be followed exactly:
@@ -74,6 +91,11 @@ These props have non-obvious shapes that **must** be followed exactly:
74
91
  - **Heading level**: `headingType` (or its alias `level`) accepts `h1`–`h6`.
75
92
  - **children**: Text components accept children as shorthand. `<Heading>Hello</Heading>` sets the heading text. `<Paragraph>` supports children for plain text.
76
93
  - **Paragraph text**: Use `html` prop for text content (supports inline formatting like `<b>`, `<a>`). Use children for plain text.
94
+ - **Text shows as typed**: Heading and Button children and text placed straight in a Row or Column show markup and entities as written, as React shows text (`{"Terms &amp; Conditions"}` shows `&amp;`; in JSX text, `Terms &amp; Conditions` is already `&`). Put markup in Paragraph's `html` prop or an `<Html>` block, and template syntax with `<` or `>` in it (a Liquid `{% if count > 1 %}`) in the `text` prop. An email service's `<%name%>` tag stays as written, for it to fill in. Menu item text shows markup as typed; in an email, an entity (`&rarr;`) and a single quote stay as written, as in 0.1.22, and a double quote is escaped, also in a template tag (the text is also written in an `aria-label`): write a template's string in single quotes (`{{ name | default: 'you' }}`; in Go templates, backticks).
95
+ - **`text` and `html` props are HTML**: Heading's and Button's `text` prop, like Paragraph's `html` and `<Html>`, is written into the email as given (as in 0.1.22). Put only markup you wrote there: a value a user typed (a name, a message) goes in as children, which show it as text.
96
+ - **Link URLs**: `"`, `<` and `>` are percent-encoded, so a URL can't end its attribute. Fill template tags that contain them (a Liquid filter with quotes) in before rendering; a `<%name%>` tag stays as written.
97
+ - **Your own components** render as React renders them: hooks, Context (also from a Provider around the root) and Fragments work. One that's async, suspends or throws is left out with a console message, and the rest renders. Elements renders the template once, and may call a component once more on its own, to take the HTML it puts in a Column or to say why it failed (the whole template once more when it holds markup React rejects), so keep side effects, like creating a coupon code, out of rendering.
98
+ - **Inside your own render**: `renderToHtml`, `renderToJson` and `renderToPlainText` can run while React renders (a preview page's `useMemo`, a client component, Next.js's server render of one). Inside react-dom/server's own `renderToString`, Elements renders with another of react-dom's modules where a synchronous `require` can load one with your React (CommonJS, Jest, an ES module on Node 20.16+ / 22.3+). Where it can't (a bundle with React in it, some test runners' module registries), it renders with the same module, as 0.1.22 did: call it in the component's body, not in `useMemo` and not before another hook (React keeps a render's hooks in that module), or render first and pass the result as a prop. In Next.js's edge runtime, react-dom can't render at all (React there is React Server Components'): render emails in the Node.js runtime.
77
99
 
78
100
  ## Structure: Email/Page/Document > Row > Column > Items
79
101
 
@@ -120,6 +142,7 @@ These props have non-obvious shapes that **must** be followed exactly:
120
142
  | `<Social>` | Social media icons with `icons` shorthand array |
121
143
  | `<Menu>` | Navigation menu with `items` shorthand array |
122
144
  | `<Table>` | Data table with `headers` / `data` shorthands |
145
+ | `<PageBreak>` | Force subsequent document content onto a new PDF page |
123
146
  | `<Video>` | Video embed with `videoUrl` shorthand |
124
147
  | `<Html>` | Custom HTML passthrough |
125
148
 
@@ -133,13 +156,17 @@ Root wrapper for email-safe HTML. Same props as Body (without `mode`).
133
156
  - `fontFamily?: { label: string, value: string }` — `{ label: "Arial", value: "arial,helvetica,sans-serif" }`
134
157
  - `textColor?: string` — `"#000000"`
135
158
  - `linkStyle?: { linkColor, linkHoverColor, linkUnderline, linkHoverUnderline }`
136
- - `previewText?: string` — preview text shown in email client inboxes
159
+ - `previewText?: string` — plain text shown in email client inboxes, escaped for HTML. Pass `"Fish & chips"`, not `"Fish &amp; chips"`; entities supplied in the string display literally.
160
+ - `textDirection?: string` — document direction (`"ltr"` or `"rtl"`), kept in design JSON. When opening the design in the editor, also set its direction with `unlayer.setTextDirection(...)`.
161
+ - `lang?: string` — document language, such as `"ar"`; emitted on `<html>` by `renderToHtml`. Language is document metadata and is not stored in design JSON. Renderer options override both props.
137
162
 
138
163
  ### Page
139
164
  Root wrapper for responsive web display. Same props as Email.
140
165
 
141
166
  ### Document
142
- Root wrapper for print/PDF rendering. Same props as Email.
167
+ Root wrapper for print/PDF rendering. It accepts the shared Body props plus:
168
+ - `documentSize?: "A3" | "A4" | "A5" | "Legal" | "Letter" | "Tabloid"` — `"A4"`
169
+ - `documentOrientation?: "portrait" | "landscape"` — `"portrait"`
143
170
 
144
171
  ### Row
145
172
  Layout container. Must be child of Email/Page/Document/Body.
@@ -221,6 +248,24 @@ Use `html` for formatted text, children for plain text.
221
248
  - `columns?: number` — `3`
222
249
  - `rows?: number` — `3`
223
250
  - `enableHeader?: boolean` — `true`
251
+ - `repeatHeaderOnEachPage?: boolean` — `true`
252
+ - `enableFooter?: boolean` — `false`
253
+ - `repeatFooterOnEachPage?: boolean` — `true`
254
+
255
+ ### PageBreak
256
+ Forces the next block onto a new page in document output. It is inert in email and web output.
257
+
258
+ ```tsx
259
+ <Document>
260
+ <Row>
261
+ <Column>
262
+ <Paragraph>Page one</Paragraph>
263
+ <PageBreak />
264
+ <Paragraph>Page two</Paragraph>
265
+ </Column>
266
+ </Row>
267
+ </Document>
268
+ ```
224
269
 
225
270
  ### Social
226
271
  - `icons?: { name: string, url: string }[]` — shorthand
@@ -499,6 +544,23 @@ const monoFont = { label: "Monospace", value: "'SF Mono', 'Fira Code', 'Roboto M
499
544
 
500
545
  > Note: the CSS-idiom forms that used to be mistakes now work — a string `fontFamily`, a string/number `fontWeight`, a numeric `fontSize`, `padding="0"`, and `<Paragraph text="..." />` are all accepted and normalized. The object/numeric forms above are still recommended for clarity.
501
546
 
547
+ ## Phone settings
548
+
549
+ Rows, columns and content items accept `mobile` settings with the same flat CSS inputs as desktop props. For example:
550
+
551
+ ```tsx
552
+ <Column padding="24px 40px" mobile={{ padding: "16px 20px" }}>
553
+ <Heading fontSize={32} mobile={{ fontSize: 24, lineHeight: "120%", textAlign: "center" }}>Welcome</Heading>
554
+ <Image src={{ url: "https://example.com/photo.png", width: 800 }} width="50%" mobile={{ autoWidth: true }} />
555
+ <Paragraph hideOnMobile>Desktop detail</Paragraph>
556
+ <Paragraph hideOnDesktop>Phone detail</Paragraph>
557
+ </Column>
558
+ ```
559
+
560
+ Supported settings are padding, content `containerPadding`, font size, line height, text alignment and image/button width (`width`, `maxWidth`, `autoWidth`), where the component supports them. Numeric padding and font sizes use pixels; numeric line height is a multiplier. Phone CSS applies at 480px and below, matching the editor. `noStackMobile` still controls column stacking separately.
561
+
562
+ `hideOnMobile` and `hideOnDesktop` work on rows and content, as in the editor; a column can't be hidden on its own (hide its content or its row). `renderToJson` stores these settings in `_override.mobile` and `_override.desktop`, so designs keep them when opened in the visual editor. Image `autoWidth` follows the editor's natural-size cap. Document output keeps its desktop settings.
563
+
502
564
  ## Development
503
565
 
504
566
  ```bash