Segment Display
segment-displayViewersNot a font. A segment display is 7, 14 or 16 bars in fixed places, and what makes a real one unmistakable is the bars that are off: a cell showing 1 still shows the ghost of 8, dark red on darker glass. A typeface can only draw the lit state, so this draws the geometry — mitred bars generated from a thickness and a gutter, the thinner diagonals real glass has, sheared about the baseline because every module in a rack is italic by a few degrees. Round that sit the three things a photograph of a panel has and a styled div does not: a pane recessed under the bezel's own overhang, a bloom that carries past each lit bar, and light spilling onto the panel in proportion to how much of the display is lit — 88:88 washes the bezel and 1 barely does. A plain value with a window of digits, or several captioned fields behind one piece of glass, the way a multi-tap delay says DELAY / 4X 60MS / L+R instead of opening a menu. Decimal points ride the cell before them, so 120.5 is four digits wide; overflow is truncated from the end the text is not aligned to, so a tempo drops leading digits and keeps the ones that move.
Install
Copies the source into your project. Anything it depends on comes with it.
$ npx shadcn add @syntho-ui/segment-displayPulls 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 { SegmentDisplay } from "@/components/ui/segment-display"
import { themeVars } from "@/lib/theme"
// A tempo readout: seven segments, right-aligned, the point riding a cell.
<SegmentDisplay type="seven" value="128.5" digits={4} align="right" />
// A whole front panel: three captioned windows behind one piece of glass.
<SegmentDisplay
size={30}
fields={[
{ label: "mode", text: "DELAY", digits: 5 },
{ label: "parameter 1", text: "4X 60MS", digits: 7 },
{ label: "parameter 2", text: "L+R", digits: 5 },
]}
/>
// No character generator: a bar graph out of the bars themselves.
<SegmentDisplay masks={levels.map((on) => (on ? 0x00ff : 0x00c0))} digits={8} />
// Another decade's panel — the skin is the whole colour surface.
<SegmentDisplay preset="vfd" value="PROGRAM 07" digits={10} />
// Every display under one wrapper, without touching a component.
// Instance color still wins; anything deeper takes a whole preset object.
<div style={themeVars({ displayInk: "#ff9f1a", displaySpill: "#ff9f1a" })}>
<SegmentDisplay value="PATCH 12" digits={8} />
</div>Props
| Prop | Type | Default | Description |
|---|---|---|---|
| value | string | number | — | The readout. Shown as written — format it first; the display has no opinion about decimal places. |
| digits | number | — | Cells in the window. Omit to fit the value. Text longer than the window is truncated from the end it is not aligned to. |
| align | "left" | "right" | "left" | Which end the text sits at, and therefore which end an overflow eats. Numbers default to right. |
| fields | SegmentField[] | — | Several windows behind one pane, each with a silkscreen caption above it: { label?, text, digits?, align? }. The captions are laid out from the same widths the windows are, so they stay over their own field at any size. |
| masks | number[] | — | Drive the bars directly, one mask per cell, bit 0 being segment A (SEGMENT_NAMES names the bits). Ignores value, and is the counterpart of the dot screen's bitmap: a bar graph out of the middle bars, a rotating busy segment, the annunciators a real panel has. Also available per field. |
| type | "seven" | "fourteen" | "sixteen" | "fourteen" | Seven bars for numbers, fourteen for words, sixteen for the starburst with its split top and bottom bars. |
| preset | DisplayPresetId | DisplayPreset | "led-red" | Panel skin: led-red, led-amber, led-green, led-blue, vfd, plasma, lcd-green, lcd-blue, lcd-grey. A whole preset object re-skins one instance completely. |
| color | string | — | Override the lit colour. The ghosts are derived from it, so they follow — an amber display with red ghosts is a thing no panel has ever done. |
| size | number | 26 | Cell height in pixels. Everything else is proportional to it. |
| weight | number | 0.095 | Bar thickness as a fraction of the cell height. |
| slant | number | 6 | Italic lean in degrees, sheared about the baseline. Zero is upright, which reads as a web page rather than a module. |
| ghost | number | — | How visible the unlit bars are, 0..1. Defaults to the skin's. Zero switches them off, which is exactly what a display does not look like. |
| bloom | number | — | Halo around the lit bars, 0..1. Defaults to the skin's — zero on the reflective ones. |
| spill | number | — | How far light escapes the window onto the panel, 0..1. Scaled by how much of the display is lit. |
| brightness | number | 1 | Overall drive on the lit bars — a dimmed panel, a fade, or an idle state. |
| label | string | — | Silkscreen caption above the whole display. |
| — theme | --uikit-display-ink / --uikit-display-spill | — | Not props: the two CSS custom properties (displayInk / displaySpill via themeVars) that re-skin every display under a wrapper. They resolve in CSS, so nothing re-renders. Precedence is instance color, then these, then the skin; anything beyond the light — glass, bezel, bloom, ghost level — is a whole DisplayPreset object rather than more tokens. |
| frame | boolean | true | Draw the panel around the pane. Off leaves the bare recessed window to drop into your own. |
| blink | boolean | number | false | Blink the lit bars — true for 500 ms, or a period in milliseconds. The ghosts stay put, as they do on hardware. |
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.