Slider

A linear slider component for continuous value adjustment with support for both horizontal and vertical orientations.

The Slider component provides a linear control for continuous value adjustment. It shares the same layout, parameter model, interaction, and accessibility as other vector components; see the Vector introduction.

  • Multiple visual variants: abstract, trackless, trackfull, stripless
  • Flexible orientation: horizontal and vertical layouts
  • Extensive cursor customization: image-based cursors, custom styling, aspect ratio control
  • Full theming support: color, roundness, thickness customization

Props

NameTypeDefaultRequiredDescription
valuenumber—RequiredCurrent value of the control
onChange(event: AudioControlEvent<number>) => void—OptionalHandler for value changes
minnumber—OptionalMinimum value (ad-hoc mode)
maxnumber—OptionalMaximum value (ad-hoc mode)
stepnumber1OptionalStep size for value adjustments
bipolarbooleanfalseOptionalWhether the component should operate in bipolar mode (centered at zero)
labelstring—OptionalLabel displayed below the component
variant"abstract" | "trackless" | "trackfull" | "stripless"abstractOptionalVisual variant of the slider
orientation"horizontal" | "vertical"verticalOptionalOrientation of the slider
thicknessnumber0.5OptionalThickness of the slider (normalized 0.0-1.0, maps to 1-50)
valueAsLabel"labelOnly" | "valueOnly" | "interactive"labelOnlyOptionalControls how the label and value are displayed
cursorSize"None" | "Strip" | "Track" | "Tick" | "Label"—OptionalCursor size option - determines which component's width is used for the cursor
cursorAspectRationumber—OptionalAspect ratio of the cursor
cursorRoundnessnumber | string—OptionalOverrides the roundness factor of the cursor. Defaults to `roundness`
cursorImageHrefstring—OptionalOptional image URL to display as cursor
cursorClassNamestring—OptionalOptional CSS class name for the cursor
cursorStyleReact.CSSProperties—OptionalOptional inline styles for the cursor
colorstring—OptionalComponent primary color - any valid CSS color value
roundnessnumber—OptionalRoundness for component corners (normalized 0.0-1.0)
adaptiveSizebooleanfalseOptionalWhether the component stretches to fill its container
size"xsmall" | "small" | "normal" | "large" | "xlarge"normalOptionalSize of the component
parameterContinuousParameter—OptionalAudio Parameter definition (Model). If provided, overrides min/max/step/label/bipolar from ad-hoc props
valueFormatter(value: number, parameterDef: AudioParameter) => string | undefined—OptionalCustom renderer for the value display
interactionMode"drag" | "wheel" | "both"bothOptionalInteraction mode
interactionSensitivitynumber—OptionalSensitivity of the control (normalized value change per pixel/unit)
interactionDirectionInteractionDirection—OptionalDirection of the interaction

Basic Usage

The Slider component requires a value and onChange handler. By default, sliders are vertical:

import { useState } from "react";
import { Slider } from "@cutoff/audio-ui-react";
 
export default function BasicSlider() {
  const [value, setValue] = useState(50);
 
  return (
    <div className="h-48">
      <Slider
        value={value}
        onChange={(e) => setValue(e.value)}
        min={0}
        max={100}
        size="large"
        label="Volume"
      />
    </div>
  );
}
 

Orientation

Sliders can be oriented horizontally or vertically:

Vertical Slider

The default orientation, suitable for fader-style controls:

import { useState } from "react";
import { Slider } from "@cutoff/audio-ui-react";
 
export default function VerticalSlider() {
  const [value, setValue] = useState(0.7);
 
  return (
    <div className="h-48">
      <Slider
        value={value}
        onChange={(e) => setValue(e.value)}
        orientation="vertical"
        label="Volume"
        min={0}
        max={1}
        size="large"
      />
    </div>
  );
}
 

Horizontal Slider

Useful for pan controls and other horizontal adjustments:

import { useState } from "react";
import { Slider } from "@cutoff/audio-ui-react";
 
