Skip to content
txbrendan/ui

Status Text

beta

Status as colored text with no background, with an optional quickest fix and a peek behind it.

Preview

tone

GoingMaybeCan’t make itInvitedNo reply

icon

SavedOverdue

fix

Couldn’t saveNo reply

detail

stream

Reply

Install

  1. 1. Add the registry to components.json, once per app. Without it, the shadcn CLI looks up @txbrendan in a public list that txbrendan/ui does not control.

    npx shadcn@latest registry add "@txbrendan=https://txbrendan.dev/r/{name}.json"
  2. 2. Add the theme, once per app. It replaces your color tokens with ones checked for contrast.

    npx shadcn@latest add @txbrendan/theme
  3. 3. Add the component.

    npx shadcn@latest add @txbrendan/status-text

Use it for

  • Drawing a status anywhere: rows, tables, receipts, files, and sync lines. Status is colored text, not a chip.
  • Map your own statuses to a tone, like ok → success, warn → warning, bad → danger, info → brand, muted → neutral, overdue → danger. Overdue shares danger's red, so its word, Overdue, must always show.
  • fix ends the status with its quickest fix as an icon in the same color, named in its tooltip: Couldn't save, then a retry arrow.
  • Give fix a result, like { label: 'Reminded' }. The icon slips to a check and its tooltip says so. With onUndo, coming back shows Undo for 8 seconds, and ⌘Z undoes it too. Send the change in onCommit.
  • Return a promise from onClick, and give the result failed words. The fix waits while it runs, and turns into a red Retry arrow if it fails.
  • detail opens the story behind the status on hover, focus, or tap. Pass PeekCard props, or a node.
  • Set stream when the words change in place, like Reply to Sent, so the new words slip in.

Avoid it for

  • A chip or badge for a status. Use StatusText.
  • An icon for a fix that does not say the action on sight. Leave fix out, and put the action in the row.
  • Color alone. The words must say the status, since color is only a hint.

Props

  • tone

    Color role. neutral is muted.

    "neutral" | "brand" | "danger" | "success" | "warning" · default "neutral"

  • icon

    An icon before the words, in their color.

    ReactNode

  • fix

    The quickest fix: an icon after the words, named by label in its tooltip. The default icon is a turn arrow, for retry.

    { label: string; icon?: ReactNode; onClick?; result?: ActionResult }

  • stream

    When the words change, the new ones slip in. The first words just show.

    boolean · default false

  • detail

    The story behind the status, in a peek on hover, focus, or tap. The words get a dotted underline.

    PeekCardProps | ReactNode

  • children

    The words, like "Going" or "Couldn't save". Required, since tones share colors: Overdue and Couldn't save are both danger red.

    ReactNode

  • className

    Extra classes on the status. Later classes win.

    string

Accessibility

  • The words carry the status, so color is never the only signal.
  • A fix is a 24px button named by its label, which shows in its tooltip. Once pressed, its name follows its state: the result, with "Press to undo." while a press undoes, then the record. A fix that failed is named "Retry:" and what failed.
  • A fix says its result once, through the page's one polite live region, and its tooltip shows it for a moment after the press.
  • With detail, the words are a button that opens the peek, named by its PeekCard title, or else by the words.
  • stream only moves the words. To have a change read out, put role="status" on it.

Examples

Each tone, in words

<StatusText tone="success">Going</StatusText>
<StatusText tone="warning">Maybe</StatusText>
<StatusText>No reply</StatusText>

With its quickest fix

<StatusText tone="danger" fix={{ label: "Retry", onClick: () => save() }}>
  Couldn't save
</StatusText>

With a peek behind it

<StatusText
  tone="danger"
  detail={{
    title: "Overdue",
    facts: [["Due", "Sat 17 Oct · INV-0042"]],
  }}
>
  Overdue
</StatusText>