Search Raihin Design System

Search tokens, pages and quick actions

Patterns

Common tasks

Copy these verbatim. They are the canonical solutions to recurring jobs in the system.

Status alerts

The solid pattern: bg + foreground + border. Never bg-{status}/10.

<Alert variant="destructive">
  <XCircleIcon weight="fill" />
  <AlertTitle>Couldn't save changes</AlertTitle>
  <AlertDescription>Check your network connection.</AlertDescription>
</Alert>
Chart colors

Use --color-chart-* in series order. Series 1 anchors to a warm amber that pairs with the brand palette.

const palette = Array.from({ length: 12 }, (_, i) => `var(--color-chart-${i + 1})`);

<Bar dataKey="revenue" fill={palette[0]} />
<Bar dataKey="cost" fill={palette[1]} />
Compact density

Toggle [data-density='compact'] on the html element to tighten controls.

<html data-density="compact">…</html>
Focus state

Use --shadow-focus or the canonical --ring-width composition.

className="focus-visible:ring-(length:--ring-width) focus-visible:ring-ring/40 focus-visible:border-ring"
Form field

text-base on mobile (iOS focus-zoom), helper text, density-aware height.

We'll only use this for login and security alerts.

<div className="flex flex-col gap-(--density-field-gap)">
  <Label htmlFor="email">Work email</Label>
  <Input id="email" type="email" placeholder="you@company.com" />
  <p className="text-xs text-muted-foreground">
    We'll only use this for login and security alerts.
  </p>
</div>
Field with error state

Solid status pattern: bg-destructive/30 helper + border-destructive + aria-invalid.

Enter a valid email address.

<div className="flex flex-col gap-(--density-field-gap)">
  <Label htmlFor="email" className="text-destructive-foreground">Work email</Label>
  <Input
    id="email"
    type="email"
    aria-invalid={true}
    aria-describedby="email-error"
    className="border-destructive focus-visible:border-destructive focus-visible:ring-destructive/40"
  />
  <p id="email-error" className="text-xs text-destructive-foreground">
    Enter a valid email address.
  </p>
</div>

Always pair the visible error with aria-invalid + aria-describedby. Color alone is not sufficient for the error to read as an error to assistive tech.

Multi-field layout

Stack with --density-field-gap. Two-column grids only when fields are short (state, zip).

<form className="flex flex-col gap-(--density-field-gap) max-w-md">
  <div className="grid grid-cols-2 gap-3">
    <div className="flex flex-col gap-1.5">
      <Label htmlFor="first">First name</Label>
      <Input id="first" />
    </div>
    <div className="flex flex-col gap-1.5">
      <Label htmlFor="last">Last name</Label>
      <Input id="last" />
    </div>
  </div>
  <div className="flex flex-col gap-1.5">
    <Label htmlFor="org">Organization</Label>
    <Input id="org" />
  </div>
  <div className="flex justify-end gap-2 pt-2">
    <Button variant="ghost" size="sm">Cancel</Button>
    <Button size="sm">Save changes</Button>
  </div>
</form>
Template card

A visual-first card for browsing design templates. Hero image fades into the card surface, followed by a compact info section and preview link.

TEMPLATE

Pinky Promise

Rosegold

Warm rose-gold gradients with romantic serif typography.

Preview

TEMPLATE

Happy Teal

Evergreen

Calm sage and forest tones with clean sans-serif type.

Preview
<div className="rounded-card overflow-hidden bg-card border border-border-subtle">
  <div
    className="relative aspect-[3/4] flex flex-col items-center justify-center p-6"
    style={{ background: "linear-gradient(180deg, oklch(0.85 0.1 10), oklch(0.32 0.06 320))" }}
  >
    <p className="absolute top-6 text-[10px] tracking-[0.2em] uppercase text-white/70">
      Template
    </p>
    <h3 className="font-display font-bold text-3xl text-white">Pinky Promise</h3>
  </div>
  <div className="p-4 flex flex-col gap-1">
    <h4 className="font-medium text-base">Rosegold</h4>
    <p className="text-xs text-foreground-subtle">
      Warm rose-gold gradients with romantic serif typography.
    </p>
    <a className="mt-2 inline-flex items-center gap-1 text-sm text-foreground hover:underline">
      Preview <ArrowRightIcon className="size-3" />
    </a>
  </div>
</div>

Hero gradient uses inline oklch — these belong to the template, not the design system. Card surface, border, and text use system tokens so the rest of the chrome reskins automatically.

Invitation card

Dashboard card showing an active invitation with live stats, or a draft awaiting completion. Badges indicate plan tier and publish status.

FREELIVE

TEMPLATE NAME

Invitation Title

12 Aug 2026Edited 2 hr ago
129Views
12RSVP
17Guestbook
PREMIUMDRAFT

TEMPLATE NAME

Invitation Title

Not scheduledEdited yesterday
Views
RSVP
Guestbook
EXCLUSIVELIVE

TEMPLATE NAME

Invitation Title

20 Sep 2026Edited 1 hr ago
312Views
45RSVP
28Guestbook
<Card className="overflow-hidden p-0">
  {/* Hero — gradient supplied by the template, not the design system */}
  <div className="relative aspect-[16/10]" style={{ background: heroGradient }}>
    <Badge className="absolute top-3 left-3 bg-tier-free text-tier-free-foreground">
      <FileIcon weight="fill" className="size-3" /> FREE
    </Badge>
    <Badge variant="success" className="absolute top-3 right-3">
      <BroadcastIcon weight="fill" className="size-3" /> LIVE
    </Badge>
  </div>

  {/* Body */}
  <div className="flex flex-col gap-3 p-4">
    <div className="flex flex-col gap-1">
      <p className="text-[10px] tracking-[0.18em] uppercase text-muted-foreground">
        Template name
      </p>
      <h4 className="font-heading text-base font-semibold">Invitation Title</h4>
      <div className="flex items-center gap-2 text-xs text-muted-foreground">
        <CalendarBlankIcon className="size-3.5" />
        <span>12 Aug 2026</span>
        <span aria-hidden>·</span>
        <span>Edited 2 hr ago</span>
      </div>
    </div>

    <Separator className="bg-border-subtle" />

    <div className="grid grid-cols-3 text-center">
      <Stat label="Views" value="129" />
      <Stat label="RSVP" value="12" />
      <Stat label="Guestbook" value="17" />
    </div>

    <Separator className="bg-border-subtle" />

    <div className="flex items-center justify-around -mx-2">
      <ActionButton icon={PencilSimpleIcon}>Edit</ActionButton>
      <ActionButton icon={ShareNetworkIcon}>Share</ActionButton>
    </div>
  </div>
</Card>

Tier badge uses bg-tier-{plan} text-tier-{plan}-foreground. Status badge uses the system status variants (success for live, warning for draft). Stats and actions use foreground tokens so the card never reaches for hardcoded colors outside the hero strip.

Submission states

Loading state on the submit button only. Don't disable the whole form unless it's destructive.

const [pending, setPending] = useTransition();

<Button type="submit" disabled={pending}>
  {pending ? (
    <>
      <SpinnerIcon className="size-(--size-icon-sm) animate-spin" />
      Saving…
    </>
  ) : (
    "Save changes"
  )}
</Button>

Disabled button uses --opacity-disabled automatically via aria-disabled. Don't gray out other fields — the user may still want to edit while the request is in flight.