Status Chip

status-chipViewers

The little LED chip that says what a facility is doing — AUDITION lit, HOST SYNC off, LIVE, no tap from this host. Its reason to exist is that the states worth showing are not a boolean, and the pair that matters most is off versus dim: off means the facility is here and you have not engaged it, so its label stays fully readable and only the lamp goes dark; dim means it is not available in this host at all, so the whole chip recedes. A face that draws "no telemetry from this host" identically to "telemetry switched off" has told the user something false about their session, and that is a bug you cannot see in a screenshot — so the five appearances are a pure table with a test that pins them as mutually distinct. warn sits on the second accent, a different KIND of on rather than a brighter one: engaged, but not in the state you asked for (a fallback source, a value past its budget). live is the only state that animates, because a pulse should mean data is arriving right now and nothing else. The chip is presentational and stateless — the host decides which state is true — and data-status-chip / data-state let a face's render test assert on the state without matching on copy.

AuditionHost syncOutput tapnot measuredSourceInternal (fallback)

Four chips, four different claims. Audition and Host sync toggle between lit and off — the facility is there either way. Output tap is the one that matters: when the host publishes no tap it goes dim, not off, because "this host cannot tell me" is a different statement from "measurement is switched off", and a face that draws them the same has told you something false about your session. Source sits on warn: engaged, but not the source you asked for. Only live pulses.

Install

Copies the source into your project. Anything it depends on comes with it.

$ npx shadcn add @syntho-ui/status-chip

Pulls in

control-theme

First time? Add the registry to your components.json once:

components.json
{
  "registries": {
    "@syntho-ui": "https://engine.syntho.app/r/{name}.json"
  }
}

Usage

Controlled or uncontrolled, whichever suits the surrounding state.

example.tsx
import { StatusChip, StatusChipGroup } from "@/components/ui/status-chip"

<StatusChipGroup>
  <StatusChip label="Audition" state={auditioning ? "lit" : "off"} />
  <StatusChip label="Host sync" state={hostTempo ? "lit" : "off"} detail="128 BPM" />
  {/* Not "off" - this host publishes no tap at all. */}
  <StatusChip
    label="Output tap"
    state={hasTap ? "live" : "dim"}
    title={hasTap ? undefined : "This host publishes no output tap"}
  />
  <StatusChip label="Source" state="warn" detail="Internal (fallback)" />
</StatusChipGroup>

Props

PropTypeDefaultDescription
labelReactNodeThe facility's name. Short — this is a chip, not a sentence.
state"off" | "dim" | "lit" | "warn" | "live"off = present, not engaged (label readable, lamp dark). dim = unavailable in this host (whole chip recedes). lit = engaged. warn = engaged but not as asked, on the second accent. live = engaged and receiving; the only state that pulses.
detailReactNodeA value or qualifier after the label, in muted monospace — a tempo, a resolved source name.
titlestringNative tooltip. The place for the full why behind a dim or warn state.
colorstringOverride the lamp colour for one chip. Otherwise the state picks --uikit-accent, --uikit-accent-2 or the muted text colour.
compactbooleanfalseTighter type and padding, for a crowded bottom rail.
StatusChipGroup{ children, gap?, wrap? }A row of chips on one baseline — flex, a gap, and whether they may wrap. Deliberately trivial; it exists so a status rail is one element with one hook rather than a bare div every face styles differently.

Interaction

  • Drag with pointer capture, so the gesture keeps tracking past the edge of the control.
  • Shift while dragging for a fine pass; release it mid-gesture and coarse tracking resumes.
  • Double-click resets to defaultValue.
  • Arrow keys step normally, Shift+arrow steps finely, PageUp/PageDown jump by ten, Home/End go to the extremes.
  • Proper slider and switch roles with live aria-valuetext, so a screen reader announces the formatted value rather than the raw number.
  • The scroll wheel adjusts the value while the pointer is over the control; stepped ranges move at least one declared step per notch by default.