XY Pad

Two-dimensional control surface for mapping and automating X/Y parameters with pointer, wheel, and keyboard input.

"use client";

import { useState } from "react";

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/xypad

Usage

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

BehaviorDetails
Click / drag on padPointer position maps directly to X/Y in bounds.
ClampingValues always clamp to configured axis ranges.
Commit eventonValueCommit fires when drag interaction ends.

Keyboard

Focused XY pad:

KeyAction
ArrowLeft / ArrowRightDecrease / increase X by stepX
ArrowUp / ArrowDownIncrease / decrease Y by stepY
PageUp / PageDownIncrease / decrease Y by stepY × 10
HomeJump to top-left logical corner (x = minX, y = maxY)
EndJump 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

PropTypeDefaultDescription
value{ x: number; y: number }-Controlled value.
defaultValue{ x: number; y: number }{ x: 0, y: 0 }Uncontrolled default value.
minXnumber0Minimum X value.
maxXnumber100Maximum X value.
minYnumber0Minimum Y value.
maxYnumber100Maximum Y value.
stepXnumber1Step increment for X axis.
stepYnumber1Step increment for Y axis.
disabledbooleanfalseWhether 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-labelstring"XY Pad"Accessible name for the interactive surface.
aria-labelledbystring-ID of a labeling element.

Layout and display

PropTypeDefaultDescription
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.
classNamestring-Additional CSS classes.

Additional valid HTML attributes passed to XYPad.Root are forwarded.

Examples

Live value readout

"use client";

import { useState } from "react";

Size variants

sm

import { XYPad } from "@/components/audio/elements/xypad";

export function XYPadSizeSmDemo() {

default

import { XYPad } from "@/components/audio/elements/xypad";

export function XYPadSizeDefaultDemo() {

lg

import { XYPad } from "@/components/audio/elements/xypad";

export function XYPadSizeLgDemo() {

xl

import { XYPad } from "@/components/audio/elements/xypad";

export function XYPadSizeXlDemo() {

Disabled state

import { XYPad } from "@/components/audio/elements/xypad";

export function XYPadDisabledDemo() {

Custom formatted display

"use client";
import { XYPad } from "@/components/audio/elements/xypad";

Hidden value display

"use client";
import { XYPad } from "@/components/audio/elements/xypad";

Bipolar ranges (pan and mix style)

"use client";

import { useState } from "react";

Live value vs committed value callbacks

"use client";

import { useState } from "react";

Channel strip

Filter pad

"use client";

import { useState } from "react";

Reverb pad

"use client";

import { useId, useState } from "react";

More Shadcn XY Pad components

Browse 10 production-ready audio/ui XY Pad 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 10 Shadcn XY Pad components for copy-ready layouts, dashboards, and forms built with Tailwind CSS in the audio/ui library.