export default function HorizontalSlider() {
  const [value, setValue] = useState(0);
 
  return (
    <div className="w-full">
      <Slider
        value={value}
        onChange={(e) => setValue(e.value)}
        orientation="horizontal"
        label="Pan"
        min={-100}
        max={100}
        bipolar={true}
        size="large"
      />
    </div>
  );
}
 

Variants

The Slider component supports four visual variants:

Abstract

The default variant with a clean, minimal design:

import { useState } from "react";
import { Slider } from "@cutoff/audio-ui-react";
 
export default function AbstractVariant() {
  const [value, setValue] = useState(0.5);
 
  return (
    <div className="h-48">
      <Slider
        value={value}
        onChange={(e) => setValue(e.value)}
        variant="abstract"
        label="Volume"
        size="large"
      />
    </div>
  );
}
 

Trackless

A variant without a visible track:

import { useState } from "react";
import { Slider } from "@cutoff/audio-ui-react";
 
export default function TracklessVariant() {
  const [value, setValue] = useState(0.5);
 
  return (
    <div className="h-48">
      <Slider
        value={value}
        onChange={(e) => setValue(e.value)}
        variant="trackless"
        label="Gain"
        size="large"
      />
    </div>
  );
}
 

Trackfull

A variant with a full track visible:

import { useState } from "react";
import { Slider } from "@cutoff/audio-ui-react";
 
export default function TrackfullVariant() {
  const [value, setValue] = useState(0.5);
 
  return (
    <div className="h-48">
      <Slider
        value={value}
        onChange={(e) => setValue(e.value)}
        variant="trackfull"
        label="Cutoff"
        size="large"
      />
    </div>
  );
}
 

Stripless

A variant without a value strip:

import { useState } from "react";
import { Slider } from "@cutoff/audio-ui-react";
 
export default function StriplessVariant() {
  const [value, setValue] = useState(0.5);
 
  return (
    <div className="h-48">
      <Slider
        value={value}
        onChange={(e) => setValue(e.value)}
        variant="stripless"
        label="Resonance"
        size="large"
      />
    </div>
  );
}
 

Cursor Customization

The Slider component provides extensive options for customizing the cursor appearance:

Cursor Size

The cursorSize prop determines which component's width is used for the cursor:

import { useState } from "react";
import { Slider } from "@cutoff/audio-ui-react";
 
export default function CursorSizeExample() {
  const [v1, setV1] = useState(0.5);
  const [v2, setV2] = useState(0.5);
 
  return (
    <div className="flex gap-8 h-48">
      <Slider
        value={v1}
        onChange={(e) => setV1(e.value)}
        cursorSize="Strip"
        size="large"
        label="Strip Cursor"
      />
      <Slider
        value={v2}
        onChange={(e) => setV2(e.value)}
        cursorSize="Track"
        size="large"
        label="Track Cursor"
      />
    </div>
  );
}
 

Cursor Aspect Ratio

Control the aspect ratio of the cursor:

import { useState } from "react";
import { Slider } from "@cutoff/audio-ui-react";
 
export default function CursorAspectRatio() {
  const [v1, setV1] = useState(0.5);
  const [v2, setV2] = useState(0.5);
 
  return (
    <div className="flex gap-8 h-48">
      <Slider
        value={v1}
        onChange={(e) => setV1(e.value)}
        cursorAspectRatio={1.0}
        size="large"
        label="Square Cursor"
      />
      <Slider
        value={v2}
        onChange={(e) => setV2(e.value)}
        cursorAspectRatio={2.0}
        size="large"
        label="Tall Cursor"
      />
    </div>
  );
}
 

Cursor Roundness

Override the roundness of the cursor independently from the slider:

import { useState } from "react";
import { Slider } from "@cutoff/audio-ui-react";
 
export default function CursorRoundness() {
  const [v1, setV1] = useState(0.5);
  const [v2, setV2] = useState(0.5);
 
  return (
    <div className="flex gap-8 h-48">
      <Slider
        value={v1}
        onChange={(e) => setV1(e.value)}
        cursorRoundness={0.0}
        size="large"
        label="Square Cursor"
      />
      <Slider
        value={v2}
        onChange={(e) => setV2(e.value)}
        cursorRoundness={1.0}
        size="large"
        label="Fully Rounded"
      />
    </div>
  );
}
 

