Status Chip
status-chipViewersThe 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.
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-chipPulls in
First time? Add the registry to your components.json once:
{
"registries": {
"@syntho-ui": "https://engine.syntho.app/r/{name}.json"
}
}Usage
Controlled or uncontrolled, whichever suits the surrounding state.
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
| Prop | Type | Default | Description |
|---|---|---|---|
| label | ReactNode | — | The 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. |
| detail | ReactNode | — | A value or qualifier after the label, in muted monospace — a tempo, a resolved source name. |
| title | string | — | Native tooltip. The place for the full why behind a dim or warn state. |
| color | string | — | Override the lamp colour for one chip. Otherwise the state picks --uikit-accent, --uikit-accent-2 or the muted text colour. |
| compact | boolean | false | Tighter 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
sliderandswitchroles with livearia-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.