Skip to content
menumenu tanreiexpand_morecontrasttranslate
tanreiexpand_more
Getting startedWebReactSwiftUIJetpack ComposeFlutterReact NativePresetsYour own design systemUsing Tanrei with AI agentsBrandDesign tokensDesign systems and customizationTheme StudioColorTypographyIconsShapeElevationMotionInteraction statesBehaviourLayoutAccessibilityWordsColor tokensTypescale tokensShape tokensElevation tokensMotion tokensState tokensSpace and measure tokensComponentsButtonMain action buttonSegmented buttonButton groupButton with menuToolbarCopy buttonCheckboxRadio buttonSwitchChipMenuSliderSlider fieldCalendarDateTimePickerField groupRadio groupCheckbox groupSelectSelect fieldMenubarFile uploadFile picker AdvancedDrop zoneText input AdvancedText fieldChip fieldFieldCombobox AdvancedCombobox fieldNumber input AdvancedNumber fieldColor input AdvancedColor fieldOne-time-code input AdvancedOne-time-code fieldEmbedded text input AdvancedChat composerCardDividerModal layer AdvancedDialogListList rowBottom sheetSide sheetCarouselCode blockTablePopoverStepsAccordionDescription listFigureApp shellPage headerTree viewTimelineImage previewHandleResizable frameScroll areaBadgeProgress indicatorMeterNumber tickerLoading indicatorSnackbarTooltipKeyboard shortcutTagInline codeCalloutAvatarEmpty stateTag groupSkeletonFile itemSwatchMarquee textTabsTab viewApp barNavigation barNavigation drawerSearchLinkPaginationPrevious and next linksStepperBreadcrumbsTable of contentsLink cardFAB menuStatusHow Tanrei is builtContributingLicense and attribution
HomeComponentsSlider field

Slider field

Lets people choose a value, or a range of values, on a scale as one complete field — the track under a label, with the value in words at the end of the label row, a line of help and the reason a value was refused.

content_copyView as Markdown
Category
Selection
Tokens
comp.field
Level
Composed
Built from
Field, Slider

Overview

Web
tanrei-slider-field
schedule
SwiftUI
TanreiSliderField
radio_button_unchecked
Jetpack Compose
TanreiSliderField
radio_button_unchecked
Flutter
TanreiSliderField
radio_button_unchecked
React Native
SliderField
radio_button_unchecked

Generated from docs/status/status.json, specs/slider-field.spec.json

A slider field, a stepped one, and a range

Use a slider field for a value that is chosen by feel and read back in words: a text size of 120 %, a distance of 5 km, a price from $100 to $300. A slider alone has no label that is drawn, and its track does not say what it is set to. The slider field is the ordinary case, ready to use: a label, the value in words, the track, a line of help and an error.

Built from a field and a slider. The field is the frame: the label, the required or optional mark, the value text at the end of the label row, the help and the error. The slider is the control: the track, the handles and everything a person does with them. The slider field draws nothing of its own and has no token: every property it has is a property of one of the two, given to it unchanged, except valueHidden, which is its own.

It is as wide as the place it is put in, and its track fills it.

On the web it is <tanrei-slider-field>. The other platforms have not implemented it yet.

Usage

value is the value of the handle, and of a range’s end handle; startValue is the range’s start handle. The two events are the slider’s own: input at every change while the person drags, change once when the change is finished. When either is heard the field’s value and startValue are already the new ones.

<form>
  <tanrei-slider-field name="text-size" label="Text size"
    supporting-text="Applies to every page."
    min="50" max="200" step="10" value="120"></tanrei-slider-field>

  <!-- A range submits start-value, then value, under the one name. Name each handle. -->
  <tanrei-slider-field name="price" label="Price" range
    min="0" max="500" step="10" start-value="100" value="300"
    start-label="Minimum price" end-label="Maximum price"></tanrei-slider-field>
</form>

<script type="module">
  import '@tanrei/web/components/slider-field';

  // The words for a value, given once: a property, never an attribute.
  const percent = new Intl.NumberFormat(document.documentElement.lang, { style: 'percent' });
  const size = document.querySelector('[name="text-size"]');
  size.formatValue = (value) => percent.format(value / 100);
  size.addEventListener('input', () => applyTextSize(size.value));

  const dollars = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', maximumFractionDigits: 0 });
  document.querySelector('[name="price"]').formatValue = (value) => dollars.format(value);
</script>
import { SliderField } from '@tanrei/react';

<SliderField name="text-size" label="Text size" supportingText="Applies to every page."
  min={50} max={200} step={10} value={size}
  formatValue={(value) => percent.format(value / 100)}
  onInput={(event) => setSize(event.currentTarget.value)} />

The value in words

