EQ Editor
eq-editorControlsThe interactive layer over eq-display, which stays a pure renderer. Drag a handle to move a band in frequency and gain, wheel over it for Q, tab to it and use the arrows for all three — and because what a band will let you change is a property of the band, an editor over four peaking bands and one over a fixed low/mid/high stack are the same component with different inputs. Two drawings of the identical model: parametric puts handles on the curve, bars stands each band as a column at its own frequency with the curve still behind it, which makes the set of gains legible where the curve makes the result legible. Controlled — bands in, changes out, no internal copies — with the band model, hit testing and step maths in a pure core beside it and pinned in Node.
Drag a handle for frequency and gain, wheel over one for Q, or tab to it and use the arrows — Alt+Left/Right (or [ and ]) for Q, Shift for a fine pass. In bars mode the columns stand at their own frequencies, so the curve behind them is the curve they make.
Install
Copies the source into your project. Anything it depends on comes with it.
$ npx shadcn add @syntho-ui/eq-editorPulls 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 { EQEditor } from "@/components/ui/eq-editor"
const [bands, setBands] = useState([
{ type: "lowshelf", freq: 90, gain: 4, q: 0.7, label: "Low" },
{ type: "peaking", freq: 1200, gain: -3, q: 1.4, label: "Mid" },
// A derived centre frequency locks its axis: the handle moves in gain only.
{ type: "highshelf", freq: 8000, gain: 5, q: 0.7, label: "Air", freqRange: null },
])
<EQEditor mode="parametric" bands={bands} onBandsChange={setBands} />Props
| Prop | Type | Default | Description |
|---|---|---|---|
| bands | EQEditorBand[] | — | Everything EQBand carries, plus a label and freqRange / gainRange / qRange. Each range is three-valued: omitted takes the editor's default, an object pins that axis's bounds (and an optional step), and null locks the axis — the handle will not move on it and its keys fall through so the page still scrolls. |
| onBandsChange | (bands: EQEditorBand[]) => void | — | The whole next array, for a consumer that holds one. |
| onBandChange | (index, patch, band) => void | — | One band's change, for a consumer whose bands are separate parameters. Fires alongside onBandsChange, so neither consumer has to reconstruct what the other wanted. |
| onChangeEnd | () => void | — | Fires once when a drag ends — the moment to commit an undo entry. |
| mode | "parametric" | "bars" | "parametric" | Which drawing the same bands get. Switching modes changes nothing about the bands; in bars mode a column keeps its place on the frequency axis, so a drag is vertical only. |
| defaults | { freq?, gain?, q? } | — | Ranges for any axis a band does not pin itself. Defaults to 20–20 kHz, ±18 dB and Q 0.1–18. |
| minFrequency / maxFrequency | number | 20 / 20000 | The frequency axis bounds, drawn logarithmically. Forwarded to the display. |
| decibelRange | number | 18 | Vertical range, in dB either side of flat. |
| showBands / showGrid / fill | boolean | — | Forwarded to the underlying EQDisplay. showBands defaults on in parametric mode. |
| showLabels | boolean | true | Draw each band's label under its handle or column. |
| showGuides | boolean | — | Vertical guide through each band's frequency. On in parametric mode, off in bars mode where the column is the guide. |
| cursor | EQCursor | null | — | A modulation cursor riding the curve — forwarded to the display. |
| color | string | — | Override the accent for this instance, curve included. |
| height | number | 200 | Plot height in pixels; width defaults to 100%. |
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.