InputsReact
Picks an angle, such as a direction or a rotation, by turning a thumb around a dial.
Rendered by React 19.3.1
Loading React…Installation
npm i @hamur/reactNot on npm yet. The package goes out under the chosen name.
Anatomy
Import the component and assemble its parts:
<AngleSlider.Root>
<AngleSlider.Label />
<AngleSlider.Control>
<AngleSlider.Indicator />
<AngleSlider.Marker />
<AngleSlider.Value />
<AngleSlider.Thumb />
</AngleSlider.Control>
</AngleSlider.Root>Examples
Controlled
A wind direction held in state with step 5; each change shows its reason, and a button sets north.
Form
A heading in a Field inside a Form; the form submits the degrees by name.
API reference
20 props across 7 parts, in React syntax. className, style, render are listed once, under Shared props.
ControlAngleSlider.Control
The circle that takes presses and drags: the value follows the pointer's angle around its center. Renders a <div>.
IndicatorAngleSlider.Indicator
A layer the size of its box turned to the value, so a needle drawn at its top points at the value. Renders a <div>.
LabelAngleSlider.Label
An accessible label that names the angle slider's input and group. Renders a <div>.
MarkerAngleSlider.Marker
A decorative mark on the circle at its own value, hidden from assistive technology. Renders a <div>.
| Prop | Type | Default |
|---|---|---|
valuerequiredThe marker's place in degrees, normalised into one turn. | number | — |
| Data attribute | Description |
|---|---|
data-active | Present when the marker is at the value. |
data-filled | Present when the marker lies on the arc from 0 to the value. |
data-dragging | Present while the user is dragging. |
data-disabled | Present when the angle slider is disabled. |
data-valid | Present when the angle slider is in a valid state (when wrapped in Field.Root). |
data-invalid | Present when the angle slider is in an invalid state (when wrapped in Field.Root). |
data-touched | Present when the angle slider has been touched (when wrapped in Field.Root). |
data-dirty | Present when the angle slider's value has changed (when wrapped in Field.Root). |
data-focused | Present when the angle slider is focused (when wrapped in Field.Root). |
| CSS variable | Description |
|---|---|
--angle-slider-marker-angle | The marker's own value in degrees. |
RootAngleSlider.Root
Groups all parts of the angle slider: one value in degrees, 0 at the top and clockwise, wrapping at a full turn. Renders a <div>.
| Prop | Type | Default |
|---|---|---|
defaultValueThe uncontrolled value in degrees when the slider is initially rendered, | number | 0 |
valueThe value in degrees, 0 at the top and clockwise. | number | — |
disabledWhether the slider should ignore user interaction. | boolean | false |
formatOptions to format the value, merged over { style: 'unit', unit: 'degree', unitDisplay: 'narrow' }. | Intl.NumberFormatOptions | — |
localeThe locale used by Intl.NumberFormat when formatting the value. | Intl.LocalesArgument | — |
nameIdentifies the field when a form is submitted. | string | — |
formIdentifies the form that owns the slider input. | string | — |
stepThe degrees between positions: 0, step, 2·step, … below 360. | number | 1 |
largeStepThe degrees moved by Page Up/Page Down and Shift + an arrow key, and the multiple a pointer snaps to while Shift is held. | number | 15 |
onValueChangeCallback fired when the value changes. | ((value: number, eventDetails: AngleSliderRootChangeEventDetails) => void) | — |
onValueCommittedCallback fired when a change is committed: on release, per key, per input change. | ((value: number, eventDetails: AngleSliderRootCommitEventDetails) => void) | — |
| Data attribute | Description |
|---|---|
data-dragging | Present while the user is dragging. |
data-disabled | Present when the angle slider is disabled. |
data-valid | Present when the angle slider is in a valid state (when wrapped in Field.Root). |
data-invalid | Present when the angle slider is in an invalid state (when wrapped in Field.Root). |
data-touched | Present when the angle slider has been touched (when wrapped in Field.Root). |
data-dirty | Present when the angle slider's value has changed (when wrapped in Field.Root). |
data-focused | Present when the angle slider is focused (when wrapped in Field.Root). |
| CSS variable | Description |
|---|---|
--angle-slider-angle | The value in degrees, inherited by every part. |
ThumbAngleSlider.Thumb
The thumb on the circle at the value. It holds the visually hidden <input type="range"> that takes focus and the keys. and a nested <input type="range">. Renders a <div>.
| Prop | Type | Default |
|---|---|---|
aria-valuetextA string value forwarded to the [aria-valuetext](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-valuetext) attribute of the input. | string | — |
getAriaValueTextA function which returns a string value for the [aria-valuetext](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-valuetext) attribute of the input. | ((formattedValue: string, value: number) => string) | null | — |
inputRefA ref to access the nested input element. | React.Ref<HTMLInputElement> | — |
onBlurA blur handler forwarded to the input. | React.FocusEventHandler<HTMLInputElement> | — |
onFocusA focus handler forwarded to the input. | React.FocusEventHandler<HTMLInputElement> | — |
onKeyDownA keydown handler forwarded to the input. | React.KeyboardEventHandler<HTMLInputElement> | — |
tabIndexOptional tab index attribute forwarded to the input. | number | — |
ValueAngleSlider.Value
Displays the value as text: "90°" by default. Renders an <output>.
| Prop | Type | Default |
|---|---|---|
childrenReplaces the text: receives the formatted value and the value in degrees. | ((formattedValue: string, value: number) => React.ReactNode) | null | — |
Shared props
Every part that renders an element takes these.
| Prop | Type |
|---|---|
classNameCSS class applied to the element, or a function that
returns a class based on the component's state. | string | ((state: State) => string | undefined) |
styleStyle applied to the element, or a function that
returns a style object based on the component's state. | React.CSSProperties | ((state: State) => React.CSSProperties | undefined) |
renderAllows you to replace the component's HTML element
with a different tag, or compose it with another component. | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, State> |
Keyboard and accessibility
Keyboard
| Keys | Does | Part |
|---|---|---|
| ArrowRightArrowUp | Turns clockwise by step, in right-to-left too | Thumb |
| ArrowLeftArrowDown | Turns counterclockwise by step | Thumb |
| Shift | Turns by largeStep (15° by default) | Thumb |
| PageUpPageDown | Turns by largeStep | Thumb |
| HomeEnd | Sets 0° or the last position (359° with step 1) | Thumb |
| Wrap: 359° to 0° and 0° to 359° | Thumb |
Accessibility
| Part | Sets | So that |
|---|---|---|
| Thumb | a nested <input type="range"> with min="0", max the last position, aria-valuenow | the angle is read as a slider with its value, never outside its range |
| Thumb | aria-valuetext with the long unit, or from getAriaValueText | the value is read as "90 degrees", not "90" or a symbol |
| Thumb | aria-labelledby to Label or the Field label | the slider has a name |
| Root | role="group", aria-labelledby to Label | the dial is read as one named control |
| Marker | aria-hidden="true" | the ticks are drawn only; the value text already says where the thumb is |
| Value | renders an <output> for the input | the value text is tied to the slider without being announced on every change |
Focus order
- The Thumb is one tab stop.
- Pressing the Control focuses the thumb; clicking Label focuses it too.