The value is drawn at the end of the label row, in the words the slider gives its handle — the same words a screen reader hears and the value indicator shows. They are, in this order:

The words When
valueText, and startValueText for a range’s start handle You write the words yourself, and write them again at every input.
What formatValue writes You give one function from a value to its words, once. The slider asks it for each handle at every change.
The number in the page’s locale Neither is given.

A range’s two values are joined by an en dash, in reading order: in a right-to-left layout the start’s words stand at the right, where the start handle is. The slider field writes no number, unit or word itself.

A value text that shares the label's line, one that takes a line of its own, and a field that hides it

The value text stands on the baseline of the label’s first line and the label wraps in the room that is left. Where that would leave the label less than half of the row, the value text takes a line of its own after the label, and wraps there if it must. valueHidden leaves it out, for a slider whose number means nothing to the person: a volume, a brightness. The handle still says its value to assistive technology.

One level down

The same field, written by hand from its two members, is the same picture and the same slider to assistive technology:

<tanrei-field label="Text size" supporting-text="Applies to every page." value-text="120 %">
  <tanrei-slider name="text-size" min="50" max="200" step="10" value="120"></tanrei-slider>
</tanrei-field>

<script type="module">
  const field = document.querySelector('tanrei-field');
  const slider = field.querySelector('tanrei-slider');
  slider.formatValue = (value) => percent.format(value / 100);
  // What the slider field does by itself: the field's value text is the slider's, at every change.
  slider.addEventListener('input', () => (field.valueText = slider.shownValueText));
</script>

The same field written by hand: a field with a slider in it, given the value text once — without the listener above it is not kept in step

Go one level down when you need an arrangement the slider field does not offer:

You need Use
A label, the value in words, the track, help and an error The slider field
A value text the slider does not say — a sentence, “Any price” — or something of your own in the frame A field with a slider in it, and your own value-text
The track alone, named by something drawn elsewhere — a table’s column, a toolbar’s glyph, a player’s volume control The slider alone, named by its own label
A vertical slider The slider alone: the slider field has no orientation
A value that is known and typed A number field, alone or beside a slider

What changes one level down is where things are said. name, value and startValue are on the slider, which is then the control the form meets, and its events are heard on it. label and disabled stay on the field, which passes them to the slider. The end handle of a range is named by the slider’s own label, which the slider field calls endLabel.

Specs

Required with the product's word, optional, in error and disabled

What each member gives

Aspect From the field From the slider
Properties label, labelHidden, supportingText, errorText, error, disabled, required, optional, requiredMark, requiredText, optionalText value, startValue, range, min, max, step, origin, stops, size, valueIndicator, valueText, startValueText, startLabel, and endLabel, which is the slider’s label
Events — input, change
Slots label-icon —
Tokens comp.field.* comp.slider.*

One property is the slider field’s own: valueHidden. And one property of the field is filled by the slider field itself and is not yours to set: the field’s valueText, from the slider’s words.

The slider has a disabled and an orientation of its own. Neither is a property of the slider field: the field’s disabled disables the slider, so that the label and the value text follow, and the track always runs in the inline direction: a slider field has no vertical orientation.

A slider always has a value, so required does not mean “not empty” here. A form that marks every control as required or optional marks this one too; what it refuses — a level of 0, a range too narrow — is yours to say with error and errorText. An error changes nothing of the track: the words and the invalid state carry it.

What the handles do — dragging, the keys, the steps, the value indicator — is on the slider’s page. What the frame does — the required mark, the value text, the help, the error and how it is announced — is on the field’s page.

Setting one field apart

The slider field has no token of its own. Its frame reads the field’s tokens and its track the slider’s, wherever they are set. To change one instance, set the member’s token on it:

<tanrei-slider-field label="Volume" value="40"
  style="--tanrei-comp-field-standard-value-text-color: var(--tanrei-sys-color-on-surface)"></tanrei-slider-field>

Anatomy

Anatomy

Drawn over the fixture default, as the web package draws it.
Part Description
1 field The Field itself: the label row with its label glyph, its requirement mark and, at its end, the value text; and the supporting row with the help and the error text. Drawn by the Field from the Field's tokens. A member: it frames the component.
2 slider The Slider itself, as the Field's one control: its track, active track, handles, stop dots, state layer, value indicator and focus ring, drawn by the Slider from the Slider's tokens. A member: it holds the component's value.

Properties

