Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,17 @@ For the full API reference, component props, design patterns, and common mistake
| [`@unlayer-internal/shared-elements`](./packages/shared) | Framework-agnostic shared logic | Internal |
| [`@unlayer/elements-demo`](./packages/demo) | Demo application | — |

## Examples

Runnable projects you can clone and experiment with:

| Example | Description |
|---------|-------------|
| [`examples/nextjs-app-router`](./examples/nextjs-app-router) | Next.js 15 App Router — renders an email with `renderToHtml()` in a Server Component, previews it at `/email-preview`, and serves the raw HTML from a Route Handler |

## Development


```bash
# Prerequisites: Node.js (see .nvmrc), pnpm 9+

Expand Down
4 changes: 4 additions & 0 deletions examples/nextjs-app-router/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules/
.next/
package-lock.json
tsconfig.tsbuildinfo
30 changes: 30 additions & 0 deletions examples/nextjs-app-router/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Next.js App Router Example

Renders an Unlayer Elements email to HTML inside a Next.js 15 App Router **Server Component**, then previews it in the browser.

## Run it

From this directory:

```bash
pnpm install
pnpm dev
```

Then open:

- <http://localhost:3000/email-preview> — the email rendered in an interactive preview dashboard (Desktop/Mobile view toggles, Raw HTML / Plain Text view)
- <http://localhost:3000/email-preview/raw> — the raw HTML string, served as `text/html` from a Route Handler

## Architecture

| File | Purpose |
|------|---------|
| `src/emails/welcome-email.tsx` | A realistic transactional email as a plain component tree, parameterized by props |
| `src/app/email-preview/page.tsx` | A Server Component calling `renderToHtml()` and `renderToPlainText()`, passing the strings to the client-side layout |
| `src/app/email-preview/PreviewDashboard.tsx` | Client-side dashboard layout managing viewport resizing, copy to clipboard, and tab switching |
| `src/app/email-preview/raw/route.ts` | A Route Handler returning the rendered HTML — the shape production code usually takes |

### Note on Server Components

The template components and `renderToHtml()` function run completely on the server. The component tree is never shipped to the browser; only the resulting HTML/plain-text strings are.
6 changes: 6 additions & 0 deletions examples/nextjs-app-router/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" />
/// <reference path="./.next/types/routes.d.ts" />

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

const __dirname = dirname(fileURLToPath(import.meta.url));

const nextConfig: NextConfig = {
serverExternalPackages: ["@unlayer/react-elements"],
outputFileTracingRoot: __dirname,
};

export default nextConfig;
23 changes: 23 additions & 0 deletions examples/nextjs-app-router/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "@unlayer/example-nextjs-app-router",
"version": "0.0.0",
"private": true,
"description": "Next.js App Router example rendering an Elements email with renderToHtml()",
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"@unlayer/react-elements": "^0.1.20",
"next": "15.5.22",
"react": "19.1.0",
"react-dom": "19.1.0"
},
"devDependencies": {
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"typescript": "^5"
}
}
Loading