Skip to content
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
867ea90
Implement React Email Chat example with OpenAI integration
i-subham23 Mar 20, 2026
23d5a59
Enhance React Email Chat example with new components and functionality
i-subham23 Mar 21, 2026
177e930
Remove React Email Chat example and related configurations
i-subham23 Mar 21, 2026
cc3eecd
Refactor and remove React Email Chat package
i-subham23 Mar 21, 2026
cfd75fc
Enhance responsiveness in ChatPage and ComposePage components
i-subham23 Mar 21, 2026
9896cf3
Enhance ChatPage component for improved mobile responsiveness
i-subham23 Mar 21, 2026
bba863c
Add React Email Chat package with initial setup and components
i-subham23 Mar 21, 2026
07df1b2
Implement React Email Chat example with comprehensive features
i-subham23 Mar 22, 2026
bf86f9f
Add TypeScript definitions and update prompt generation in React Emai…
i-subham23 Mar 22, 2026
afe0397
Refactor React Email Chat example by removing unused components and u…
i-subham23 Mar 22, 2026
5ad25b6
Refactor EmailApp component in React Email Chat example for improved …
i-subham23 Mar 23, 2026
61645b3
Refactor imports in library.ts for improved organization
i-subham23 Mar 23, 2026
c872a7f
Update dependencies and clean up React Email Chat example
i-subham23 Mar 23, 2026
81aba7f
Refactor React Email Chat components and update dependencies
i-subham23 Mar 23, 2026
85f4fd8
Enhance React Email Chat functionality and update components
i-subham23 Mar 23, 2026
7ec3c64
Refactor React Email Chat to utilize new email library and clean up code
i-subham23 Mar 23, 2026
9331da7
Add React Email example with new components and features
i-subham23 Mar 23, 2026
8a2f5bf
Update pnpm-lock.yaml to reflect dependency changes and version updates
i-subham23 Mar 23, 2026
57be8b6
Merge remote-tracking branch 'origin' into sd/example/react-email-chat
i-subham23 Mar 23, 2026
016d4e6
Add lucide-react dependency and refactor email components
i-subham23 Mar 24, 2026
c4c9ed0
Remove deprecated render-email.tsx file and update EmailEditor to use…
i-subham23 Mar 24, 2026
fb17209
Refactor email components and update imports for consistency
i-subham23 Mar 24, 2026
36d56b1
Update React Email example documentation and structure
i-subham23 Mar 24, 2026
8115100
Add tsx dependency to React Email example
i-subham23 Mar 24, 2026
1585fcc
Refactor theme handling and streamline email components
i-subham23 Mar 24, 2026
e9dae43
Refactor email component organization and structure
i-subham23 Mar 24, 2026
9e8647f
Enhance React Email package and workflow configuration
i-subham23 Mar 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 121 additions & 0 deletions docs/content/docs/openui-lang/examples/react-email.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
---
title: React Email
description: An AI-powered email generator that uses OpenUI Lang to render 44 React Email components from natural language descriptions.
---

OpenUI Lang isn't limited to chat interfaces — it can power any domain-specific UI generator. This example uses [React Email](https://react.email) components as the rendering target, letting users describe emails in plain English and see them rendered live. The `@openuidev/react-email` package ships 44 email components built with `defineComponent`, a ready-to-use `emailLibrary`, and a system prompt with examples and design rules — so the LLM generates well-structured, email-client-compatible HTML out of the box.

