$npx -y skills add vercel-labs/json-render --skill react-emailReact Email renderer for json-render that turns JSON specs into HTML or plain-text emails using @react-email/components and @react-email/render. Use when working with @json-render/react-email, building transactional or marketing emails from JSON, creating email catalogs, renderin
| 1 | # @json-render/react-email |
| 2 | |
| 3 | React Email renderer that converts JSON specs into HTML or plain-text email output. |
| 4 | |
| 5 | ## Quick Start |
| 6 | |
| 7 | ```typescript |
| 8 | import { renderToHtml } from "@json-render/react-email"; |
| 9 | import { schema, standardComponentDefinitions } from "@json-render/react-email"; |
| 10 | import { defineCatalog } from "@json-render/core"; |
| 11 | |
| 12 | const catalog = defineCatalog(schema, { |
| 13 | components: standardComponentDefinitions, |
| 14 | }); |
| 15 | |
| 16 | const spec = { |
| 17 | root: "html-1", |
| 18 | elements: { |
| 19 | "html-1": { type: "Html", props: { lang: "en", dir: "ltr" }, children: ["head-1", "body-1"] }, |
| 20 | "head-1": { type: "Head", props: {}, children: [] }, |
| 21 | "body-1": { |
| 22 | type: "Body", |
| 23 | props: { style: { backgroundColor: "#f6f9fc" } }, |
| 24 | children: ["container-1"], |
| 25 | }, |
| 26 | "container-1": { |
| 27 | type: "Container", |
| 28 | props: { style: { maxWidth: "600px", margin: "0 auto", padding: "20px" } }, |
| 29 | children: ["heading-1", "text-1"], |
| 30 | }, |
| 31 | "heading-1": { type: "Heading", props: { text: "Welcome" }, children: [] }, |
| 32 | "text-1": { type: "Text", props: { text: "Thanks for signing up." }, children: [] }, |
| 33 | }, |
| 34 | }; |
| 35 | |
| 36 | const html = await renderToHtml(spec); |
| 37 | ``` |
| 38 | |
| 39 | ## Spec Structure (Element Tree) |
| 40 | |
| 41 | Same flat element tree as `@json-render/react`: `root` key plus `elements` map. Root must be `Html`; children of `Html` should be `Head` and `Body`. Use `Container` (e.g. max-width 600px) inside `Body` for client-safe layout. |
| 42 | |
| 43 | ## Creating a Catalog and Registry |
| 44 | |
| 45 | ```typescript |
| 46 | import { defineCatalog } from "@json-render/core"; |
| 47 | import { schema, defineRegistry, renderToHtml } from "@json-render/react-email"; |
| 48 | import { standardComponentDefinitions } from "@json-render/react-email/catalog"; |
| 49 | import { Container, Heading, Text } from "@react-email/components"; |
| 50 | import { z } from "zod"; |
| 51 | |
| 52 | const catalog = defineCatalog(schema, { |
| 53 | components: { |
| 54 | ...standardComponentDefinitions, |
| 55 | Alert: { |
| 56 | props: z.object({ |
| 57 | message: z.string(), |
| 58 | variant: z.enum(["info", "success", "warning"]).nullable(), |
| 59 | }), |
| 60 | slots: [], |
| 61 | description: "A highlighted message block", |
| 62 | }, |
| 63 | }, |
| 64 | actions: {}, |
| 65 | }); |
| 66 | |
| 67 | const { registry } = defineRegistry(catalog, { |
| 68 | components: { |
| 69 | Alert: ({ props }) => ( |
| 70 | <Container style={{ padding: 16, backgroundColor: "#eff6ff", borderRadius: 8 }}> |
| 71 | <Text style={{ margin: 0 }}>{props.message}</Text> |
| 72 | </Container> |
| 73 | ), |
| 74 | }, |
| 75 | }); |
| 76 | |
| 77 | const html = await renderToHtml(spec, { registry }); |
| 78 | ``` |
| 79 | |
| 80 | ## Server-Side Render APIs |
| 81 | |
| 82 | | Function | Purpose | |
| 83 | |----------|---------| |
| 84 | | `renderToHtml(spec, options?)` | Render spec to HTML email string | |
| 85 | | `renderToPlainText(spec, options?)` | Render spec to plain-text email string | |
| 86 | |
| 87 | `RenderOptions`: `registry`, `includeStandard` (default true), `state` (for `$state` / `$cond`). |
| 88 | |
| 89 | ## Visibility and State |
| 90 | |
| 91 | Supports `visible` conditions, `$state`, `$cond`, repeat (`repeat.statePath`), and the same expression syntax as `@json-render/react`. Use `state` in `RenderOptions` when rendering server-side so expressions resolve. |
| 92 | |
| 93 | ## Server-Safe Import |
| 94 | |
| 95 | Import schema and catalog without React or `@react-email/components`: |
| 96 | |
| 97 | ```typescript |
| 98 | import { schema, standardComponentDefinitions } from "@json-render/react-email/server"; |
| 99 | ``` |
| 100 | |
| 101 | ## Key Exports |
| 102 | |
| 103 | | Export | Purpose | |
| 104 | |--------|---------| |
| 105 | | `defineRegistry` | Create type-safe component registry from catalog | |
| 106 | | `Renderer` | Render spec in browser (e.g. preview); use with `JSONUIProvider` for state/actions | |
| 107 | | `createRenderer` | Standalone renderer component with state/actions/validation | |
| 108 | | `renderToHtml` | Server: spec to HTML string | |
| 109 | | `renderToPlainText` | Server: spec to plain-text string | |
| 110 | | `schema` | Email element schema | |
| 111 | | `standardComponents` | Pre-built component implementations | |
| 112 | | `standardComponentDefinitions` | Catalog definitions (Zod props) | |
| 113 | |
| 114 | ## Sub-path Exports |
| 115 | |
| 116 | | Path | Purpose | |
| 117 | |------|---------| |
| 118 | | `@json-render/react-email` | Full package | |
| 119 | | `@json-render/react-email/server` | Schema and catalog only (no React) | |
| 120 | | `@json-render/react-email/catalog` | Standard component definitions and types | |
| 121 | | `@json-render/react-email/render` | Render functions only | |
| 122 | |
| 123 | ## Standard Components |
| 124 | |
| 125 | All components accept a `style` prop (object) for inline styles. Use inline styles for email client compatibility; avoid external CSS. |
| 126 | |
| 127 | ### Document structure |
| 128 | |
| 129 | | Component | Description | |
| 130 | |-----------|-------------| |
| 131 | | `Html` | Root wrapper (lang, dir). Children: Head, Body. | |
| 132 | | `Head` | Email head section. | |
| 133 | | `Body` | Body wrapper; use `style` |