Property Type Default Description
label string "" Names the control, visibly and to assistive technology. Required, unless the control names itself (a checkbox or a switch with its own label): then leave it empty and the field adds only help and an error. — Field Drawn above the track and, for one handle, its accessible name. While range is true it is the visible name of the pair, and each handle is named by startLabel and endLabel (SLF-5).
labelHidden boolean false Does not draw the label, which stays the accessible name. For a control whose visible label is elsewhere (a table column, a toolbar). — Field The label row takes the value text with it (FLD-29).
supportingText string "" Help shown below the control and given to assistive technology as the control's description. While the field is in error it gives way to errorText, unless the design system keeps both (comp.field.error-text.placement append). — Field
errorText string "" Shown while error is true, in supportingText's place — or below it, which then stays, where the design system's comp.field.error-text.placement is append: what is wrong and how to put it right, in words. — Field
error boolean false Puts the field in the error condition: the error text is drawn, the control is exposed as invalid and, where it has an error condition of its own, drawn in it. What a value means is the product's to validate; the field never sets this itself. — Field A slider has no error condition of its own to draw (FLD-8): the track and the handles stay as they are, and each handle is exposed as invalid.
disabled boolean false Disables the control and draws the frame as disabled. Disable a framed control here, not on the control, so that its label follows. — Field The one disabled of the slider field: the Field passes it to the Slider (FLD-14, SLD-20), whose own disabled is not a prop here, so that the label and the value text always follow.
required boolean false What the form asks of the control: true exposes it as required and draws the required mark beside the label. It never validates: a missing answer is the product's to report with error. — Field
optional boolean false Draws the optional tag after the label and adds optionalText to the control's description, because assistive technology has no state for it. Ignored while required is true: a control is never both. — Field
requiredMark auto | tag | asterisk | none "auto" How this control shows that it is required: tag is a small filled Tag with requiredText, asterisk is "*" after the label, none draws nothing and keeps the semantics. Auto takes comp.field.requirement.mark, which follows sys.behavior.requirement-mark, the system's one answer. Ignored unless required is true. — Field
requiredText string "" The text of the required tag, in the product's language ("Required", "必須"). The product's: Tanrei has no word for it. Empty reads the product's words; with neither, FLD-24 says what is drawn. — Field
optionalText string "" The text of the optional tag, in the product's language ("Optional", "任意"); also read to assistive technology as part of the description. The product's: Tanrei has no word for it. Empty reads the product's words. — Field
value number 0 The value of the only handle, or of a range's end handle. — Slider
startValue number 0 The value of a range's start handle. Ignored while range is false. — Slider
range boolean false Draws two handles, choosing the range from startValue to value (a price filter). — Slider
min number 0 The lowest value, at the track's start. — Slider
max number 100 The highest value, at the track's end. — Slider
step number 0 0 is continuous. Above 0 the slider is discrete: its values are min plus whole multiples of step, up to max. — Slider
origin number null Where the active track starts. Null starts it at min. A value inside the range makes a centered slider (a balance control) whose active track grows toward either side. Ignored while range is true. — Slider
stops boolean false Draws a stop dot at every value a discrete slider can take. Meant for a few steps; ignored while step is 0. — Slider
size small | medium | large "small" The track's weight and the stop dots' size (and, where a system says so, the handle's height). Small is the everyday slider; medium and large give a prominent control (a volume or brightness slider) more weight. The hit area always meets the minimum target. A design system may add values. — Slider Changes nothing of the frame.
valueIndicator none | active | always "none" Whether a handle shows its value beside it: never, while it is pressed or has keyboard focus, or all the time. — Slider
valueText string "" The value as words ("40 %", "3 stars"), spoken and shown by the value indicator in place of the number. For a range, the end handle's. — Slider Also drawn at the end of the label row (SLF-3).
startValueText string "" The start handle's valueText, for a range. — Slider
startLabel string "" Names a range's start handle ("Minimum price"). Required while range is true. — Slider
endLabel string "" Names the slider (a range's end handle) for assistive technology. Never drawn: a visible label is the product's text next to the slider, in the same words. Required. — Slider The Slider's label under the name of the handle it names, because label is the visible name here. Read only while range is true, and required then (SLF-5).
valueHidden boolean false Does not draw the value at the end of the label row. For a slider set by feel, whose number means nothing to the person (a volume, a brightness). The handle still says its value to assistive technology, and valueIndicator still shows it.

Slots

Slot Description
label-icon A glyph before the label. — Field

Events

Event Description
input The person changed a value; carries value and, for a range, startValue. Emitted for every change during a drag, not when the product sets a value. — Slider
change The person finished changing a value (the press ended, or a key or assistive-technology adjustment was made); carries value and, for a range, startValue. Always after the input it follows. — Slider

States

Behavior

Requirements in EARS form. Every platform implementation is tested against these ids.

ID Requirement
SLF-1 THE slider field SHALL be a Field whose one control is a Slider — the two components themselves, each drawn from its own tokens in every state and behaving by its own sentences (FLD-1 to FLD-24, FLD-29 and FLD-30; SLD-1 to SLD-26) — and SHALL draw nothing of its own, have no token of its own, and give neither member a look, a state or a size that the member does not have where it stands alone.
SLF-2 THE slider field SHALL give each member the value of every prop that is that member's, at once and whenever it changes, and SHALL hold none back: the Field takes label, labelHidden, supportingText, errorText, error, disabled, required, optional, requiredMark, requiredText, optionalText and the glyph of the label-icon slot; the Slider takes value, startValue, range, min, max, step, origin, stops, size, valueIndicator, valueText, startValueText, startLabel and, as its own label, endLabel. THE slider field SHALL give the Slider no orientation, so that the track always runs along the line (SLD-21), and SHALL NOT set the Slider's own disabled: the Field disables its control (FLD-14).
SLF-3 WHILE valueHidden is false THE slider field SHALL give the Field, as its value text (FLD-29), the words the Slider gives its handle as that handle's value (SLD-18): WHILE range is false the only handle's; WHILE range is true the start handle's, an en dash with a space on each side, and the end handle's, each of the two an isolated run and the two in reading order, so that in a right-to-left layout the start's words stand at the right of the dash as the start handle stands at the right of the track. THE slider field SHALL NOT write a number, a unit or a word itself. WHILE valueHidden is true THE slider field SHALL give the Field no value text.
SLF-4 WHEN a value changes — at every input of a drag, by a key, by assistive technology, because the product set value or startValue, or because min, max or step changed what the Slider draws (SLD-22) — or valueText, startValueText or the product's function for a value changes, THE slider field SHALL show the new value text in the same frame in which the handle is drawn at its new place, without a motion and without an announcement of its own: the handle says its value to assistive technology itself (SLD-19), and the Field keeps the drawn text from it (FLD-30).
SLF-5 WHILE range is false THE slider field SHALL have its handle named by label, as the Field names its control (FLD-10). WHILE range is true THE slider field SHALL have the start handle named by startLabel and the end handle by endLabel (SLD-19), which should each hold the words of label so that what is seen is in what is heard, and WHILE either is empty SHALL have that handle named by label and in debug builds report that a handle of a range has no name of its own. THE slider field SHALL have every handle described by the text the supporting row shows, with optionalText while optional is true (FLD-11), and exposed as invalid while error is true (FLD-8); WHILE required is true it SHALL have every handle exposed as required where the platform's slider has such a state and, where it has none (the web's slider role), SHALL have requiredText added to the handle's description instead.
SLF-6 THE slider field SHALL hold value and startValue as its own and report them as the Slider does: WHEN the Slider emits input or change THE slider field SHALL emit the same event exactly once, carrying value and, for a range, startValue (SLD-2 to SLD-4), with its own value and startValue already equal to what the event carries; WHEN the product sets value or startValue THE slider field SHALL emit nothing (SLD-16). WHERE the platform has forms THE slider field SHALL be the one control the form sees — it carries the name, submits what the Slider submits, is reset and restored as the Slider is, and submits nothing WHILE disabled is true — and neither member SHALL be a second one.
SLF-7 THE slider field SHALL add no stop to the focus order and handle no key: its only focus stops are the Slider's handles, in the Slider's order (SLD-5), and every key is the Slider's (SLD-3). WHEN focus is given to the slider field itself, or the person presses the label row (FLD-12), THE slider field SHALL move focus to the only handle and, WHILE range is true, to the start handle, and SHALL change no value.
SLF-8 WHILE disabled is true THE slider field SHALL be a disabled Field holding a disabled Slider (FLD-14, SLD-20): no handle takes focus or changes, no event is emitted, the value indicator is not shown, and the label, the requirement mark, the supporting row and the value text are drawn from the Field's disabled tokens; THE slider field SHALL keep the value text drawn, because what a disabled control is set to is still read.
SLF-9 WHILE the text size is enlarged THE slider field SHALL grow as the Field grows (FLD-16) and SHALL leave the Slider's track, handles and hit area as they are (SLD-7); at 200% in a width of 320 no text SHALL be cut, lie over another part or need scrolling in two directions: the label wraps beside the value text, and a value text too wide to share the label's line moves whole to a line of its own (FLD-29).
SLF-10 THE slider field SHALL take its layout direction from where it is used and have no direction setting of its own, and its two members SHALL take the same one (FLD-19, SLD-25). WHERE the layout direction is right-to-left the frame and the track mirror together — the label row starts at the right with the value text at its left end (FLD-18), the track runs from the right (min) to the left (max) and the arrow keys follow it (SLD-21) — and the words of a value SHALL NOT be mirrored: each is laid out as text of its own direction (FLD-21, SLD-26), so that a number keeps its digits, its sign and its unit in their own order.
SLF-11 WHERE the platform draws with a person's own forced colors THE slider field SHALL add nothing and remove nothing: the Field draws its texts as FLD-17 says and the Slider its track and handles as it does standing alone, and the error SHALL still be carried by the words of errorText and by the invalid state of each handle (FLD-8), never by a color.
SLF-12 THE slider field SHALL be, in what is drawn and in what assistive technology is told, exactly what a Field holding a Slider is when a product writes the two by hand with the same props and gives the Field the same value text, which is the one prop of a member the slider field fills itself: every fixture of the slider field and its twin among the Field's fixtures are the same picture, with the same names, descriptions, values and states, and a difference is a defect of the slider field.
SLF-13 THE slider field SHALL be a block as wide as its place in the layout, with no width of its own, and its Slider SHALL fill it from the start edge to the end edge, as a Slider standing in a Field does (FLD-1); the label row and the supporting row are as wide as the track's box.
SLF-14 WHERE the platform has ARIA attributes (the web), WHEN the product sets an aria- attribute on the host, by the attribute or by the ARIA property that reflects it, THE slider field SHALL move it to the data-aria- attribute of the same name, so that the host is no second node with its name, description or state, and SHALL expose it on the element that carries its role — an id reference by the elements it names in the host's tree or a tree around it, an error message as part of the description while the slider field is invalid — except those the slider field owns (aria-label, aria-labelledby, aria-disabled), which it SHALL move and not expose: its name is label (SLF-5). WHEN the product removes the aria- attribute or its data-aria- twin, or sets the ARIA property that reflects it (ariaLabel, ariaDescribedByElements…) to null, THE slider field SHALL take it off that element. WHEN the product sets an aria- attribute the slider field owns THE slider field SHALL report it in debug builds.

Platform name mapping

Parity does not mean identical APIs. Each platform uses its own idiom for the same contract.

Spec Web SwiftUI Jetpack Compose Flutter React Native
Component tanrei-slider-field TanreiSliderField TanreiSliderField TanreiSliderField SliderField
label · Property label label label labelText label
labelHidden · Property labelHidden labelsHidden labelHidden labelHidden labelHidden
supportingText · Property supportingText supportingText supportingText helperText supportingText
errorText · Property errorText errorText errorText errorText errorText
error · Property error error isError isError error
disabled · Property disabled disabled enabled enabled disabled
required · Property required isRequired required required required
optional · Property optional isOptional optional optional optional
requiredMark · Property requiredMark requiredMark requiredMark requiredMark requiredMark
requiredText · Property requiredText requiredText requiredText requiredText requiredText
optionalText · Property optionalText optionalText optionalText optionalText optionalText
value · Property value value value value value
startValue · Property startValue value value start startValue
range · Property range value value range range
min · Property min bounds valueRange min minimumValue
max · Property max bounds valueRange max maximumValue
step · Property step step step step step
origin · Property origin origin origin origin origin
stops · Property stops showsStops showStops showStops stops
size · Property size size size size size
valueIndicator · Property valueIndicator valueIndicator valueIndicator valueIndicator valueIndicator
valueText · Property valueText valueText stateDescription semanticValue valueText
startValueText · Property startValueText startValueText startStateDescription startSemanticValue startValueText
startLabel · Property startLabel startLabel startContentDescription startSemanticLabel startAccessibilityLabel
endLabel · Property endLabel endLabel endContentDescription endSemanticLabel endAccessibilityLabel
valueHidden · Property valueHidden valueHidden valueHidden valueHidden valueHidden
input · Event input value onValueChange onChanged onValueChange
change · Event change onCommit onValueChangeFinished onChangeEnd onSlidingComplete
Notes Class TanreiSliderField; React SliderField. A custom element with a shadow root that holds its members' own elements, composed as every field element is: <tanrei-field> in the shadow root, and in its default slot one <tanrei-slider> with no label of its own while range is false; the host's label-icon slot is passed on to the Field's. The host is display: block and as wide as its place (SLF-13). What differs here: (1) static formAssociated = true on the host, which carries name, submits what the Slider submits (the value; for a range the start value and then the value under the same name), and resets and restores it — the inner Slider has no name and is outside the form; (2) the shadow root does not delegate focus, because a press on the help or the error text must do nothing (FLD-12): focus() is overridden to go to the first handle, and the Slider's own shadow root delegates as before; (3) input and change leave the shadow root once each with the host as their target, after the host's value and startValue are set; (4) exportparts gives the Slider's documented parts under their own names and the Field's under theirs, with the two members' hosts as the parts field and slider, and the host has no other part of its own; (5) the host writes the Field's value-text from the Slider's value text at every input, in the same task, and joins a range's two in two <bdi> runs with an en dash between; (6) formatValue is a property of the host, never an attribute, ((value: number) => string) | null, null by default, handed to the Slider (field.formatValue = (value) => percent.format(value / 100)). Attributes are kebab-case and are the members': label-hidden, supporting-text, error-text, required-mark, required-text, optional-text, start-value, value-indicator, value-text, start-value-text, start-label, and end-label, value-hidden. No custom property of a member is written by the host: a token set on the host for one instance (--tanrei-comp-field-…, --tanrei-comp-slider-…) reaches the member by inheritance. Words: required-text and optional-text left empty read setWords(), as the Field's do. One level down, the same picture and the same tree: <tanrei-field label="Volume" value-text="40"><tanrei-slider name="volume" value="40"></tanrei-slider></tanrei-field>, with the product writing value-text at each input. With scripting off nothing of it is drawn and nothing is submitted, as for every control with a shadow root. Planned. Not built on this platform yet, nor is this platform's Field: TanreiSliderField(_ label:, value: Binding<Double>, in bounds: ClosedRange<Double> = 0...100, step:, supportingText:, errorText:, error:, required:, optional:, format: ((Double) -> String)? = nil), a view whose body is TanreiField(label, valueText: …) { TanreiSlider(value: $value, in: bounds, …) }; a range is the initializer whose value is a Binding<ClosedRange<Double>> and which takes startLabel and endLabel. labelHidden follows .labelsHidden() and disabled follows .disabled(_:), as the Field's do. One field set apart: .tanreiTheme(_:) on the view. Planned. Not built on this platform yet, nor is this platform's Field: TanreiSliderField(label = "Volume", value = volume, onValueChange = { volume = it }, valueRange = 0f..100f, supportingText = …, isError = …, format: ((Float) -> String)? = null), a composable that calls TanreiField(label, valueText = …) { TanreiSlider(…) }; a range is the overload whose value is a ClosedFloatingPointRange<Float>. enabled is the inverse flag. The Slider's names are kept for what is its own (stateDescription), though the slider field also draws that text. One field set apart: TanreiTheme(…) { } around the call. Planned. Not built on this platform yet, nor is this platform's Field: TanreiSliderField(labelText: 'Volume', value: volume, onChanged: (v) => …, helperText: …, errorText: …, isError: …, format: (double value) => …), a widget that builds TanreiField(labelText:, valueText:, child: TanreiSlider(…)); a range is the named constructor TanreiSliderField.range(start:, end:, onChanged: (start, end) {…}). enabled is the inverse flag; a null onChanged also disables it, as the Slider's does. One field set apart: a TanreiTheme widget around it. Planned. Not built on this platform yet, nor is this platform's Field: <SliderField label="Volume" value={volume} onValueChange={setVolume} supportingText="…" formatValue={(value) => …} />, a component that renders <Field label valueText={…}><Slider … /></Field>; a range adds range and startValue, and both callbacks receive (value, startValue). One field set apart: a provider around it.

Tokens

Token Aliases Resolved (light)
--tanrei-comp-field-counter-gap sys.space.space200 16px
--tanrei-comp-field-error-text-gap sys.space.space50 4px
--tanrei-comp-field-error-text-placement — 0
--tanrei-comp-field-label-icon-gap sys.space.space100 8px
--tanrei-comp-field-label-icon-size sys.icon.small 20px
--tanrei-comp-field-label-gap sys.space.space100 8px
--tanrei-comp-field-motion-state-duration sys.motion.role.state.default 250ms
--tanrei-comp-field-motion-state-easing sys.motion.easing.state cubic-bezier(0.2, 0, 0, 1)
--tanrei-comp-field-requirement-asterisk-gap sys.space.space25 2px
--tanrei-comp-field-requirement-gap sys.space.space100 8px
--tanrei-comp-field-requirement-mark sys.behavior.requirement-mark 0
--tanrei-comp-field-standard-counter-color sys.color.on-surface-variant #4b4b4b
--tanrei-comp-field-standard-disabled-counter-color — #1b1b1b · 38%
--tanrei-comp-field-standard-disabled-error-text-color — #1b1b1b · 38%
--tanrei-comp-field-standard-disabled-error-counter-color — #1b1b1b · 38%
--tanrei-comp-field-standard-disabled-error-label-icon-color — #1b1b1b · 38%
--tanrei-comp-field-standard-disabled-error-label-color — #1b1b1b · 38%
--tanrei-comp-field-standard-disabled-error-required-asterisk-color — #1b1b1b · 38%
--tanrei-comp-field-standard-disabled-error-supporting-text-color — #1b1b1b · 38%
--tanrei-comp-field-standard-disabled-error-value-text-color — #1b1b1b · 38%
--tanrei-comp-field-standard-disabled-label-icon-color — #1b1b1b · 38%
--tanrei-comp-field-standard-disabled-label-color — #1b1b1b · 38%
--tanrei-comp-field-standard-disabled-required-asterisk-color — #1b1b1b · 38%
--tanrei-comp-field-standard-disabled-supporting-text-color — #1b1b1b · 38%
--tanrei-comp-field-standard-disabled-value-text-color — #1b1b1b · 38%
--tanrei-comp-field-standard-error-text-color sys.color.error #cd262f
--tanrei-comp-field-standard-error-counter-color sys.color.on-surface-variant #4b4b4b
--tanrei-comp-field-standard-error-label-icon-color sys.color.on-surface-variant #4b4b4b
--tanrei-comp-field-standard-error-label-color sys.color.on-surface #1b1b1b
--tanrei-comp-field-standard-error-required-asterisk-color sys.color.primary #1b1b1b
--tanrei-comp-field-standard-error-supporting-text-color sys.color.on-surface-variant #4b4b4b
--tanrei-comp-field-standard-error-value-text-color sys.color.on-surface-variant #4b4b4b
--tanrei-comp-field-standard-focused-counter-color — #4b4b4b
--tanrei-comp-field-standard-focused-error-text-color — #cd262f
--tanrei-comp-field-standard-focused-error-counter-color — #4b4b4b
--tanrei-comp-field-standard-focused-error-label-icon-color — #4b4b4b
--tanrei-comp-field-standard-focused-error-label-color — #1b1b1b
--tanrei-comp-field-standard-focused-error-required-asterisk-color — #1b1b1b
--tanrei-comp-field-standard-focused-error-supporting-text-color — #4b4b4b
--tanrei-comp-field-standard-focused-error-value-text-color — #4b4b4b
--tanrei-comp-field-standard-focused-label-icon-color — #4b4b4b
--tanrei-comp-field-standard-focused-label-color — #1b1b1b
--tanrei-comp-field-standard-focused-required-asterisk-color — #1b1b1b
--tanrei-comp-field-standard-focused-supporting-text-color — #4b4b4b
--tanrei-comp-field-standard-focused-value-text-color — #4b4b4b
--tanrei-comp-field-standard-label-icon-color sys.color.on-surface-variant #4b4b4b
--tanrei-comp-field-standard-label-color sys.color.on-surface #1b1b1b
--tanrei-comp-field-standard-required-asterisk-color sys.color.primary #1b1b1b
--tanrei-comp-field-standard-supporting-text-color sys.color.on-surface-variant #4b4b4b
--tanrei-comp-field-standard-value-text-color sys.color.on-surface-variant #4b4b4b
--tanrei-comp-field-supporting-text-gap sys.space.space50 4px
--tanrei-comp-field-value-text-gap sys.space.space200 16px
--tanrei-comp-field-label-typescale sys.typescale.label 500 14px/1.4286
--tanrei-comp-field-supporting-text-typescale sys.typescale.label-small 500 12px/1.3333
--tanrei-comp-field-value-text-typescale sys.typescale.label 500 14px/1.4286

Fixtures

Canonical renderings. Every platform snapshots each fixture under the same id so the results can be compared.

Generated from specs/slider-field.spec.json, tokens/comp/field.tokens.json, design/tokens/

What the web draws differently

  • The element’s shadow root holds a <tanrei-field> with a <tanrei-slider> in it, and nothing else. Importing the element defines both.
  • The element is form-associated. It takes name and form, submits the value — a range the start value and then the value, under the one name; nothing while disabled —, resets to the value and start-value attributes and follows a disabled <fieldset>. Its two members add no entry to the form.
  • input and change are the slider’s CustomEvents with detail.value (and detail.startValue for a range). Their target is the element, and event.target.value is the new value in every listener.
  • formatValue is a property and never an attribute: (value: number) => string, or null.
  • A range’s two value texts are written into the one text of the field’s value-text, with an en dash between them. Each is a run of its own direction — wrapped in a first-strong isolate, U+2068 and U+2069 — unless it is a plain number such as “$100” or “3,400,000”, which is one left-to-right run in either direction already and is written as it is.
  • Parts: field and slider are the two members. Their own parts have the same names here as one level down: label, label-icon, requirement-label, value-text, supporting-text; track, active-track, stop-indicator, container, handle, value-indicator.
  • The element is not focusable itself: focus() goes to the handle, a range’s start handle, and a page’s own <label for> moves focus there.
  • The element has no role. Name it with label — with label-hidden where the label is drawn elsewhere — and never with aria-label, which names nothing here.
  • The attributes are the members’ own: label-hidden, supporting-text, error-text, required-mark, required-text, optional-text, start-value, value-indicator, value-text, start-value-text, start-label; and end-label, value-hidden.
  • Before the element is defined it has no size and shows only a label-icon child. A page that must work without script uses a <label> around a plain <input type="range">.

Guidelines

  • Give the words for a value with formatValue when the bare number would be unclear: a percentage, a currency, a unit.
  • Name both handles of a range, with startLabel and endLabel, in words that hold the words of label: “Minimum price”, “Maximum price” under “Price”.
  • Say in supportingText what the value changes, where the label does not.
  • Say what is refused in words, with error and errorText.
  • Use valueHidden for a value set by feel whose number tells the person nothing.

Don’t

  • Don’t write valueText once in markup for a slider a person can move: the words would be wrong after the first drag. Give formatValue, or write valueText again at every input.
  • Don’t put a slider field inside a field. It is a field already; a debug build says so.
  • Don’t name it with aria-label. Where no label should be drawn, give label and labelHidden.
  • Don’t use valueIndicator="always" to show the value: the value text does that, and the indicator would lie over the label row.
  • Don’t use a slider field for a value that must be exact. Use a number field, alone or beside it.

Accessibility

Role
slider
Labeling
The slider field has no role of its own: assistive technology meets the Slider's handles, each a slider (SLD-19), What the slider field ties together (SLF-5): label is the accessible name of the only handle; a range's two handles are named by startLabel and endLabel; the supporting text with, in error, the error text after it is every handle's description, with optionalText while optional is true; every handle is invalid while error is true and required, or described by requiredText where the role has no required state, while required is true. Each handle's value is said in the words of SLD-18 — valueText, or what the product's function writes, or the platform's number — and the same words are drawn at the end of the label row, where they are kept from assistive technology so that a value is not read twice (FLD-30).
Minimum target
The hit area meets the minimum target size even when the visual size is smaller. minimum 32px · pointer 44px · spacing 8px · touch 48px

Keyboard

Keys Action
Tab / Shift+Tab Moves focus to the handle — for a range to the start handle, then the end handle — and on from it: the stops are the Slider's, and the slider field adds none (SLF-7).
Every other key The Slider's own, as its spec's keyboard table says (SLD-3). The slider field handles no key.

Notes

  • Everything else is a member's and is said in its spec: the Field's rows, requirement marks, error announcement and press on the label (FLD-2 to FLD-12); the Slider's roles, value limits, target size and contrast (SLD-7, SLD-19 and its accessibility notes).
  • A value a person cannot read is a value only some people are told. The handle says its value to assistive technology, and a track does not say it to the eye; the value text at the end of the label row is drawn unless valueHidden says the number means nothing to the person.
  • A number with a unit is words, and the words are the product's: valueText for a value the product writes itself, or one function from a value to its words, given once, which the Slider asks at every change (SLD-18). The slider field writes none, and joins a range's two with an en dash, which is a mark.
  • A slider always has a value, so required does not mean "not empty" here: a product that marks every control of a form as required or optional marks this one too, and says with error and errorText what it refuses (a level of 0, a range too narrow).
  • Dragging is never the only way (WCAG 2.5.7): a press on the track moves the handle to it, and the keys step it (SLD-2, SLD-3). A value that must be entered exactly is a number field, alone or beside a slider.
  • How a state looks is a value decision of the active design system; components read the state's tokens and never compute the effect themselves.

Generated from specs/slider-field.spec.json, tokens/sys/measure.tokens.json

What the component handles

  • Each handle is a slider. One handle is named by label, drawn or not; a range’s two by startLabel and endLabel, and by label where one is missing, which a debug build reports.
  • Each handle is described by the shown supporting or error text, with the optional text while the field is optional, and is exposed as invalid while error is true and as disabled while disabled is true. The web’s slider role has no required state, so a required slider field says requiredText in the description.
  • Each handle says its value in words. The same words are drawn at the end of the label row, where they are kept from assistive technology, so a value is read once.
  • The drawn label, the requirement mark and the value text are not exposed a second time, and a change of the value text is not announced: the handle says its own value.
  • Its focus stops are the slider’s handles — one, or a range’s two — and every key is the slider’s. A press on the label row moves focus to the handle and changes nothing; a press on the help does nothing.
  • While disabled, the value text stays drawn: what a disabled control is set to is still read.
  • Direction, enlarged text and forced colors are each member’s own answer: in a right-to-left layout the frame and the track mirror together and the words of a value keep their own order; at 200% text nothing is cut and nothing scrolls sideways.
  • It has no words of its own. requiredText and optionalText left empty are read from the product’s words by the field.

Known gaps on the web: before the element is defined nothing is drawn, and a range’s two handles are not exposed as one group named by label.

What you need to do

  • Give label, always, and for a range startLabel and endLabel too.
  • Give the value’s words when a number alone would not be understood, and keep them true while the value changes.
  • Say what is refused with errorText. Color is never the only sign.
  • Offer a number field beside the slider where a person must enter an exact value: dragging is never the only way to move a handle, and it is still not a way to type one.