An approvals section for a payments product: three points down the left, and on the right payouts clearing a policy one barrier at a time. A large payout waits for sign-off, so a visitor can approve or deny it, and one to a bank outside the allowlist is turned away.
registry/blocks/checkpoint-feature.tsx
"use client";
import * as React from "react";
import { Checkpoint, type CheckpointRequest, type CheckpointRule } from "@/components/ui/checkpoint";
/* ── Content ─────────────────────────────────────────────────
* Everything you'd change to make the section yours: the copy,
* the points down the left, and the payouts policy the requests
* on the right have to clear. A rule a request doesn't mention
* passes; "hold" waits for sign-off and "block" turns it away.
* ─────────────────────────────────────────────────────────── */
/** The one accent: the checks, the barriers' token, the primary link. */
const ACCENT = "#ff3b1f";
const ACCENT_DARK = "#ff5a3c";
const EYEBROW = "Approvals";
const HEADLINE = "Payouts wait for the right yes.";
const SUBLINE =
"Write your money-movement policy once. Every payout and refund clears it before it runs, and anything over the line waits for a second approver.";
const POINTS = [
{ title: "Rules in plain words", body: "Amounts, payees, countries and limits, set per team and per environment." },
{ title: "Sign off where you work", body: "Approve or deny from the dashboard, Slack or email, with the reason attached." },
{ title: "Every decision on the record", body: "Who asked, which rule stopped it and who said yes, exported for your auditors." },
];
const CTA = { label: "See the policy builder", href: "#policies" };
const PANEL = { title: "Payouts policy", scope: "Production · 4 rules" };
const APPROVER = "Marta, CFO";
/** ms a held payout waits before the demo approves it. Visitors can approve or deny first. */
const APPROVE_AFTER = 3200;
const RULES: CheckpointRule[] = [
{ id: "payee", label: "Payee", detail: "A verified business", value: "VERIFIED" },
{ id: "amount", label: "Amount", detail: "Over $10,000 needs a second approver", value: "≤ $10K" },
{ id: "country", label: "Bank country", detail: "On your allowlist", value: "ALLOWLIST" },
{ id: "velocity", label: "Velocity", detail: "Three payouts a day per payee", value: "≤ 3 / DAY" },
];
const REQUESTS: CheckpointRequest[] = [
{ id: "po1", label: "payout po_7Kd1", meta: "$2,480.00 to Lindqvist Design AB" },
{ id: "po2", label: "payout po_8Qw3", meta: "$18,600.00 to Harbor Freight Co.", verdicts: { amount: "hold" } },
{
id: "po3",
label: "payout po_2Zc9",
meta: "$940.00 to a new bank account",
verdicts: { country: "block" },
reason: "Bank country isn't on your allowlist",
},
];
/* ── Bits ── */
function Tick({ className }: { className?: string }) {
return (
<svg viewBox="0 0 16 16" className={className} fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
<path d="M3.5 8.5 6.5 11.5 12.5 5" />
</svg>
);
}
function Arrow({ className }: { className?: string }) {
return (
<svg viewBox="0 0 16 16" className={className} fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden>
<path d="M3.5 8h9M8.5 4l4 4-4 4" />
</svg>
);
}
/* ── Section ── */
export function CheckpointFeature() {
return (
<section
style={{ "--accent": ACCENT, "--accent-dark": ACCENT_DARK } as React.CSSProperties}
className="overflow-x-clip bg-white text-zinc-950 dark:bg-zinc-950 dark:text-white"
>
<div className="mx-auto grid max-w-6xl grid-cols-1 items-center gap-12 px-6 py-20 sm:py-24 lg:grid-cols-[minmax(0,26rem)_1fr] lg:gap-16">
<div>
<p className="text-[13px] font-medium text-(--accent) dark:text-(--accent-dark)">{EYEBROW}</p>
<h2 className="mt-2 text-balance text-[2rem] font-medium leading-[1.1] tracking-[-0.035em] sm:text-[2.6rem]">{HEADLINE}</h2>
<p className="mt-4 text-pretty text-[15px] leading-relaxed text-zinc-500 dark:text-zinc-400">{SUBLINE}</p>
<ul className="mt-8 space-y-5">
{POINTS.map((p) => (
<li key={p.title} className="flex gap-3.5">
<span className="mt-0.5 grid size-[18px] shrink-0 place-items-center rounded-[5px] bg-(--accent) text-white dark:bg-(--accent-dark)">
<Tick className="size-3" />
</span>
<span>
<span className="block text-[15px] font-medium tracking-tight">{p.title}</span>
<span className="mt-1 block text-sm leading-relaxed text-zinc-500 dark:text-zinc-400">{p.body}</span>
</span>
</li>
))}
</ul>
<a
href={CTA.href}
className="mt-9 inline-flex items-center gap-1.5 rounded-sm text-sm font-semibold text-(--accent) transition-[gap] duration-150 hover:gap-2.5 focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-(--accent) dark:text-(--accent-dark)"
>
{CTA.label}
<Arrow className="size-4" />
</a>
</div>
<div className="relative">
<div
aria-hidden
className="pointer-events-none absolute -inset-10 bg-[radial-gradient(closest-side,color-mix(in_oklab,var(--accent)_10%,transparent),transparent)]"
/>
<div className="relative rounded-[28px] border border-zinc-950/[0.08] bg-[color-mix(in_oklab,var(--accent)_3%,white)] p-2 shadow-[0_1px_2px_rgba(0,0,0,0.04),0_24px_60px_-30px_rgba(0,0,0,0.18)] dark:border-white/10 dark:bg-zinc-900 dark:shadow-none">
<div className="flex items-center justify-between gap-3 px-4 pb-3 pt-3">
<p className="text-[13px] font-medium tracking-tight">{PANEL.title}</p>
<p className="font-mono text-[11px] text-zinc-500 dark:text-zinc-400">{PANEL.scope}</p>
</div>
<div className="rounded-[22px] border border-zinc-950/[0.06] bg-white p-4 sm:p-5 dark:border-white/[0.06] dark:bg-zinc-950">
<Checkpoint
className="[--checkpoint-accent:var(--accent)] dark:[--checkpoint-accent:var(--accent-dark)]"
rules={RULES}
requests={REQUESTS}
approveAfter={APPROVE_AFTER}
approver={APPROVER}
/>
</div>
</div>
</div>
</div>
</section>
);
}
Live preview and the components it's built with: https://keyframeui.com/blocks/feature-sections/checkpoint-feature