Skip to content
Frontend
Skill

/react-email

React 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,

From plugin
json-render
20k32 skills

Claude Code

$ npx -y skills add vercel-labs/json-render --skill react-email --agent claude-code

SKILL.md

react-email.SKILL.md
name: react-email
description: React 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, rendering AI-generated email specs, or when the user mentions react-email, HTML email, or transactional email.
metadata:
  tags: react-email, email, json-render, html email, transactional email

@json-render/react-email

React Email renderer that converts JSON specs into HTML or plain-text email output.

Quick Start

import { renderToHtml } from "@json-render/react-email";
import { schema, standardComponentDefinitions } from "@json-render/react-email";
import { defineCatalog } from "@json-render/core";

const catalog = defineCatalog(schema, {
  components: standardComponentDefinitions,
});

const spec = {
  root: "html-1",
  elements: {
    "html-1": { type: "Html", props: { lang: "en", dir: "ltr" }, children: ["head-1", "body-1"] },
    "head-1": { type: "Head", props: {}, children: [] },
    "body-1": {
      type: "Body",
      props: { style: { backgroundColor: "#f6f9fc" } },
      children: ["container-1"],
    },
    "container-1": {
      type: "Container",
      props: { style: { maxWidth: "600px", margin: "0 auto", padding: "20px" } },
      children: ["heading-1", "text-1"],
    },
    "heading-1": { type: "Heading", props: { text: "Welcome" }, children: [] },
    "text-1": { type: "Text", props: { text: "Thanks for signing up." }, children: [] },
  },
};

const html = await renderToHtml(spec);

Spec Structure (Element Tree)

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.

Creating a Catalog and Registry

import { defineCatalog } from "@json-render/core";
import { schema, defineRegistry, renderToHtml } from "@json-render/react-email";
import { standardComponentDefinitions } from "@json-render/react-email/catalog";
import { Container, Heading, Text } from "@react-email/components";
import { z } from "zod";

const catalog = defineCatalog(schema, {
  components: {
    ...standardComponentDefinitions,
    Alert: {
      props: z.object({
        message: z.string(),
        variant: z.enum(["info", "success", "warning"]).nullable(),
      }),
      slots: [],
      description: "A highlighted message block",
    },
  },
  actions: {},
});

const { registry } = defineRegistry(catalog, {
  components: {
    Alert: ({ props }) => (
      <Container style={{ padding: 16, backgroundColor: "#eff6ff", borderRadius: 8 }}>
        <Text style={{ margin: 0 }}>{props.message}</Text>
      </Container>
    ),
  },
});

const html = await renderToHtml(spec, { registry });

Server-Side Render APIs

| Function | Purpose | |----------|---------| | `renderToHtml(spec, options?)` | Render spec to HTML email string | | `renderToPlainText(spec, options?)` | Render spec to plain-text email string |

`RenderOptions`: `registry`, `includeStandard` (default true), `state` (for `$state` / `$cond`).

Visibility and State

Supports `visible` conditions, `$state`, `$cond`, repeat (`repeat.statePath`), nested repeat paths with `{ "$item": "field" }`, and the same expression syntax as `@json-render/react`. Use `state` in `RenderOptions` when rendering server-side so expressions resolve.

Server-Safe Import

Import schema and catalog without React or `@react-email/components`:

import { schema, standardComponentDefinitions } from "@json-render/react-email/server";

Key Exports

| Export | Purpose | |--------|---------| | `defineRegistry` | Create type-safe component registry from catalog | | `Renderer` | Render spec in browser (e.g. preview); use with `JSONUIProvider` for state/actions | | `createRenderer` | Standalone renderer component with state/actions/validation | | `renderToHtml` | Server: spec to HTML string | | `renderToPlainText` | Server: spec to plain-text string | | `schema` | Email element schema | | `standardComponents` | Pre-built component implementations | | `standardComponentDefinitions` | Catalog definitions (Zod props) |

Sub-path Exports

| Path | Purpose | |------|---------| | `@json-render/react-email` | Full package | | `@json-render/react-email/server` | Schema and catalog only (no React) | | `@json-render/react-email/catalog` | Standard component definitions and types | | `@json-render/react-email/render` | Render functions only |

Standard Components

All components accept a `style` prop (object) for inline styles. Use inline styles for email client compatibility; avoid external CSS.

Document structure

| Component | Description | |-----------|-------------| | `Html` | Root wrapper (lang, dir). Children: Head, Body. | | `Head` | Email head section. | | `Body` | Body wrapper; use `style` for background. |

Layout

| Component | Description | |-----------|-------------| | `Container` | Constrain width (e.g. max-width 600px). | | `Section` | Group content; table-based for compatibility. | | `Row` | Horizontal row. | | `Column` | Column in a Row; set width via style. |

Content

| Component | Description | |-----------|-------------| | `Heading` | Heading text (as: h1–h6). | | `Text` | Body text. | | `Link` | Hyperlink (text, href). | | `Button` | CTA link styled as button (text, href). | | `Image` | Image from URL (src, alt, width, height). | | `Hr` | Horizontal rule. |

Utility

| Component | Description | |-----------|-------------| | `Preview` | Inbox preview text (inside Html). | | `Markdown` | Markdown content as email-safe HTML. |

Email Best Practices

  • Keep width constrained (e.g. Container max-width 600px).
  • Use inline styles or React Email's style props; many clients strip `<style>` blocks.
  • Pr
Read more
@vercel-labs-2
Ships withjson-render

The Generative UI framework. Generate dynamic, personalized UIs from prompts without sacrificing reliability. Predefined components and actions for safe, predictable output.

Stars on GitHub

Momentum

stars in total
19.6k
Star history of vercel-labs/json-render on GitHub, a chart by star-history.com

Other skills on json-render.

chat

chat

Chat SDK renderer for json-render that turns JSON specs into native chat cards (Block Kit on Slack, Adaptive Cards on Teams, and…

codegen

codegen

Code generation utilities for json-render. Use when generating code from UI specs, building custom code exporters, traversing…

core

core

Core package for defining schemas, catalogs, and AI prompt generation for json-render. Use when working with @json-render/core,…

More skills from other plugins.

next-bundle-optimizer
Auto-invoked

next-bundle-optimizer

Audit and reduce Next.js browser initial-load work. Use for slow route startup, oversized client bundles, duplicate browser…

nextjs4d143k
@vercel@vercelInstall Skill
migrate-radix-to-base

migrate-radix-to-base

Migrates React projects and components from Radix UI to Base UI. Use when asked to migrate from radix, move to base-ui, convert…

ui2w127k
@shadcn-ui@shadcn-uiInstall Skill
chrome-release-cls

chrome-release-cls

Given a Chrome Releases blog post URL (chromereleases.googleblog.com), extract every CVE/bug and find the underlying Gerrit CL…

electron4d124k
@electron@electronInstall Skill
taste-skill
Auto-invoked

taste-skill

tasteskill v2, the anti-slop frontend skill. Art direction for websites, distilled from a study of 247 curated gallery sites (One…

Questions about react-email.

Which coding agents can use react-email?
react-email installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.