Skip to main content

An angle slider is a circular dial that allows users to select an angle, typically in degrees, within a 360° range. It provides an intuitive way to control rotations or orientations, offering accessibility features.

Loading...

Features

  • Fully managed keyboard navigation
  • Supports touch or click on the track to update value
  • Supports right-to-left direction

Installation

Install the angle slider package:

npm install @zag-js/angle-slider @zag-js/react # or yarn add @zag-js/angle-slider @zag-js/react

Anatomy

To set up the angle slider correctly, you'll need to understand its anatomy and how we name its parts.

Each part includes a data-part attribute to help identify them in the DOM.

No anatomy available for angle-slider

Usage

Import the angle-slider package:

import * as angleSlider from "@zag-js/angle-slider"

The angle slider package exports two key functions:

  • machine - State machine logic.
  • connect - Maps machine state to JSX props and event handlers.

Pass a unique id to useMachine so generated element ids stay predictable.

Then use the framework integration helpers:

import * as angleSlider from "@zag-js/angle-slider" import { normalizeProps, useMachine } from "@zag-js/react" export function AngleSlider() { const service = useMachine(angleSlider.machine, { id: "1" }) const api = angleSlider.connect(service, normalizeProps) return ( <div {...api.getRootProps()}> <label {...api.getLabelProps()}>Wind direction</label> <div {...api.getControlProps()}> <div {...api.getThumbProps()}></div> <div {...api.getMarkerGroupProps()}> {[0, 45, 90, 135, 180, 225, 270, 315].map((value) => ( <div key={value} {...api.getMarkerProps({ value })}></div> ))} </div> </div> <div {...api.getValueTextProps()}>{api.value} degrees</div> <input {...api.getHiddenInputProps()} /> </div> ) }

Setting the initial value

Set defaultValue to define the initial slider value.

const service = useMachine(angleSlider.machine, { defaultValue: 45, })

Controlled angle slider

Use value and onValueChange to control the value externally.

