Two-dimensional control surface for mapping and automating X/Y parameters with pointer, wheel, and keyboard input.
XY pad for simultaneous control of two values (for example filter cutoff/resonance, pan/mix, or macro controls). The registry component wraps XYPad primitives from @audio-ui/react and provides ready-to-use visuals (grid, crosshair, cursor, value display).
Overview
- Interaction model: Pointer drag, wheel nudging, and keyboard nudging over both axes.
- Axes: Independent ranges and steps for X (
minX,maxX,stepX) and Y (minY,maxY,stepY). - Feedback: Grid lines, crosshair, animated cursor, and optional value display overlay.
- Accessibility: Focusable interactive surface with ARIA labeling (
aria-label/aria-labelledby).
Installation
pnpm dlx shadcn@latest add @audio/xypadUsage
import { XYPad } from "@/components/audio/xypad";Uncontrolled - initial value only:
<XYPad
defaultValue={{ x: 0, y: 0 }}
maxX={100}
maxY={1}
minX={-100}
minY={-1}
stepX={1}
stepY={0.01}
/>Controlled - drive value from state:
const [position, setPosition] = useState({ x: 50, y: 50 });
<XYPad
maxX={100}
maxY={100}
minX={0}
minY={0}
onValueChange={setPosition}
onValueCommit={(value) => console.log("Committed:", value)}
value={position}
/>Interaction
Pointer
| Behavior | Details |
|---|---|
| Click / drag on pad | Pointer position maps directly to X/Y in bounds. |
| Clamping | Values always clamp to configured axis ranges. |
| Commit event | onValueCommit fires when drag interaction ends. |
Keyboard
Focused XY pad:
| Key | Action |
|---|---|
ArrowLeft / ArrowRight | Decrease / increase X by stepX |
ArrowUp / ArrowDown | Increase / decrease Y by stepY |
PageUp / PageDown | Increase / decrease Y by stepY × 10 |
Home | Jump to top-left logical corner (x = minX, y = maxY) |
End | Jump to bottom-right logical corner (x = maxX, y = minY) |
Wheel
When focused, wheel deltas nudge both axes according to pad dimensions and axis ranges, then quantize with stepX and stepY.
API reference
XYPad accepts style props (size, formatValue, valueDisplay, className) plus primitive props from XYPadPrimitive.RootProps.
Value and state
| Prop | Type | Default | Description |
|---|---|---|---|
value | { x: number; y: number } | - | Controlled value. |
defaultValue | { x: number; y: number } | { x: 0, y: 0 } | Uncontrolled default value. |
minX | number | 0 | Minimum X value. |
maxX | number | 100 | Maximum X value. |
minY | number | 0 | Minimum Y value. |
maxY | number | 100 | Maximum Y value. |
stepX | number | 1 | Step increment for X axis. |
stepY | number | 1 | Step increment for Y axis. |
disabled | boolean | false | Whether the pad is disabled. |
onValueChange | (value: { x: number; y: number }) => void | - | Callback when value changes during interaction. |
onValueCommit | (value: { x: number; y: number }) => void | - | Callback when value is committed (on release). |
aria-label | string | "XY Pad" | Accessible name for the interactive surface. |
aria-labelledby | string | - | ID of a labeling element. |
Layout and display
| Prop | Type | Default | Description |
|---|---|---|---|
size | "sm" | "default" | "lg" | "xl" | "default" | Size variant (affects height). |
formatValue | (value: { x: number; y: number }) => React.ReactNode | - | Custom formatter for value display. |
valueDisplay | "visible" | "hidden" | "visible" | Controls value display visibility. Use "hidden" to hide overlay. |
className | string | - | Additional CSS classes. |
Additional valid HTML attributes passed to XYPad.Root are forwarded.
Examples
Live value readout
Size variants
sm
default
lg
xl
Disabled state
Custom formatted display
Hidden value display
Bipolar ranges (pan and mix style)
Live value vs committed value callbacks
Channel strip
Filter pad
Reverb pad
Last updated 4/15/2026
On This Page
smdefaultlgxlDisabled stateCustom formatted displayHidden value displayBipolar ranges (pan and mix style)Live value vs committed value callbacksChannel stripFilter padReverb pad