Custom Cursor Image

Use a custom image for the cursor:

import { useState } from "react";
import { Slider } from "@cutoff/audio-ui-react";
 
export default function CursorImage() {
  const [value, setValue] = useState(0.5);
 
  return (
    <div className="h-48">
      <Slider
        value={value}
        onChange={(e) => setValue(e.value)}
        cursorImageHref="/images/documentation/svg-primitives-radial-light.png"
        size="large"
        label="Custom Cursor"
      />
    </div>
  );
}
 

Cursor Styling

Apply custom CSS classes or inline styles to the cursor:

import { useState } from "react";
import { Slider } from "@cutoff/audio-ui-react";
 
export default function CursorStyling() {
  const [value, setValue] = useState(0.5);
 
  return (
    <div className="h-48">
      <Slider
        value={value}
        onChange={(e) => setValue(e.value)}
        cursorClassName="custom-cursor"
        cursorStyle={{ border: "2px solid #3b82f6" }}
        size="large"
        label="Styled Cursor"
      />
    </div>
  );
}
 

Theming

Vector components share common theming features; see Theming Features in the Vector introduction for an overview. The Slider component supports theming through the color and roundness props:

Color Customization

import { useState } from "react";
import { Slider } from "@cutoff/audio-ui-react";
 
export default function SliderColor() {
  const [v1, setV1] = useState(0.5);
  const [v2, setV2] = useState(0.5);
 
  return (
    <div className="flex gap-8 h-48">
      <Slider
        value={v1}
        onChange={(e) => setV1(e.value)}
        color="#3b82f6"
        size="large"
        label="Blue Slider"
      />
      <Slider
        value={v2}
        onChange={(e) => setV2(e.value)}
        color="#ef4444"
        size="large"
        label="Red Slider"
      />
    </div>
  );
}
 

Roundness

Control the roundness of the slider track and cursor:

import { useState } from "react";
import { Slider } from "@cutoff/audio-ui-react";
 
export default function SliderRoundness() {
  const [v1, setV1] = useState(0.5);
  const [v2, setV2] = useState(0.5);
  const [v3, setV3] = useState(0.5);
 
  return (
    <div className="flex gap-8 h-48">
      <Slider
        value={v1}
        onChange={(e) => setV1(e.value)}
        roundness={0.0}
        size="large"
        label="Square"
      />
      <Slider
        value={v2}
        onChange={(e) => setV2(e.value)}
        roundness={0.5}
        size="large"
        label="Rounded"
      />
      <Slider
        value={v3}
        onChange={(e) => setV3(e.value)}
        roundness={1.0}
        size="large"
        label="Fully Rounded"
      />
    </div>
  );
}
 

Thickness

Adjust the thickness of the slider track:

import { useState } from "react";
import { Slider } from "@cutoff/audio-ui-react";
 
export default function SliderThickness() {
  const [v1, setV1] = useState(0.5);
  const [v2, setV2] = useState(0.5);
  const [v3, setV3] = useState(0.5);
 
  return (
    <div className="flex gap-8 h-48">
      <Slider
        value={v1}
        onChange={(e) => setV1(e.value)}
        thickness={0.2}
        size="large"
        label="Thin"
      />
      <Slider
        value={v2}
        onChange={(e) => setV2(e.value)}
        thickness={0.5}
        size="large"
        label="Medium"
      />
      <Slider
        value={v3}
        onChange={(e) => setV3(e.value)}
        thickness={0.8}
        size="large"
        label="Thick"
      />
    </div>
  );
}
 

Bipolar Mode

In bipolar mode, the slider visualizes values relative to a center point. This is ideal for pan controls:

import { useState } from "react";
import { Slider } from "@cutoff/audio-ui-react";
 
