Glow Button
glow-buttonControlsOne component covers large performance controls and compact vintage console buttons. Round and pill caps use an LED bezel with a layered halo; console-round and console-square use a machined bezel, recessed face and restrained indicator bloom. Every style can be momentary or latching with real button semantics underneath. The glow prop can still be fed from an audio level, and onInteraction fires synchronously inside the first gesture, which makes it the natural place to resume a suspended AudioContext.
Hold the first, latch the second, or use the smaller console faces for vintage hardware panels. Space and Enter work too.
Install
Copies the source into your project. Anything it depends on comes with it.
$ npx shadcn add @syntho-ui/glow-buttonPulls 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 { GlowButton } from "@/components/ui/glow-button"
// The audio-start button: resume the context synchronously inside the
// first gesture — that is the only place browsers allow it.
<GlowButton
mode="toggle"
size={160}
onInteraction={() => audioContext.resume()}
onPressedChange={(on) => (on ? transport.start() : transport.stop())}
>
Play
</GlowButton>
// Side-chain the light to the music: feed the halo an audio level.
const [level, setLevel] = useState(0) // 0..1, from an AnalyserNode loop
<GlowButton mode="toggle" glow={playing ? level : undefined} pulse={{ bpm: 124 }}>
Drop
</GlowButton>Props
| Prop | Type | Default | Description |
|---|---|---|---|
| mode | "momentary" | "toggle" | "momentary" | Lit while held and firing onPress/onRelease, or latching with aria-pressed. |
| pressed | boolean | — | Controlled latched state (toggle mode). Omit for uncontrolled operation. |
| defaultPressed | boolean | false | Initial latched state when uncontrolled (toggle mode). |
| onPressedChange | (pressed: boolean) => void | — | Fires on every latch change (toggle mode), controlled or not. |
| onPress / onRelease | (event) => void | — | Momentary mode: the push landed / ended — including a pointer dragged off the cap. |
| onInteraction | (event) => void | — | Fires once, on the first gesture of any kind, synchronously inside the event — the place to resume a suspended AudioContext. |
| glow | number | — | External halo intensity, 0..1. Takes over the bloom completely — pass an audio level every frame and the light follows the music. Overrides pulse and the lit/idle logic; clamped, so a hot level cannot blow the layers up. |
| pulse | { bpm: number } | — | Make the idle halo hit on the beat. rAF-driven with no re-renders, off by default, and skipped under prefers-reduced-motion. |
| children | ReactNode | — | Text or glyph centred on the cap. Doubles as the accessible name. |
| variant | "round" | "pill" | "console-round" | "console-square" | "round" | Large round or pill performance controls, plus compact round or square machined-console faces. |
| size | number | 140 / 52 | Cap diameter (round/square) or height (pill), in pixels. Console variants default to 52; performance variants default to 140. |
| color | string | — | Halo and LED colour. Defaults to the --uikit-accent token. |
| disabled | boolean | false | Block interaction, kill the glow and dim the control. |
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.