import { useState } from "react" export function ControlledAngleSlider() { const [value, setValue] = useState(45) const service = useMachine(angleSlider.machine, { value, onValueChange(details) { setValue(details.value) }, }) return ( // ... ) }

Setting the value's granularity

By default, step is 1, so values move in whole-number increments. Set step to control granularity.

For example, set step to 0.01 for two-decimal precision:

const service = useMachine(angleSlider.machine, { step: 0.01, })

Listening for changes

When the angle slider value changes, the onValueChange and onValueChangeEnd callbacks are invoked.

const service = useMachine(angleSlider.machine, { onValueChange(details) { console.log("value:", details.value) console.log("as degree:", details.valueAsDegree) }, onValueChangeEnd(details) { console.log("final value:", details.value) }, })

Read-only mode

Set readOnly to prevent updates while preserving focus and form semantics.

const service = useMachine(angleSlider.machine, { readOnly: true, })

Usage in forms

To submit the value with a form:

  • Set name on the machine.
  • Render the hidden input from api.getHiddenInputProps().
const service = useMachine(angleSlider.machine, { name: "wind-direction", })

Labeling the thumb for assistive tech

Use aria-label or aria-labelledby when you need custom labeling.

const service = useMachine(angleSlider.machine, { "aria-label": "Wind direction", })

Using angle slider marks

To show marks or ticks along the angle slider track, use the exposed api.getMarkerProps() method to position the angle slider marks at desired angles.

//... <div {...api.getRootProps()}> <label {...api.getLabelProps()}>Wind direction</label> <div {...api.getControlProps()}> <div {...api.getThumbProps()}></div> <div {...api.getMarkerGroupProps()}> {[0, 45, 90, 135, 180, 225, 270, 315].map((value) => ( <div key={value} {...api.getMarkerProps({ value })}></div> ))} </div> </div> <div {...api.getValueTextProps()}>{api.value} degrees</div> <input {...api.getHiddenInputProps()} /> </div> //...

Styling guide

Each part includes a data-part attribute you can target in CSS.

Disabled State

When the angle slider is disabled, the data-disabled attribute is added to the root, label, control, thumb and marker.

[data-part="root"][data-disabled] { /* styles for root disabled state */ } [data-part="label"][data-disabled] { /* styles for label disabled state */ } [data-part="control"][data-disabled] { /* styles for control disabled state */ } [data-part="thumb"][data-disabled] { /* styles for thumb disabled state */ } [data-part="range"][data-disabled] { /* styles for thumb disabled state */ }

Invalid State

When the slider is invalid, the data-invalid attribute is added to the root, track, range, label, and thumb parts.

[data-part="root"][data-invalid] { /* styles for root invalid state */ } [data-part="label"][data-invalid] { /* styles for label invalid state */ } [data-part="control"][data-invalid] { /* styles for control invalid state */ } [data-part="valueText"][data-invalid] { /* styles for output invalid state */ } [data-part="thumb"][data-invalid] { /* styles for thumb invalid state */ } [data-part="marker"][data-invalid] { /* styles for marker invalid state */ }

Styling the markers

[data-part="marker"][data-state="(at|under|over)-value"] { /* styles for when the value exceeds the marker's value */ }

Methods and Properties

Machine Context

The angle slider machine exposes the following context properties:

  • idsPartial<{ root: string; thumb: string; hiddenInput: string; control: string; valueText: string; label: string; }>The ids of the elements in the machine. Useful for composition.
  • stepnumberThe step value for the slider.
  • valuenumberThe value of the slider.
  • defaultValuenumberThe initial value of the slider. Use when you don't need to control the value of the slider.
  • onValueChange(details: ValueChangeDetails) => voidThe callback function for when the value changes.
  • onValueChangeEnd(details: ValueChangeDetails) => voidThe callback function for when the value changes ends.
  • disabledbooleanWhether the slider is disabled.
  • readOnlybooleanWhether the slider is read-only.
  • invalidbooleanWhether the slider is invalid.
  • namestringThe name of the slider. Useful for form submission.
  • aria-labelstringThe accessible label for the slider thumb.
  • aria-labelledbystringThe id of the element that labels the slider thumb.
  • dir"ltr" | "rtl"The document's text/writing direction.
  • idstringThe unique identifier of the machine.
  • getRootNode() => ShadowRoot | Node | DocumentA root node to correctly resolve document in custom environments. E.x.: Iframes, Electron.

Machine API

The angle slider api exposes the following methods:

  • valuenumberThe current value of the angle slider
  • valueAsDegreestringThe current value as a degree string
  • setValue(value: number) => voidSets the value of the angle slider
  • draggingbooleanWhether the slider is being dragged.

Data Attributes

Root
data-scope
angle-slider
data-part
root
data-disabled
Present when disabled
data-invalid
Present when invalid
data-readonly
Present when read-only
Label
data-scope
angle-slider
data-part
label
data-disabled
Present when disabled
data-invalid
Present when invalid
data-readonly
Present when read-only
Control
data-scope
angle-slider
data-part
control
data-disabled
Present when disabled
data-invalid
Present when invalid
data-readonly
Present when read-only
Thumb
data-scope
angle-slider
data-part
thumb
data-disabled
Present when disabled
data-invalid
Present when invalid
data-readonly
Present when read-only
Marker
data-scope
angle-slider
data-part
marker
data-value
The value of the item
data-disabled
Present when disabled

CSS Variables

Root
--value
The current value
--angle
The angle in degrees
Marker
--marker-value
The logical marker value (e.g. 0, 45, 90)
--marker-display-value
The rotation angle for display (mirrored in RTL)

Keyboard Interactions

  • ArrowRight
    Increments the angle slider based on defined step
  • ArrowLeft
    Decrements the angle slider based on defined step
  • ArrowUp
    Decreases the value by the step amount.
  • ArrowDown
    Increases the value by the step amount.
  • Shift + ArrowUp
    Decreases the value by a larger step
  • Shift + ArrowDown
    Increases the value by a larger step
  • Home
    Sets the value to 0 degrees.
  • End
    Sets the value to 360 degrees.
Edit this page on GitHub