Lamp
The patch-bay status light, and the only thing in Switchboard that glows. Shows whether a server is patched in, healthy, or carrying a call right now.
Examples
States
Six states, one meaning each. Live and error carry a halo; routed glows once; off is hollow.
<Lamp state="off" label="Off" showLabel />
<Lamp state="idle" label="Idle" showLabel />
<Lamp state="live" label="Live" showLabel />
<Lamp state="routed" label="Routed" showLabel />
<Lamp state="warn" label="Warning" showLabel />
<Lamp state="error" label="Failing" showLabel />What each state means
Pick the state from what an agent would experience, not from the last HTTP status alone.
{states.map(({ state, label, meaning }) => (
<>
<Lamp state={state} label={label} showLabel />
<span>{meaning}</span>
</>
))}In a server list
The label says why, not just the state: "Token expires in 2 days" beats "Warning". On narrow rows hide the label; it is still read out.
GitHub
mcp.github.com
Linear
mcp.linear.app
Sentry
mcp.sentry.dev
Notion
mcp.notion.com
Postgres (staging)
localhost:5433
<Card>
{servers.map((server) => (
<div class="server-row">
<Stack gap="1">
<Text weight="medium">{server.name}</Text>
<Text size="xs" tone="ink-3" mono>{server.host}</Text>
</Stack>
<Lamp state={server.state} label={server.label} showLabel />
</div>
))}
</Card>Dot only
Without showLabel the label is visually hidden but still read. Echo it in a tooltip when the dot sits on a focusable control.
Linear
<Inline gap="2">
<Lamp state="live" label="Linear is live" />
<Text>Linear</Text>
</Inline>
<Tooltip content="Sentry: token expires in 2 days">
<Button variant="ghost" size="sm">
<Lamp state="warn" label="Token expires in 2 days" />
Sentry
</Button>
</Tooltip>Usage
import { Lamp } from '@switchboard/ui'
<Lamp state={server.lamp} label={server.statusText} showLabel />Props
Every component also takes mix, for css() and mixins applied after its own style.
Lamp
| Prop | Type | Default | Description |
|---|---|---|---|
| state* | 'off' | 'idle' | 'live' | 'routed' | 'warn' | 'error' | – | off: not patched in. idle: patched, quiet. live: connected and healthy. routed: a call just went through (one-shot glow). warn: degraded or auth expiring. error: failing. |
| label* | string | – | What the state means for this server. Always rendered; visually hidden unless showLabel. |
| showLabel | boolean | – | Show the label next to the dot (13px, ink-2). |
| align | 'center' | 'text' | 'center' | text: top-align the dot with the first line of a wrapping row (a name cell), using the row’s line height. |
| mix | Mix | – | Extra css() or mixins. |
Also accepts every <span> attribute.
Accessibility
- Colour is never the only signal: `label` is required and is always in the DOM, visually hidden without showLabel. The dot itself is aria-hidden.
- Off is a hollow ring, not just a grey dot, so it differs from idle by shape as well as colour.
- A Lamp is not a live region. When a state change must be announced, also raise a toast or put the row in a role="status" container.
- The routed glow runs once (2s) and is skipped under prefers-reduced-motion.
Guidance
Do
- Use a Lamp for live server and connection state; it is the only element allowed to glow.
- Write the label as the reason: "Token expires in 2 days", "Auth failed".
- Re-render with routed when a call passes through, then fall back to live.
Don’t
- Use a Lamp as decoration, a bullet, or for things that are not live state (use a Badge with dot).
- Invent new colours or make it blink; the six states are the whole vocabulary.
- Put two lamps on one row.