Vize

Angle Picker

Full-circle angle input (0–359°) with wrapping keyboard steps and pointer rotation.

Package @vizejs/ui/angle-picker
Maturity stable
Own the source vize lib pull angle-picker
Requires controllable-state, id, knob
Aliases angle input, rotation picker, hue wheel, direction picker
Covers WAI-ARIA Slider, Figma angle input, Mantine AngleSlider

Usage

import { AnglePicker } from "@vizejs/ui/angle-picker";

Or copy the source into your project with vize lib pull angle-picker (see Source Distribution).

API

AnglePicker

Source: src/families/form/angle-picker/angle-picker.vue

Props

Prop Type Default Description
id string | null undefined Element id. null and undefined select a deterministic fallback.
name string undefined Native form field name; a hidden input submits the angle in degrees.
modelValue number undefined Controlled angle in degrees; any number is wrapped into [0, 360).
defaultValue number 0 Initial uncontrolled angle, also restored by form reset.
step number 1 Angle step in degrees.
largeStep number 15 Angle step for Page Up and Page Down.
disabled boolean false Disable interaction and form submission.
readOnly boolean false Keep focus and form value while preventing user changes.
getValueText (angle: number) => string (angle) => ${angle} degrees Formats aria-valuetext.
ariaLabel string undefined Accessible name when no label or aria-labelledby supplies one.
ariaLabelledby string undefined Ids that label the picker.
ariaDescribedby string undefined Ids that describe the picker.
ariaErrormessage string undefined Id of the validation error message used while invalid.
ariaInvalid AnglePickerAriaInvalid false Invalid state announced to assistive technology.

Events

Event Payload Description
update:modelValue [angle: number] Fired for every requested angle, including drag frames.
change [angle: number, source: AnglePickerChangeSource] Fired once a change is committed (key press, pointer release, or API).

Slots

Slot Slot props Description
default AnglePickerSlotState Renders the dial and indicator with the current angle.

Exposed

Member Type Description
value number Current value.
angle number Indicator angle in degrees (clockwise from 12 o'clock).
percent number Position within the bounds, 0–100.
min number Normalized lower bound.
max number Normalized upper bound.
dragging boolean Whether a pointer drag is active.
disabled boolean Whether interaction is disabled.
state KnobState Stable state token.
element HTMLSpanElement | null Rendered role="slider" element.
focus (options?: FocusOptions) => void Focus the rotary element.
setValue (value: number) => boolean Request a value (snapped/clamped or wrapped); returns whether it changed.
reset () => boolean Restore the default value; returns whether it changed.

Behavior

Normative state x input -> outcome table for angle-picker.vue (@vizejs/ui/angle-picker), a full-circle angle input with WAI-ARIA APG slider semantics that reuses Knob's rotary geometry and drag handling. Every row is proven by the named test in angle-picker.test.ts or ../knob/knob-ssr.test.ts; compile-only assertions live in angle-picker.types.test-d.ts.

# State Input Outcome Proven by
A1 seeded render role="slider" with 0 to 360 - step, wrapped value, "N degrees" value text, --vize-angle-picker-angle, hidden value renders a full-circle slider with degree value text and a CSS angle
A2 focused Arrow / Page / Home / End steps wrap around the circle; Home is 0°, End is the last step; each change commits keyboard steps wrap around the circle
A3 idle pointer drag the pointer angle around the center becomes the value, snapped to step; release commits once pointer rotation follows the pointer and snaps to the step
A4 controlled / disabled / API keys, expose controlled values win; disabled pickers ignore keys; setValue wraps; reset restores the default controlled, disabled, and imperative behavior
A5 SSR isolated requests byte-identical markup and hydration without diagnostics renders byte-identical rotary markup and hydrates without mismatches

The subpath is tree-shakable and ships no CSS; those package contracts are pinned by distribution.test.ts, check:size, and check:tree-shaking.