Dual Band Selector
dual-band-selectorControlsThe Logic-style Low Cut / High Cut band bar.
$ pnpm dlx shadcn@latest add @pluginui/core-dual-band-selectorInstall
Copies the source into your project. Anything it depends on comes with it. Run this in your React project with shadcn initialized; no registry configuration is needed.
Pulls in
Install using the registry URL
$ pnpm dlx shadcn@latest add https://pluginui.com/r/core-dual-band-selector.jsonUsage
Connect the documented props to your application or host.
import { DualBandSelector } from "@/components/ui/dual-band-selector"
<DualBandSelector
low={tone.lowCut}
high={tone.highCut}
min={20}
max={20000}
defaultLow={20}
defaultHigh={20000}
onLowChange={(hz) => patch.set({ lowCut: hz })}
onHighChange={(hz) => patch.set({ highCut: hz })}
/>About Dual Band Selector
Two caps share one frequency track, with the band between them lit. This gives a tone section the band view it needs: the bar shows where the band sits and how wide it is, while two knobs would leave you to calculate that. Press the band to move both caps at their current width; press the open track to jump the nearer one; hold Shift for a fine pass. The caps stop against each other at a minimum ratio (log taper) or difference (linear) rather than crossing, so the band can never invert. Each cap is its own slider in the tab order and reports the limit imposed by the other cap as its own aria range.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| low / high | number | — | The two cap values, in engine units. Controlled only: they are engine parameters, and a control that also remembered them would be a second source of truth. A crossed or out-of-range pair is corrected before it is drawn. |
| min / max | number | — | The track's endpoints, 20 and 20000 for an audio-band bar. |
| taper | "log" | "linear" | "log" | How values map onto the track. The log taper is the same mapping every knob in the kit uses, so an octave is an octave anywhere along it. |
| minGap | number | 1.25 (log) / 0 (linear) | How close the caps may come: a high/low ratio on a log track, a difference on a linear one. The moved cap stops there instead of pushing its neighbour along. |
| onLowChange / onHighChange | (value: number) => void | — | One call per cap that actually moved. During a band drag both fire, the leading cap first, so a host that clamps each against the other still accepts both. |
| onChangeStart / onChangeEnd | (handle: "low" | "high") => void | — | Gesture bracket for undo coalescing or a host's beginEdit/endEdit. A band drag brackets both caps; a wheel notch or a key press is its own bracket. |
| formatValue | (value: number) => string | 220 Hz / 6.0 kHz / 20 kHz | Readouts and aria-valuetext, so the two never disagree. |
| lowLabel / highLabel | string | "Low Cut" / "High Cut" | Caption above each cap, and each cap's accessible name. |
| defaultLow / defaultHigh | number | — | Double-click reset target for that cap. Omitted, double-click does nothing. |
| accent | string | — | Colour of the lit band and the caps. Falls back to the control-theme accent, like every other control. |
| size | "sm" | "md" | "lg" | "md" | Groove height, cap size and readout scale. |
| width | number | string | "100%" | Track length. Fills its container by default. |
| onInteraction | (event) => void | — | Fires once, synchronously inside the first gesture. Use it to resume a suspended AudioContext. |
Interaction
- Drag a cap Moves that cap only; it stops against the other at minGap.
- Drag the band Moves both caps, keeping the band's width, and parks at the rail.
- Press the open track Jumps the nearer cap there and carries on into a drag.
- Shift Fine pass, relative and anchored where Shift went down.
- Wheel Steps the cap nearest the pointer; Shift steps finely.
- Arrows / Page / Home / End Step the focused cap by a fraction of the track, ten of those, or run it to its limit.
- Double-click a cap Resets it to defaultLow / defaultHigh.