Media & effects
Torque Dial
Rotational control knob with physical spin momentum
detent-torque-dial
Port status
- Catalog status
- implemented
- Origin
- upstream
- Phase
- 4
- Wave
- phase-4-motion-controls
- Group
- Media & effects
7.1 KB gzip for the class module · inlines the shared spring
Variants
Drag a dial, use the wheel, or focus and use the arrow keys. Nothing has changed yet.
Recorded states
draggingrecorded state; no setter
Usage
Import
import '/components/torque-dial/define.js';
// or register it yourself
import { DetentTorqueDial } from '/components/torque-dial/torque-dial.js';
Attributes
disabledlabelmaxminmomentumshow-valuesizestepunitvalue
Properties
onChangeonChangeEnd
Slots
No slots are recorded for this component.
Events
detent-change— {}detent-change-end— {}
Example
Runnable example: site/examples/torque-dial.ts. The snippet below is generated from the catalogued attributes.
<detent-torque-dial
disabled
label
max="100"
min="0"
momentum
show-value
size="120"
step="1"
unit=""
value
></detent-torque-dial>
Property-only values
const element = document.querySelector('detent-torque-dial');
if (element !== null) {
// onChange: (val: number) => void
element.onChange = () => {};
}
Source
The pinned upstream source for this row:
src/components/ui/TorqueDial.tsxsha256 9edabeddc493…
Native files
The native module and its artifacts:
src/components/torque-dial/torque-dial.tssrc/components/torque-dial/styles.csssrc/components/torque-dial/define.tsdocs/components/torque-dial.mdsite/examples/torque-dial.tstests/browser/torque-dial.spec.tsevidence/components/torque-dial.md
API
Boolean attributes follow HTML presence semantics: present means true, absent means false, and disabled="false" still means disabled.
Attributes
| Attribute | Property | Type | Default | Notes |
|---|---|---|---|---|
disabled | — | — | — | Recorded in the catalog as an attribute. |
label | — | — | — | Recorded in the catalog as an attribute. |
max | max | number | 100 | Kebab-case attribute; camelCase property. |
min | min | number | 0 | Kebab-case attribute; camelCase property. |
momentum | momentum | boolean | true | Presence semantics: present means true, absent means false. |
show-value | — | — | — | Recorded in the catalog as an attribute. |
size | size | number | 120 | Kebab-case attribute; camelCase property. |
step | step | number | 1 | Kebab-case attribute; camelCase property. |
unit | unit | string | '' | Kebab-case attribute; camelCase property. |
value | value | number | — | Kebab-case attribute; camelCase property. |
Properties
| Property | Type | Default | Notes |
|---|---|---|---|
onChange | (val: number) => void | — | Property-only: assign from script; not accepted as an attribute. |
onChangeEnd | — | — | Recorded in the catalog without a top-level type; pinned from source when the row is ported. |
Events
| Event | Upstream prop | Payload type | Notes |
|---|---|---|---|
detent-change | onChange | (val: number) => void | Composed, bubbles; fires only for a user action. |
detent-change-end | onChangeEnd | () => void | Composed, bubbles; fires only for a user action. |
Slots
No slots are recorded for this component.
CSS customisation
- React callback props become typed composed CustomEvents; programmatic state assignment emits none.
- Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
- React state/hooks replaced by element-owned state with pre-upgrade property preservation.
- Controlled/uncontrolled React pair maps to initial-value attributes plus owned state and change events.
- Knob rotation and progress arc share one springSnappy (380/30/0.5) spring on the shared helper, started from the painted angle; a retarget continues from there. Upstream ran two springs with the same token, so the arc and knob trajectories match; no easing is substituted.
- The progress arc follows the value instead of springing.
- An absent value resolves to min.
- min/max/step changes re-clamp the stored value.
- A no-op step emits no detent-change and a no-op gesture emits no detent-change-end.
- Track, knob border and muted label are lightened for contrast (upstream measured 1.21:1, 1.12:1 and 3.74:1).
- The release glide decay is normalised by elapsed time instead of per-frame multiply 0.92.
- className is not a property.
What it does
A rotational knob with pointer-drag value mapping, wheel and keyboard stepping, double-click centring, an angular release glide and an SVG radial progress ring.
Upstream behaviour
- Natural angular momentum release with exponential friction deceleration decay
- Supports drag rotation, mouse wheel fine-tuning, keyboard arrow adjustments, and double-click centering
- Dynamic SVG radial progress ring with continuous value telemetry
- Full accessibility with role="slider", aria-valuenow, and keyboard stepping
Differences from upstream
- React callback props become typed composed CustomEvents; programmatic state assignment emits none.
- Framer Motion springs/AnimatePresence ported to CSS transitions, WAAPI or the shared rAF spring helper.
- React state/hooks replaced by element-owned state with pre-upgrade property preservation.
- Controlled/uncontrolled React pair maps to initial-value attributes plus owned state and change events.
- Knob rotation and progress arc share one springSnappy (380/30/0.5) spring on the shared helper, started from the painted angle; a retarget continues from there. Upstream ran two springs with the same token, so the arc and knob trajectories match; no easing is substituted.
- The progress arc follows the value instead of springing.
- An absent value resolves to min.
- min/max/step changes re-clamp the stored value.
- A no-op step emits no detent-change and a no-op gesture emits no detent-change-end.
- Track, knob border and muted label are lightened for contrast (upstream measured 1.21:1, 1.12:1 and 3.74:1).
- The release glide decay is normalised by elapsed time instead of per-frame multiply 0.92.
- className is not a property.