An email API's relays with a switch each. Pause relays and the mail moves on to whichever is still up.
registry/demos/reroute-email-demo.tsx
"use client";
import * as React from "react";
import { Reroute, type RerouteItem } from "@/components/ui/reroute";
function Mark({ children }: { children: React.ReactNode }) {
return (
<svg viewBox="0 0 24 24" className="size-full" aria-hidden>
{children}
</svg>
);
}
// Postwick, a transactional email API, sends through four relays. Flip one off and mail reroutes.
const RELAYS: (RerouteItem & { short: string })[] = [
{
id: "pelican",
short: "Pelican",
name: "Pelican Mail",
detail: "99.2% inboxed · 1.1s",
icon: (
<Mark>
<rect x="3" y="5" width="18" height="14" rx="3.5" fill="#0ea5e9" />
<path d="M6.5 9l5.5 4 5.5-4" fill="none" stroke="#fff" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" />
</Mark>
),
},
{
id: "courier",
short: "Courier",
name: "Courier One",
detail: "98.7% inboxed · 0.9s",
icon: (
<Mark>
<path d="M3.5 11.5 20.5 4l-5 16-3.6-6.2z" fill="#f97316" />
<path d="M11.9 13.8 20.5 4" stroke="#fff" strokeWidth="1.5" strokeLinecap="round" />
</Mark>
),
},
{
id: "harbor",
short: "Harbor",
name: "Harbor SMTP",
detail: "99.0% inboxed · 1.4s",
icon: (
<Mark>
<circle cx="12" cy="12" r="9" fill="#4f46e5" />
<path d="M12 6.5v10M8 12.5a4 4 0 0 0 8 0M9.5 8.5h5" fill="none" stroke="#fff" strokeWidth="1.8" strokeLinecap="round" />
</Mark>
),
},
{
id: "beacon",
short: "Beacon",
name: "Beacon Relay",
detail: "98.9% inboxed · 1.2s",
icon: (
<Mark>
<rect x="4" y="4" width="16" height="16" rx="5" fill="#16a34a" />
<circle cx="12" cy="12" r="2.4" fill="#fff" />
<path d="M7.8 7.8a6 6 0 0 0 0 8.4M16.2 7.8a6 6 0 0 1 0 8.4" fill="none" stroke="#bbf7d0" strokeWidth="1.6" strokeLinecap="round" />
</Mark>
),
},
];
export function RerouteEmailDemo() {
const [down, setDown] = React.useState<string[]>(["courier"]);
const [live, setLive] = React.useState<string | null>("pelican");
const [sent, setSent] = React.useState(18204);
// Mail keeps going out while any relay is up.
React.useEffect(() => {
if (!live) return;
const id = window.setInterval(() => setSent((n) => n + 1 + Math.floor(Math.random() * 3)), 420);
return () => window.clearInterval(id);
}, [live]);
const toggle = (id: string) => setDown((d) => (d.includes(id) ? d.filter((x) => x !== id) : [...d, id]));
return (
<div className="w-full max-w-xl overflow-hidden rounded-3xl border border-zinc-950/[0.08] bg-white shadow-[0_1px_2px_rgba(0,0,0,0.04)] dark:border-white/10 dark:bg-zinc-950">
<div className="flex items-end justify-between gap-4 px-6 pt-6">
<div className="min-w-0">
<h3 className="text-[15px] font-semibold tracking-tight text-zinc-950 dark:text-white">Delivery relays</h3>
<p className="mt-0.5 text-xs text-zinc-500 dark:text-zinc-400">Pause a relay and mail moves to the next one.</p>
</div>
<div className="shrink-0 text-right">
<p className="font-mono text-lg font-medium leading-6 tabular-nums tracking-tight text-zinc-950 dark:text-white">
{sent.toLocaleString("en-US")}
</p>
<p className="text-[11px] text-zinc-500 dark:text-zinc-400">sent today</p>
</div>
</div>
<Reroute
className="[--reroute-accent:#00a86b] [--reroute-down:#ef4444] dark:[--reroute-accent:#1fd18f] dark:[--reroute-down:#f87171]"
label="Email relay"
items={RELAYS}
defaultValue="pelican"
down={down}
onRoute={(id) => setLive(id)}
hub={
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
<rect x="3.5" y="5.5" width="17" height="13" rx="2.5" />
<path d="M4 7l8 6 8-6" />
</svg>
}
/>
<ul className="grid grid-cols-1 gap-px border-t border-zinc-950/[0.06] bg-zinc-950/[0.06] sm:grid-cols-2 dark:border-white/[0.08] dark:bg-white/[0.08]">
{RELAYS.map((r) => {
const off = down.includes(r.id);
return (
<li key={r.id} className="flex items-center gap-3 bg-white px-5 py-3 dark:bg-zinc-950">
<span className="size-5 shrink-0">{r.icon}</span>
<span className="min-w-0 flex-1">
<span className="block truncate text-[13px] font-medium tracking-tight text-zinc-950 dark:text-white">{r.short}</span>
<span className="block text-[11px] text-zinc-500 dark:text-zinc-400">
{off ? "Paused" : r.id === live ? "Sending" : "Standing by"}
</span>
</span>
<button
type="button"
role="switch"
aria-checked={!off}
aria-label={`${r.short} relay`}
onClick={() => toggle(r.id)}
className="relative h-6 w-10 shrink-0 rounded-full outline-offset-2 outline-[#00a86b] transition-colors duration-200 focus-visible:outline-2 aria-checked:bg-[#00a86b] aria-[checked=false]:bg-zinc-200 dark:aria-checked:bg-[#1fd18f] dark:aria-[checked=false]:bg-zinc-700"
>
<span
className="absolute left-0.5 top-0.5 size-5 rounded-full bg-white shadow-sm transition-transform duration-200 ease-[cubic-bezier(0.23,1,0.32,1)]"
style={{ transform: off ? "translateX(0)" : "translateX(16px)" }}
/>
</button>
</li>
);
})}
</ul>
</div>
);
}
Live preview, examples and props: https://keyframeui.com/components/reroute#reroute-email-demo