A rotary control for continuous parameters, with pointer, wheel and keyboard input.
Base UI
import { Knob } from "@/components/audio/elements/knob";
const MARKS = [A rotary control for continuous parameters such as level, cutoff or pan. The registry component wraps the Knob primitive from @audio-ui/react and adds size variants and theme styles.
dragMode="circular", the default), up and down ("vertical"), or by full turns ("revolution"). The mouse wheel and the keyboard also work. A double-click or a double-tap returns to defaultValue.anchor to the value, and a needle that turns with the value. The needle follows the pointer without easing, so it stays in line with the arc.<input type="range"> that takes focus and carries the accessible name (aria-label or aria-labelledby), the value text (formatted with format, or set with getAriaValueText on the primitive's Thumb) and the form value (name).Import the primitive and assemble its parts.
import { Knob } from "@audio-ui/react";
<Knob.Root>
<Knob.Control>
<Knob.Track />
<Knob.Indicator />
<Knob.Thumb />
<Knob.Mark value={50} />
</Knob.Control>
<Knob.Value />
<Knob.Label />
</Knob.Root>import { Knob } from "@/components/audio/knob";Uncontrolled: set only the initial value.
<Knob defaultValue={50} max={100} min={0} step={1} />Controlled: drive the value from state.
const [cutoff, setCutoff] = useState(1000);
<Knob
max={20_000}
min={20}
onValueChange={setCutoff}
step={1}
value={cutoff}
/>Pass defaultValue even when the knob is controlled if you use the double-tap reset: it sets the value the knob returns to, clamped and stepped.
Behavior · 5
min…max.dragMode="vertical": drag up to increase, like a fader; 150px of travel spans min…max.dragMode="revolution": one full 360° turn spans min…max.Shift while dragging, in any mode, to turn four times slower. Only the stretch moved with Shift held is slowed, and small moves add up rather than rounding away.defaultValue, or to the middle of the dial's travel without one. Reports eventDetails.reason === "reset".Values stay within min…max and do not wrap. While dragging, the knob follows the pointer even if a controlled value updates late.
scale sets how the value maps onto the dial's travel. "linear" (the default) suits levels and times; "log" suits frequency, resonance and ratios, which are heard as proportions: on a 20 Hz–20 kHz cutoff, every decade gets the same share of the dial, and 632 Hz sits at the middle. A log scale needs a positive min. For anything else, pass your own { toPosition, toValue }, mapping a value to 0…1 along the travel and back.
<Knob aria-label="Cutoff" max={20_000} min={20} scale="log" />Away from linear, the keys and the wheel move a share of the travel (1%, or 10% with Shift and the Page keys) rather than a step, and always by at least one step.
On the focused knob:
Keys · 6
stepsteplargeStep (default 10)largeStep (default 10)minmaxThe mouse wheel over the knob moves the value by step and reports eventDetails.reason === "wheel".
Groups all parts of the knob and owns its value. Dragging the Control, turning the mouse wheel over it, the keyboard on the Thumb's input, or a double tap (reset) all report through onValueChange / onValueCommitted. Renders a <div> element.
Props · 16
0 on a -1…1 pan knob). Defaults to min.Knob.Value and the input's aria-valuetext.linear, log for frequency, Q or ratios (needs a positive min), or your own { toPosition, toValue }. Away from linear, the keys and the wheel move a share of the travel (1%, or 10% with Shift and Page keys) rather than a step.Data attributes · 2
data-disableddata-draggingThe interactive surface: pointer drags (see dragMode), mouse-wheel stepping, and double tap to reset. Sets touch-action: none so touch drags don't scroll the page. Renders a <div> element.
Data attributes · 2
data-disableddata-draggingThe full sweep of the dial, as an SVG arc. Renders a <svg> element.
Props · 1
Data attributes · 2
data-disableddata-draggingThe arc from anchor to the value, drawn over the Track. Renders a <svg> element.
Data attributes · 2
data-disableddata-draggingRotates with the value (rotate, clockwise from 12 o'clock), so a pointer drawn inside it points at the value. Holds the knob's native <input type="range">, which takes focus, carries the accessible name (aria-label / aria-labelledby) and the form value, and handles the keyboard. Renders a <div> element.
Props · 2
aria-valuetext, e.g. "-6 dB". Defaults to the formatted value.Data attributes · 2
data-disableddata-draggingThe formatted value (format/locale on Root). With editable, a double click, or Enter while it has focus, lets you type a value: Enter commits it (a unit or a decimal comma is fine, and it is clamped), Escape drops it, and it reports reason: "input-change". Renders a <output> element.
Props · 2
Data attributes · 2
data-disableddata-draggingA graduation on the dial at value, placed on the knob's scale: a layer the size of the knob, rotated to where value sits, so a tick drawn at its top lands on the sweep. Its --knob-mark-angle CSS variable is that rotation, to turn a label back upright. It carries data-active while the value has reached it from the anchor. Decorative: the input announces the value. Renders a <div> element.
Props · 1
Data attributes · 3
data-disableddata-draggingdata-activeAccessible label, associated with the thumb's input. Renders a <div> element.
Data attributes · 2
data-disableddata-draggingKnob accepts size and className plus primitive props from KnobPrimitive.Root.Props. aria-label, aria-labelledby, and aria-describedby are forwarded to the knob's input.
Props · 21
PageUp / PageDown and Shift + arrows.0 on a bipolar pan knob.anchor light up.auto while hovered, turned or focused from the keyboard."8.7 kHz".Knob.Value on the primitive).format.eventDetails.reason is "drag", "keyboard", "wheel", "reset", or "input-change"; call eventDetails.cancel() to reject it.@audio-ui/react/knob exposes Knob.Root, Knob.Control (pointer, wheel, reset), Knob.Track and Knob.Indicator (SVG arcs; strokeWidth in the 48×48 viewBox), Knob.Thumb (rotates with the value and holds the input), Knob.Value (formatted <output>), Knob.Mark (a graduation at a value, rotated onto the dial's scale, with data-active once reached), and Knob.Label. Every part accepts a render prop, className / style as functions of state, and exposes data-disabled / data-dragging.
Use anchor to show a reference point on the rail (for example the center of a bipolar control). The arc highlights the interval between anchor and the current value.
Base UI
"use client";
import { Knob } from "@/components/audio/elements/knob";scale="log" spreads a frequency evenly by ratio, so a quarter turn goes from 1 kHz to 8.7 kHz instead of packing the useful range into the first few degrees.
Base UI
"use client";
import { useState } from "react";
import { Knob } from "@/components/audio/elements/knob";Browse 3 production-ready audio/ui Knob components for players, mixers, and synth interfaces. These examples use Base UI primitives from @base-ui/react and stay fully compatible with Shadcn Create so radius, color, and typography match your configured theme.
Browse all 3 Shadcn Knob components for copy-ready layouts, dashboards, and forms built with Tailwind CSS in the audio/ui library.