EQ Editor
eq-editorControlsThe interactive layer over eq-display, which remains a pure renderer. Drag a handle to move a band in frequency and gain, wheel over it for Q, or tab to it and use the arrows for all three. The band model determines which properties can change, so the same editor supports four peaking bands or a fixed low/mid/high stack. It offers two drawings of the same model: parametric places handles on the curve; bars shows each band's gain as a column at its frequency, with the curve behind it. The columns make the gain settings legible, while the curve shows the combined response. The editor is controlled: bands in, changes out, with no internal copies. Its band model, hit testing and step maths live in a pure core beside it and are pinned in Node.
Install
Copies the source into your project. Anything it depends on comes with it.
$ pnpm dlx shadcn@latest add @pluginui/core-eq-editorPulls in
First time? Add the registry to your components.json once:
{
"registries": {
"@pluginui": "https://pluginui.com/r/{name}.json"
}
}Usage
Connect the documented props to your application or host.
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[] | — | Includes everything in EQBand, plus a label and freqRange / gainRange / qRange. Each range has three states: omitted uses the editor's default; an object pins that axis's bounds and optional step; null locks the axis. A locked handle will not move, and its keys fall through so the page can still scroll. |
| 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. Use it 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 forwarded to the display as it rides the curve. |
| 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.