export default function BipolarSlider() {
  const [value, setValue] = useState(0);
 
  return (
    <div className="w-full">
      <Slider
        value={value}
        onChange={(e) => setValue(e.value)}
        min={-100}
        max={100}
        bipolar={true}
        orientation="horizontal"
        size="large"
        label="Pan"
      />
    </div>
  );
}
 

Value Display

The valueAsLabel prop controls how the label and value are displayed:

import { useState } from "react";
import { Slider } from "@cutoff/audio-ui-react";
 
export default function SliderValueDisplay() {
  const [v1, setV1] = useState(0.5);
  const [v2, setV2] = useState(0.5);
  const [v3, setV3] = useState(0.5);
 
  return (
    <div className="flex gap-8 h-48">
      <Slider
        value={v1}
        onChange={(e) => setV1(e.value)}
        valueAsLabel="labelOnly"
        size="large"
        label="Volume"
      />
      <Slider
        value={v2}
        onChange={(e) => setV2(e.value)}
        valueAsLabel="valueOnly"
        size="large"
        label="Volume"
      />
      <Slider
        value={v3}
        onChange={(e) => setV3(e.value)}
        valueAsLabel="interactive"
        size="large"
        label="Volume"
      />
    </div>
  );
}
 

Value Formatting

Customize how values are displayed using the valueFormatter prop:

import { useState } from "react";
import { Slider, frequencyFormatter } from "@cutoff/audio-ui-react";
 
export default function SliderFormatterExample() {
  const [frequency, setFrequency] = useState(1000);
  const [gain, setGain] = useState(0);
 
  return (
    <div className="flex gap-8 items-center flex-wrap h-48">
      <Slider
        value={frequency}
        onChange={(e) => setFrequency(e.value)}
        min={20}
        max={20000}
        label="Frequency"
        valueFormatter={(value) => frequencyFormatter(value)}
        size="large"
      />
      <Slider
        value={gain}
        onChange={(e) => setGain(e.value)}
        min={-60}
        max={12}
        label="Gain"
        valueFormatter={(value) => `${Math.round(value)} dB`}
        size="large"
      />
    </div>
  );
}
 

Parameter Model

Use a parameter model for integration with audio parameter systems. The following example uses ad-hoc props; with the full library you would use createContinuousParameter and the parameter prop:

import { useState } from "react";
import { Slider } from "@cutoff/audio-ui-react";
 
export default function SliderParameterModelExample() {
  const [value, setValue] = useState(50);
 
  return (
    <div className="h-48">
      <Slider
        min={0}
        max={100}
        label="Volume"
        value={value}
        onChange={(e) => setValue(e.value)}
        size="large"
      />
    </div>
  );
}
 

Adaptive Sizing

The Slider component supports both fixed sizes and adaptive sizing. By default, the size of the component is driven by the Size System and their size attribute:

import { useState } from "react";
import { Slider } from "@cutoff/audio-ui-react";
 
export default function SliderSizing() {
  const [v1, setV1] = useState(0.5);
  const [v2, setV2] = useState(0.5);
  const [v3, setV3] = useState(0.5);
  const [v4, setV4] = useState(0.5);
 
  return (
    <div className="flex gap-4 items-center flex-wrap h-64">
      <Slider
        value={v1}
        onChange={(e) => setV1(e.value)}
        size="small"
        label="Small"
      />
      <Slider
        value={v2}
        onChange={(e) => setV2(e.value)}
        size="normal"
        label="Normal"
      />
      <Slider
        value={v3}
        onChange={(e) => setV3(e.value)}
        size="large"
        label="Large"
      />
      <Slider
        value={v4}
        onChange={(e) => setV4(e.value)}
        size="xlarge"
        label="XLarge"
      />
    </div>
  );
}
 

Adaptive sizing allows the component to adapt to the size of its parent container, adjusting its dimensions intelligently without causing distortion (scaleToFit display mode). The fill display mode makes the component fill the entire container, potentially distorting it.

import { useState } from "react";
import { Slider } from "@cutoff/audio-ui-react";
 
