A landing page's theme toggle. Dark mode opens from the button as a domain and takes the page over, with a seam of stars at its edge; press again to draw it back in.
registry/demos/domain-switch-demo.tsx
"use client";
import * as React from "react";
import { cn } from "@/lib/utils";
import { DomainSwitch, DomainSwitchScope, DomainSwitchToggle } from "@/components/ui/domain-switch";
export function DomainSwitchDemo() {
const [dark, setDark] = React.useState(false);
return (
<div className="w-full overflow-hidden rounded-xl border border-zinc-200 dark:border-zinc-800">
<DomainSwitch checked={dark} onCheckedChange={setDark}>
<DomainSwitchScope
className="h-[var(--demo-height,560px)]"
outside={<Landing dark={false} />}
inside={<Landing dark />}
/>
</DomainSwitch>
</div>
);
}
function Landing({ dark }: { dark: boolean }) {
return (
<div
className={cn(
"relative flex h-full flex-col overflow-hidden",
dark ? "bg-[#09090c] text-zinc-100" : "bg-[#fbfbfa] text-zinc-900",
)}
>
{dark && (
<div
aria-hidden
className="pointer-events-none absolute inset-x-0 top-0 h-72 bg-[radial-gradient(60%_100%_at_50%_0%,rgba(129,140,248,0.16),transparent)]"
/>
)}
<nav className="relative flex items-center gap-6 px-5 py-4 sm:px-8">
<span className="flex items-center gap-2 text-sm font-semibold tracking-tight">
<span
className={cn(
"grid size-6 place-items-center rounded-md text-[11px] font-bold",
dark ? "bg-indigo-400 text-[#09090c]" : "bg-zinc-900 text-white",
)}
>
T
</span>
Tidal
</span>
<div className={cn("hidden gap-5 text-sm sm:flex", dark ? "text-zinc-400" : "text-zinc-500")}>
<span>Product</span>
<span>Pricing</span>
<span>Docs</span>
</div>
<div className="ml-auto flex items-center gap-2">
<DomainSwitchToggle
aria-label="Dark mode"
className={cn(
"size-9 rounded-full border",
dark
? "border-white/10 bg-white/5 text-indigo-200 hover:bg-white/10"
: "border-zinc-200 bg-white text-zinc-700 shadow-xs hover:bg-zinc-50",
)}
>
{dark ? <MoonIcon /> : <SunIcon />}
</DomainSwitchToggle>
<a
href="#"
className={cn(
"hidden rounded-full px-4 py-2 text-sm font-medium sm:block",
dark ? "bg-zinc-100 text-zinc-900" : "bg-zinc-900 text-white",
)}
>
Sign in
</a>
</div>
</nav>
<section className="relative mx-auto flex max-w-2xl flex-col items-center px-5 pt-8 text-center sm:pt-12">
<span
className={cn(
"rounded-full border px-3 py-1 text-xs",
dark ? "border-indigo-400/25 bg-indigo-400/10 text-indigo-200" : "border-zinc-200 bg-white text-zinc-600",
)}
>
New: answers in Slack
</span>
<h1 className="mt-5 text-3xl font-semibold tracking-tight text-balance sm:text-5xl/[1.05]">
Analytics that answer back.
</h1>
<p className={cn("mt-4 max-w-md text-sm text-pretty sm:text-base", dark ? "text-zinc-400" : "text-zinc-600")}>
Ask a question in plain words. Tidal writes the query, checks it and draws the chart.
</p>
<div className="mt-6 flex gap-2">
<a
href="#"
className={cn(
"rounded-full px-5 py-2.5 text-sm font-medium",
dark ? "bg-indigo-400 text-[#09090c]" : "bg-zinc-900 text-white",
)}
>
Start free
</a>
<a
href="#"
className={cn(
"rounded-full border px-5 py-2.5 text-sm font-medium",
dark ? "border-white/10 text-zinc-200" : "border-zinc-200 bg-white text-zinc-800",
)}
>
Book a demo
</a>
</div>
</section>
<section className="relative mx-auto mt-10 grid w-full max-w-3xl grid-cols-1 gap-3 px-5 sm:grid-cols-2 sm:px-8">
<Card dark={dark} title="Live queries" body="Weekly signups, by channel">
<svg viewBox="0 0 200 48" className="h-12 w-full" aria-hidden>
<path
d="M0 40 L20 36 L40 38 L60 28 L80 30 L100 20 L120 24 L140 14 L160 16 L180 8 L200 10"
fill="none"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className={dark ? "stroke-indigo-300" : "stroke-zinc-900"}
/>
</svg>
</Card>
<Card dark={dark} title="Shared boards" body="Three people are looking at Q3">
<div className="flex h-12 items-center -space-x-2">
{["bg-amber-300", "bg-sky-300", "bg-rose-300"].map((color) => (
<span
key={color}
className={cn("size-8 rounded-full border-2", color, dark ? "border-[#121217]" : "border-white")}
/>
))}
</div>
</Card>
</section>
</div>
);
}
function Card({
dark,
title,
body,
children,
}: {
dark: boolean;
title: string;
body: string;
children: React.ReactNode;
}) {
return (
<div
className={cn(
"rounded-2xl border p-4",
dark ? "border-white/[0.07] bg-[#121217]" : "border-zinc-200 bg-white shadow-xs",
)}
>
{children}
<p className="mt-3 text-sm font-medium">{title}</p>
<p className={cn("text-xs", dark ? "text-zinc-500" : "text-zinc-500")}>{body}</p>
</div>
);
}
function SunIcon() {
return (
<svg viewBox="0 0 24 24" className="size-4" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
<circle cx="12" cy="12" r="4" />
<path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4" />
</svg>
);
}
function MoonIcon() {
return (
<svg viewBox="0 0 24 24" className="size-4" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M20.5 14.1A8.5 8.5 0 1 1 9.9 3.5a7 7 0 0 0 10.6 10.6Z" />
</svg>
);
}
Live preview, examples and props: https://keyframeui.com/components/domain-switch#domain-switch-demo