Skip to content
Feedback

Alert

A message in the page: what happened, and what to do.

import { Alert } from "@flinbu/seed";

Subtle

The default: a neutral petal with the card hairline. Only the icon carries the tone.

Info: Seed 1.2.0 is out

Focus ring tokens and a pill Tabs variant. See what’s new

Success: cs_204 applied

Figma updates on the next sync.

Warning: 4 text colors fail contrast in Light

They sit below 4.5:1 on bg-primary since yesterday’s sync.

Error: We couldn’t sync to Figma

Figma didn’t respond. Your changes are safe.
import { Alert, Button, Link } from "@flinbu/seed";

<div className="flex w-full max-w-xl flex-col gap-sm">
  <Alert title="Seed 1.2.0 is out">Focus ring tokens and a pill Tabs variant. <Link href="#">See what’s new</Link></Alert>
  <Alert variant="success" title="cs_204 applied">Figma updates on the next sync.</Alert>
  <Alert variant="warning" title="4 text colors fail contrast in Light" action={<Button size="sm" variant="secondary">Fix them</Button>}>
    They sit below 4.5:1 on bg-primary since yesterday’s sync.
  </Alert>
  <Alert variant="error" title="We couldn’t sync to Figma" onDismiss={() => {}}>Figma didn’t respond. Your changes are safe.</Alert>
</div>

Loud

The same surface with a hairline in the tone, for the few alerts that must stand out.

Info: Seed 2.0 needs a migration

Token names change on March 3. Read the guide

Success: Your system is healthy again

All 446 tokens pass AA in Light and Dark.

Warning: You’re out of credits

Pluto pauses until the 1st, or until you add more.

Error: Sync to Figma failed

Figma didn’t respond three times in a row. Your changes are safe here.
import { Alert, Button, Link } from "@flinbu/seed";

<div className="flex w-full max-w-xl flex-col gap-sm">
  <Alert emphasis="loud" title="Seed 2.0 needs a migration">Token names change on March 3. <Link href="#">Read the guide</Link></Alert>
  <Alert emphasis="loud" variant="success" title="Your system is healthy again">All 446 tokens pass AA in Light and Dark.</Alert>
  <Alert emphasis="loud" variant="warning" title="You’re out of credits" action={<Button size="sm" variant="secondary">Add credits</Button>}>
    Pluto pauses until the 1st, or until you add more.
  </Alert>
  <Alert emphasis="loud" variant="error" title="Sync to Figma failed" action={<Button size="sm" variant="secondary">Try again</Button>}>
    Figma didn’t respond three times in a row. Your changes are safe here.
  </Alert>
</div>

Light and Dark

Both modes and all four tones in each theme.

Light

Info: Subtle info

Only the icon is in color. A link

Success: Subtle success

Only the icon is in color. A link

Warning: Subtle warning

Only the icon is in color. A link

Error: Subtle error

Only the icon is in color. A link

Info: Loud info

The hairline takes the tone.

Success: Loud success

The hairline takes the tone.

Warning: Loud warning

The hairline takes the tone.

Error: Loud error

The hairline takes the tone.
Dark

Info: Subtle info

Only the icon is in color. A link

Success: Subtle success

Only the icon is in color. A link

Warning: Subtle warning

Only the icon is in color. A link

Error: Subtle error

Only the icon is in color. A link

Info: Loud info

The hairline takes the tone.

Success: Loud success

The hairline takes the tone.

Warning: Loud warning

The hairline takes the tone.

Error: Loud error

The hairline takes the tone.
import { Alert, Link } from "@flinbu/seed";

<div className="grid w-full gap-base md:grid-cols-2">
  {(["light", "dark"] as const).map((theme) => (
    <div key={theme} data-theme={theme} className="flex flex-col gap-sm rounded-xl border border-secondary bg-primary p-base">
      <span className="mono-label-medium text-tertiary">{theme === "light" ? "Light" : "Dark"}</span>
      {(["info", "success", "warning", "error"] as const).map((v) => <Alert key={v} variant={v} title={`Subtle ${v}`}>Only the icon is in color. <Link href="#">A link</Link></Alert>)}
      {(["info", "success", "warning", "error"] as const).map((v) => <Alert key={v} variant={v} emphasis="loud" title={`Loud ${v}`}>The hairline takes the tone.</Alert>)}
    </div>
  ))}
</div>

Appears after an action

live announces it: role alert for this error, role status for the other tones.

import { Alert, Button } from "@flinbu/seed";

const [failed, setFailed] = React.useState(false);

<div className="flex w-full max-w-xl flex-col items-start gap-sm">
  <Button variant="secondary" onClick={() => setFailed(true)}>Sync to Figma</Button>
  {failed ? (
    <Alert live emphasis="loud" variant="error" title="Sync to Figma failed" onDismiss={() => setFailed(false)} className="w-full">
      Figma didn’t respond. Your changes are safe here.
    </Alert>
  ) : null}
</div>

Use it for

  • Errors and warnings about the page, success after an action, information people need now.
  • Subtle, the default, for almost every alert. Loud only when one must stand out: a health drop, no credits left, a failed sync, an error that blocks the work.

Use something else for

  • Messages that should disappear on their own: use a toast.
  • Several loud alerts on one screen: if everything is loud, nothing is.

Props

PropTypeDefaultDescription
variant'neutral''info''success''warning''error''offer''info'Meaning and icon.
emphasis'subtle''loud''subtle'subtle: only the icon is in color. loud: the hairline takes the tone (border-{tone}-subtle).
titleReactNode–One line.
iconIconPropfalse–Replace or hide the variant's icon.
actionReactNode–One or two small Buttons.
onDismiss() => void–Shows a close button.
liveboolean–Set when the alert appears after the page loads, so it's announced.
toneLabelstringfalse–The hidden word read before the message. Default Info, Success, Warning or Error; none for neutral and offer.
classNamestring–Extra classes. They win over Seed's, so you can adjust one thing without forking.

Accessibility

  • An alert rendered with the page has no live role. Set live when it appears later (after an action, a sync, a failed request): it becomes role status, or role alert for errors only.
  • A visually hidden Info:, Success:, Warning: or Error: is read before the message, so the tone never depends on color. Translate it with toneLabel.
  • Icons hold 3:1 on bg-primary in both themes (5.0 to 8.3:1 in Light, 6.4 to 12.7:1 in Dark). Links use text-accent-primary (5.2:1 Light, 9.9:1 Dark).
  • The loud hairline is decorative (1.4 to 1.9:1 in Light, 2.1 to 2.6:1 in Dark): the icon, the hidden prefix and the words carry the meaning.
  • The close button is labelled Dismiss (change it with dismissLabel).