export default function SliderAdaptiveSize() {
  const [wideValue, setWideValue] = useState(0.5);
  const [tallValue, setTallValue] = useState(0.5);
  const [distortedValue, setDistortedValue] = useState(0.5);
 
  return (
    <div className="flex gap-6 items-center flex-wrap h-48">
      <div className="w-48 h-16 border rounded-lg p-2">
        <Slider
          value={wideValue}
          onChange={(e) => setWideValue(e.value)}
          adaptiveSize={true}
          orientation="horizontal"
          label="Wide"
        />
      </div>
      <div className="w-24 h-48 border rounded-lg p-2">
        <Slider
          value={tallValue}
          onChange={(e) => setTallValue(e.value)}
          adaptiveSize={true}
          label="Tall"
        />
      </div>
      <div className="w-32 h-20 border rounded-lg p-2">
        <Slider
          value={distortedValue}
          onChange={(e) => setDistortedValue(e.value)}
          adaptiveSize={true}
          displayMode="fill"
          label="Distorted"
        />
      </div>
    </div>
  );
}
 

Interaction Modes

Control how users interact with the slider:

import { useState } from "react";
import { Slider } from "@cutoff/audio-ui-react";
 
export default function SliderInteractionExample() {
  const [dragVal, setDragVal] = useState(0.5);
  const [wheelVal, setWheelVal] = useState(0.5);
  const [bothVal, setBothVal] = useState(0.5);
 
  return (
    <div className="flex gap-4 items-center flex-wrap h-48">
      <Slider
        value={dragVal}
        onChange={(e) => setDragVal(e.value)}
        interactionMode="drag"
        label="Drag Only"
        size="large"
      />
      <Slider
        value={wheelVal}
        onChange={(e) => setWheelVal(e.value)}
        interactionMode="wheel"
        label="Wheel Only"
        size="large"
      />
      <Slider
        value={bothVal}
        onChange={(e) => setBothVal(e.value)}
        interactionMode="both"
        label="Drag & Wheel"
        size="large"
      />
    </div>
  );
}

Adjust the sensitivity of interactions:

import { useState } from "react";
import { Slider } from "@cutoff/audio-ui-react";
 
export default function SliderSensitivityExample() {
  const [lowVal, setLowVal] = useState(0.5);
  const [highVal, setHighVal] = useState(0.5);
 
  return (
    <div className="flex gap-4 items-center flex-wrap h-48">
      <Slider
        value={lowVal}
        onChange={(e) => setLowVal(e.value)}
        interactionSensitivity={0.01}
        label="Low Sensitivity"
        size="large"
      />
      <Slider
        value={highVal}
        onChange={(e) => setHighVal(e.value)}
        interactionSensitivity={0.1}
        label="High Sensitivity"
        size="large"
      />
    </div>
  );
}

Common Patterns

Volume Fader

A typical vertical volume fader:

import { useState } from "react";
import { Slider } from "@cutoff/audio-ui-react";
 
export default function VolumeFader() {
  const [volume, setVolume] = useState(70);
 
  return (
    <div className="h-48">
      <Slider
        value={volume}
        onChange={(e) => setVolume(e.value)}
        orientation="vertical"
        variant="trackfull"
        min={0}
        max={100}
        label="Volume"
        size="large"
        valueFormatter={(value) => `${Math.round(value)}%`}
      />
    </div>
  );
}

Pan Control

A horizontal pan control with bipolar mode:

import { useState } from "react";
import { Slider } from "@cutoff/audio-ui-react";
 
export default function PanControl() {
  const [pan, setPan] = useState(0);
 
  return (
    <Slider
      value={pan}
      onChange={(e) => setPan(e.value)}
      orientation="horizontal"
      min={-100}
      max={100}
      bipolar={true}
      label="Pan"
      size="large"
      valueFormatter={(value) => {
        if (value === 0) return "C";
        return value > 0 ? `R${Math.abs(value)}` : `L${Math.abs(value)}`;
      }}
    />
  );
}

Next Steps