[View source on GitHub →](https://github.com/thesysdev/openui/tree/main/examples/react-email)

<div className="bg-[rgba(0,0,0,0.05)] dark:bg-gray-900 rounded-2xl h-[500px] flex p-2">
<video
src="/videos/react-email.mp4"
noControls
playsInline
muted
preload="metadata"
className="w-full rounded-lg m-auto"
autoPlay
loop
/>
</div>

## Building an email library with OpenUI Lang

Each email component wraps a React Email primitive with inline styles (required by email clients that strip `<style>` tags). Here's a simplified example:

```tsx
const EmailButton = defineComponent({
name: "EmailButton",
props: z.object({
label: z.string(),
href: z.string(),
backgroundColor: z.string().optional(),
}),
description: "Email call-to-action button with link.",
component: ({ props }) => (
<Button
href={props.href as string}
style={{
backgroundColor: (props.backgroundColor as string) ?? "#5F51E8",
color: "#ffffff",
borderRadius: "6px",
padding: "12px 24px",
}}
>
{props.label as string}
</Button>
),
});
```

All 44 components are assembled into `emailLibrary` via `createLibrary`. Consumers import the library and prompt options — individual components are internal:

```tsx
import { emailLibrary, emailPromptOptions } from "@openuidev/react-email";

// Generate the system prompt (includes examples + design rules)
const systemPrompt = emailLibrary.prompt(emailPromptOptions);

// Render streamed OpenUI Lang into email components
<Renderer response={openuiCode} library={emailLibrary} isStreaming={isStreaming} />;
```

Once streaming completes, the `useEmailRendering` hook calls `render()` from `@react-email/render` with `{ pretty: true }` client-side to produce formatted HTML for the "Copy HTML" button.

See [Defining Components](/docs/openui-lang/defining-components) for the full `defineComponent` API.

## Architecture

```
Browser (email editor) -- POST /api/chat --> Next.js route --> OpenAI
<-- SSE stream -- (OpenUI Lang)
```

The client sends a conversation to `/api/chat`. The API route loads a pre-generated `system-prompt.txt` (built from `emailLibrary.prompt(emailPromptOptions)`), forwards messages to the LLM with streaming, and returns SSE events. On the client, `emailLibrary` maps each OpenUI Lang node to a React Email component that renders progressively as tokens arrive.

The key difference from other examples: the output isn't interactive UI — it's static email content. The split-view editor shows a live preview on the right and formatted HTML on the left, with copy buttons for both the HTML and the subject line.

## Project layout

```
examples/react-email/
|- src/app/ # Next.js app (layout, page, API route)
|- src/components/
| |- composePage/ # Landing page with conversation starters
| |- emailEditor/ # Split view (top bar, HTML panel, preview, input)
| |- loadingDots.tsx # Loading animation (shared)
| |- session.ts # Session persistence (shared)
|- src/hooks/ # Theme, clipboard, auto-scroll, email rendering
|- src/generated/ # Auto-generated system prompt

packages/react-email/
|- src/components/ # 44 email components (defineComponent)
|- src/index.ts # Library, groups, examples, rules
|- src/unions.ts # Component type unions
```

## Run the example

Run these commands from `examples/react-email`.

1. Install dependencies:

```bash
cd examples/react-email
pnpm install
```

2. Create a `.env.local` file with your API key:

```bash
OPENAI_API_KEY=sk-...
```

3. Start the dev server:

```bash
pnpm dev
```

This auto-generates the system prompt from the email component library and starts the Next.js dev server.
Binary file added docs/public/videos/react-email.mp4
Binary file not shown.
1 change: 1 addition & 0 deletions examples/react-email/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
OPENAI_API_KEY=sk-your-api-key-here
124 changes: 124 additions & 0 deletions examples/react-email/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# React Email

AI-powered email generator built with [OpenUI](https://openui.com) and [React Email](https://react.email).

Describe an email in natural language, and the AI generates a live preview with exportable HTML. Iterate on the design through follow-up prompts.

## Features

- **44 email components** — headers, footers, feature grids, pricing cards, checkout tables, testimonials, and more
- **Live preview** — see the email render in real time as the AI streams its response
- **Copy HTML** — one-click export of email-client-compatible HTML (pretty-formatted via `@react-email/render`)
- **Copy subject** — grab the generated subject line
- **Conversation starters** — pre-built prompts for common email types (OpenUI launch, abandoned cart, conference invite, travel newsletter)
- **Iterative design** — refine the email through follow-up messages
- **Dark mode** — automatic system theme detection

## Prerequisites

- Node.js 20+
- [pnpm](https://pnpm.io/) (this example lives inside the OpenUI monorepo)
- An [OpenAI API key](https://platform.openai.com/api-keys)

## Getting Started

1. Clone the repo and install dependencies from the monorepo root:

```bash
git clone https://github.com/thesysdev/openui.git
cd openui
pnpm install
```

2. Copy `.env.example` to `.env.local` and add your OpenAI API key:

```bash
cp examples/react-email/.env.example examples/react-email/.env.local
```

Edit `examples/react-email/.env.local`:

```
OPENAI_API_KEY=sk-your-api-key-here
```

3. Start the development server:

```bash
cd examples/react-email
pnpm dev
```

The app will be available at [http://localhost:3000](http://localhost:3000).

## Scripts

| Command | Description |
|---------|-------------|
| `pnpm dev` | Start dev server (auto-generates system prompt) |
| `pnpm build` | Production build |
| `pnpm start` | Start production server |
| `pnpm lint` | Run ESLint |

## Key Dependencies

| Package | Purpose |
|---------|---------|
| `@openuidev/react-email` | 44 email components + system prompt generation |
| `@openuidev/react-lang` | `Renderer` — parses OpenUI Lang and renders components |
| `@openuidev/react-headless` | Chat thread state management |
| `@react-email/components` | Email-compatible HTML primitives |
| `@react-email/render` | Converts React components to email HTML |
| `next` | App framework (Next.js 16) |
| `openai` | OpenAI streaming API client |

## Project Structure

```
src/
app/
page.tsx # Main app — compose + editor views
layout.tsx # Root layout with theme provider
api/chat/route.ts # OpenAI streaming API route
components/
composePage/
index.tsx # Landing page with conversation starters
starters.ts # Conversation starter prompts
emailEditor/
index.tsx # Split view orchestrator
topBar.tsx # Header with title + generating indicator
htmlPanel.tsx # Left panel — HTML code output
previewPanel.tsx # Right panel — live email preview
messageInput.tsx # Bottom input form
mobileTabToggle.tsx # Mobile HTML/Preview tab switcher
loadingDots.tsx # Loading animation (shared)
session.ts # Session persistence (shared)
hooks/
useSystemTheme.tsx # Dark/light theme detection
useIsMobile.ts # Responsive breakpoint hook
useClipboard.ts # Copy-to-clipboard hook
useAutoScroll.ts # Auto-scroll with user override
useEmailRendering.tsx # HTML rendering + streaming lifecycle
generated/
system-prompt.txt # Auto-generated from @openuidev/react-email
```

## How It Works

1. The system prompt is auto-generated at build time from `@openuidev/react-email`'s `emailLibrary` and `emailPromptOptions`
2. User describes an email (or clicks a starter)
3. The AI responds in OpenUI Lang format
4. The `Renderer` from `@openuidev/react-lang` parses and renders the email components in real time using `emailLibrary`
5. Once streaming completes, `useEmailRendering` calls `render()` from `@react-email/render` with `{ pretty: true }` client-side to produce copyable, formatted HTML

## What the package provides

The `@openuidev/react-email` package exports:

- **`emailLibrary`** — ready-to-use library with 44 components (pass to `<Renderer>`)
- **`emailPromptOptions`** — examples + rules for the LLM system prompt
- **`emailComponentGroups`** — organized component groups with usage notes
- **`emailExamples`** — 10 example email templates
- **`emailAdditionalRules`** — 40 email design rules

Individual components are internal to the library — consumers only need `emailLibrary`.
22 changes: 22 additions & 0 deletions examples/react-email/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { defineConfig, globalIgnores } from "eslint/config";
import nextVitals from "eslint-config-next/core-web-vitals";
import nextTs from "eslint-config-next/typescript";

const eslintConfig = defineConfig([
...nextVitals,
...nextTs,
globalIgnores([
".next/**",
"out/**",
"build/**",
"next-env.d.ts",
]),
{
files: ["src/openui/**/*.{ts,tsx}"],
rules: {
"react-hooks/rules-of-hooks": "off",
},
},
]);

export default eslintConfig;
6 changes: 6 additions & 0 deletions examples/react-email/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
import "./.next/dev/types/routes.d.ts";

// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
11 changes: 11 additions & 0 deletions examples/react-email/next.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
transpilePackages: [
"@openuidev/react-headless",
"@openuidev/react-lang",
"@openuidev/react-email",
],
};

export default nextConfig;
36 changes: 36 additions & 0 deletions examples/react-email/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"name": "react-email-example",
"version": "0.1.0",
"private": true,
"scripts": {
"generate:prompt": "node --import tsx -e \"import{emailLibrary,emailPromptOptions}from'@openuidev/react-email';import{writeFileSync,mkdirSync}from'fs';mkdirSync('src/generated',{recursive:true});writeFileSync('src/generated/system-prompt.txt',emailLibrary.prompt(emailPromptOptions));console.log('Prompt generated')\"",
"dev": "pnpm generate:prompt && next dev",
"build": "pnpm generate:prompt && next build",
"start": "next start",
"lint": "eslint"
},
"dependencies": {
"@openuidev/cli": "workspace:*",
"@openuidev/react-email": "workspace:*",
"@openuidev/react-headless": "workspace:*",
"@openuidev/react-lang": "workspace:*",
"@react-email/components": "^0.0.41",
"@react-email/render": "^1.0.6",
"next": "16.1.6",
"openai": "^6.22.0",
"react": "19.2.3",
"lucide-react": "^0.562.0",
"react-dom": "19.2.3"
},
"devDependencies": {
"@tailwindcss/postcss": "^4",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"eslint": "^9",
"eslint-config-next": "16.1.6",
"tailwindcss": "^4",
"tsx": "^4.19.2",
"typescript": "^5"
}
}
7 changes: 7 additions & 0 deletions examples/react-email/postcss.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const config = {
plugins: {
"@tailwindcss/postcss": {},
},
};

export default config;
Loading
Loading