メインコンテンツへスキップ
menumenu tanreiexpand_morecontrasttranslate
tanreiexpand_more
はじめにWebReactSwiftUIJetpack ComposeFlutterReact Nativeプリセット自分のデザインシステムを作るAI エージェントと Tanrei を使うブランドデザイントークンデザインシステムとカスタマイズTheme Studioカラータイポグラフィアイコン形状エレベーションモーションインタラクション状態振る舞いレイアウトアクセシビリティ言葉カラートークンタイプスケールトークン形状トークンエレベーショントークンモーショントークン状態トークンスペースと寸法のトークンコンポーネントボタンメインアクションボタンセグメントボタンボタングループメニュー付きボタンツールバーコピーボタンチェックボックスラジオボタンスイッチチップメニュースライダースライダーフィールドカレンダーDateTimePickerフィールドグループラジオグループチェックボックスグループセレクトセレクトフィールドメニューバーファイルアップロードファイルピッカー 上級者向けドロップゾーンテキスト入力欄 上級者向けテキストフィールドチップフィールドフィールドコンボボックス 上級者向けコンボボックスフィールド数値入力欄 上級者向け数値フィールドカラー入力欄 上級者向けカラーフィールドワンタイムコード入力欄 上級者向けワンタイムコードフィールド埋め込みテキスト入力欄 上級者向けチャットコンポーザーカード区切り線モーダルレイヤー 上級者向けダイアログリストリスト行ボトムシートサイドシートカルーセルコードブロックテーブルポップオーバーステップアコーディオン説明リスト図アプリシェルページヘッダーツリービュータイムライン画像プレビューハンドルサイズ変更できる枠スクロールエリアバッジプログレスインジケーターメーターナンバーティッカーローディングインジケータースナックバーツールチップキーボードショートカットタグインラインコードコールアウトアバター空の状態タググループスケルトンファイル項目色見本マーキーテキストタブタブビューアプリバーナビゲーションバーナビゲーションドロワー検索リンクページネーション前後のリンクステッパーパンくずリスト目次リンクカードFAB メニューステータスTanrei の作り方コントリビューションライセンスと帰属
ホームコンポーネントスライダーフィールド

スライダーフィールド

目盛りの上で値または値の範囲を選んでもらう、完成した 1 つのフィールドです。ラベルの下にトラックがあり、ラベルの行の末尾に値を言葉で示し、補足の 1 行と、値が受け付けられなかった理由が付きます。

content_copyMarkdown で表示
カテゴリ
選択
トークン
comp.field
レベル
合成
構成要素
Field, Slider

概要

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

生成元 docs/status/status.json, specs/slider-field.spec.json

スライダーフィールド、刻みごとに動くもの、範囲を選ぶもの

スライダーフィールドは、感覚で選び、言葉で読み返す値に使います。120% の文字の大きさ、5 km の距離、10,000 円から 30,000 円の価格などです。スライダーだけでは、描かれるラベルがなく、トラックを見ても値が何に設定されているかはわかりません。スライダーフィールドには、ラベル、言葉で示した値、トラック、補足の 1 行、エラーという、いつもの組み合わせが、そのまま使える形でそろっています。

構成要素は、フィールドとスライダーです。フィールドは枠で、ラベル、必須または任意の印、ラベルの行の末尾にある値のテキスト、補足、エラーを受け持ちます。スライダーはコントロールで、トラックとハンドル、それをユーザーが操作するすべてを受け持ちます。スライダーフィールドが自分で描くものはなく、トークンもありません。プロパティは、自身のものである valueHidden を除いて、どれも 2 つのどちらかのプロパティで、そのまま渡されます。

幅は置かれた場所に合わせて広がり、トラックはその幅いっぱいに伸びます。

Web では <tanrei-slider-field> です。ほかのプラットフォームはまだ実装していません。

使い方

value はハンドルの値で、範囲では終点側のハンドルの値です。startValue は範囲の始点側のハンドルの値です。2 つのイベントはスライダーのもので、input はドラッグ中に値が変わるたびに、change は変更が終わったときに 1 回だけ発火します。どちらが届いた時点でも、フィールドの value と startValue はすでに新しい値になっています。

<form>
  <tanrei-slider-field name="text-size" label="文字の大きさ"
    supporting-text="すべてのページに適用されます。"
    min="50" max="200" step="10" value="120"></tanrei-slider-field>

  <!-- 範囲は、同じ name で start-value、value の順に送信されます。ハンドルにはそれぞれ名前を付けます。 -->
  <tanrei-slider-field name="price" label="価格" range
    min="0" max="50000" step="1000" start-value="10000" value="30000"
    start-label="下限価格" end-label="上限価格"></tanrei-slider-field>
</form>

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

  // 値を表す言葉を、1 回だけ渡します。プロパティであり、属性ではありません。
  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 yen = new Intl.NumberFormat('ja-JP', { style: 'currency', currency: 'JPY' });
  document.querySelector('[name="price"]').formatValue = (value) => yen.format(value);
</script>
import { SliderField } from '@tanrei/react';

<SliderField name="text-size" label="文字の大きさ" supportingText="すべてのページに適用されます。"
  min={50} max={200} step={10} value={size}
  formatValue={(value) => percent.format(value / 100)}
  onInput={(event) => setSize(event.currentTarget.value)} />

言葉で示す値

値は、ラベルの行の末尾に、スライダーがハンドルに与える言葉で描かれます。スクリーンリーダーが読み、値の表示が見せるのと同じ言葉です。言葉は次の順で決まります。

言葉 使われるとき
valueText。範囲の始点側のハンドルでは startValueText 利用者側で言葉を書き、input のたびに書き直すとき。
formatValue が書いたもの 値からその言葉を作る関数を 1 つ、1 回だけ渡したとき。スライダーは、値が変わるたびに、ハンドルごとにこの関数を呼びます。
ページのロケールで書式化した数値 どちらも指定していないとき。

範囲の 2 つの値は、読む順に、半角ダッシュ(–)でつなぎます。右から左へのレイアウトでは、始点の言葉が右側、つまり始点側のハンドルがある側に置かれます。スライダーフィールドが、数値、単位、言葉を自分で書くことはありません。

ラベルと同じ行に収まる値のテキスト、独立した行に移る値のテキスト、値のテキストを隠したフィールド

値のテキストは、ラベルの 1 行目のベースラインにそろえて置かれ、ラベルは残った幅の中で折り返します。そうするとラベルに行の半分も残らないときは、値のテキストがラベルのあとの独立した行に移り、必要ならそこで折り返します。valueHidden を指定すると、値のテキストを描きません。音量や明るさのように、数値がユーザーにとって意味を持たないスライダーに使います。その場合も、ハンドルは支援技術に値を伝えます。

1 つ下の階層

同じフィールドを 2 つの構成要素から自分で書いても、見た目は同じで、支援技術にとっても同じスライダーになります。

<tanrei-field label="文字の大きさ" supporting-text="すべてのページに適用されます。" 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);
  // スライダーフィールドが自分で行うこと。値が変わるたびに、フィールドの値のテキストをスライダーの言葉にします。
  slider.addEventListener('input', () => (field.valueText = slider.shownValueText));
</script>

同じフィールドを自分で書いたもの。フィールドの中にスライダーがあり、値のテキストを 1 回だけ渡しています。上のリスナーがなければ、値に合わせて変わることはありません

スライダーフィールドにない並べ方が必要なときに、1 つ下の階層で書きます。

必要なもの 使うもの
ラベル、言葉で示した値、トラック、補足、エラー スライダーフィールド
スライダーが伝えない値のテキスト(「指定なし」のような文など)、または枠の中に置く自分の要素 フィールドにスライダーを入れ、value-text を自分で書く
トラックだけ。名前は別の場所(表の列、ツールバーのアイコン、プレーヤーの音量コントロールなど)に描かれている スライダーを単独で使い、スライダーの label で名前を付ける
縦向きのスライダー スライダーを単独で使う。スライダーフィールドに向きの指定はありません
わかっている値を入力する 数値フィールド。単独でも、スライダーの隣でも使えます

1 つ下の階層で変わるのは、何をどこに指定するかです。name、value、startValue はスライダーに指定し、フォームに加わるコントロールもイベントが届く先もスライダーになります。label と disabled はフィールドに指定したままにします。フィールドがスライダーに伝えます。範囲の終点側のハンドルには、スライダーの label で名前を付けます。スライダーフィールドでは、これを endLabel と呼びます。

仕様

プロダクトの言葉で示した必須、任意、エラー、無効

それぞれの構成要素が受け持つもの

観点 フィールドから スライダーから
プロパティ label、labelHidden、supportingText、errorText、error、disabled、required、optional、requiredMark、requiredText、optionalText value、startValue、range、min、max、step、origin、stops、size、valueIndicator、valueText、startValueText、startLabel と、スライダーの label にあたる endLabel
イベント — input、change
スロット label-icon —
トークン comp.field.* comp.slider.*

スライダーフィールド自身のプロパティは valueHidden の 1 つです。また、フィールドのプロパティのうち 1 つは、スライダーフィールドが自分で埋めるので、利用者側では指定しません。フィールドの valueText で、スライダーの言葉が入ります。

スライダーは、自分の disabled と orientation を持っています。どちらもスライダーフィールドのプロパティではありません。フィールドの disabled がスライダーを無効にするので、ラベルと値のテキストも一緒に変わります。トラックは常に行の方向に伸びます。スライダーフィールドに縦の向きはありません。

スライダーには常に値があるので、ここでの required は「空ではない」という意味にはなりません。すべてのコントロールに必須か任意かを示すフォームでは、スライダーフィールドにも示します。何を受け付けないか(0 の音量、狭すぎる範囲など)は、利用者側で error と errorText を使って伝えます。エラーになってもトラックは変わりません。エラーを伝えるのは、言葉と、不正という状態です。

ハンドルの動き(ドラッグ、キー、刻み、値の表示)はスライダーのページに、枠の動き(必須の印、値のテキスト、補足、エラーとその読み上げ)はフィールドのページにあります。

1 つのフィールドだけを変える

スライダーフィールドに自分のトークンはありません。枠はフィールドのトークンを、トラックはスライダーのトークンを、どこで設定されていても読みます。1 つだけ変えるには、構成要素のトークンをその要素に設定します。

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

構成要素

構成要素

Web パッケージが描くフィクスチャ default の上に描いています。
パーツ 説明
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.

プロパティ

プロパティ 型 既定値 説明
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.

スロット

スロット 説明
label-icon A glyph before the label. — Field

イベント

イベント 説明
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

状態

振る舞い

EARS 記法による要件です。各プラットフォームの実装は、この ID に対応するテストで検証されます。要件の原文は仕様ファイルのものをそのまま掲載しています。

ID 要件
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.

プラットフォーム別の名前対応

パリティは API が同一であることを意味しません。同じ契約を、各プラットフォームの流儀で表現します。

仕様 Web SwiftUI Jetpack Compose Flutter React Native
コンポーネント tanrei-slider-field TanreiSliderField TanreiSliderField TanreiSliderField SliderField
label · プロパティ label label label labelText label
labelHidden · プロパティ labelHidden labelsHidden labelHidden labelHidden labelHidden
supportingText · プロパティ supportingText supportingText supportingText helperText supportingText
errorText · プロパティ errorText errorText errorText errorText errorText
error · プロパティ error error isError isError error
disabled · プロパティ disabled disabled enabled enabled disabled
required · プロパティ required isRequired required required required
optional · プロパティ optional isOptional optional optional optional
requiredMark · プロパティ requiredMark requiredMark requiredMark requiredMark requiredMark
requiredText · プロパティ requiredText requiredText requiredText requiredText requiredText
optionalText · プロパティ optionalText optionalText optionalText optionalText optionalText
value · プロパティ value value value value value
startValue · プロパティ startValue value value start startValue
range · プロパティ range value value range range
min · プロパティ min bounds valueRange min minimumValue
max · プロパティ max bounds valueRange max maximumValue
step · プロパティ step step step step step
origin · プロパティ origin origin origin origin origin
stops · プロパティ stops showsStops showStops showStops stops
size · プロパティ size size size size size
valueIndicator · プロパティ valueIndicator valueIndicator valueIndicator valueIndicator valueIndicator
valueText · プロパティ valueText valueText stateDescription semanticValue valueText
startValueText · プロパティ startValueText startValueText startStateDescription startSemanticValue startValueText
startLabel · プロパティ startLabel startLabel startContentDescription startSemanticLabel startAccessibilityLabel
endLabel · プロパティ endLabel endLabel endContentDescription endSemanticLabel endAccessibilityLabel
valueHidden · プロパティ valueHidden valueHidden valueHidden valueHidden valueHidden
input · イベント input value onValueChange onChanged onValueChange
change · イベント change onCommit onValueChangeFinished onChangeEnd onSlidingComplete
備考 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.

トークン

トークン 参照先 解決値(ライト)
--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

フィクスチャ

基準となる描画パターンです。全プラットフォームが同じ ID でスナップショットを撮り、結果を比較できるようにしています。

生成元 specs/slider-field.spec.json, tokens/comp/field.tokens.json, design/tokens/

Web での描き方の違い

  • 要素のシャドウルートにあるのは、<tanrei-slider> を入れた <tanrei-field> だけです。要素をインポートすると、2 つとも定義されます。
  • 要素はフォームに関連付けられます。name と form を受け取り、値を送信します。範囲では、同じ name で始点の値、終点の値の順に送信します。無効の間は何も送信しません。リセットすると value 属性と start-value 属性の値に戻り、無効な <fieldset> に従います。2 つの構成要素がフォームに項目を加えることはありません。
  • input と change は、detail.value(範囲では detail.startValue も)を持つ、スライダーの CustomEvent です。イベントのターゲットはこの要素で、どのリスナーでも event.target.value が新しい値です。
  • formatValue はプロパティで、属性はありません。(value: number) => string または null です。
  • 範囲の 2 つの値のテキストは、フィールドの value-text という 1 つのテキストの中に、間に半角ダッシュを挟んで書かれます。それぞれが独立した書字方向を持つ並びになるよう、U+2068 と U+2069(最初の強い文字で方向が決まる分離)で囲みます。ただし「$100」や「3,400,000」のような単純な数値は、どちらの書字方向でも左から右への 1 つの並びになるので、そのまま書きます。
  • パーツ: field と slider が 2 つの構成要素です。構成要素のパーツは、1 つ下の階層と同じ名前です。label、label-icon、requirement-label、value-text、supporting-text と、track、active-track、stop-indicator、container、handle、value-indicator です。
  • 要素そのものはフォーカスを受け取りません。focus() はハンドルに(範囲では始点側のハンドルに)移り、ページの <label for> もフォーカスをそこに移します。
  • 要素にロールはありません。名前は label で付けます。ラベルが別の場所に描かれているときは label-hidden を併せて指定します。aria-label はここでは何にも名前を付けないので、使いません。
  • 属性は構成要素のものと同じです。label-hidden、supporting-text、error-text、required-mark、required-text、optional-text、start-value、value-indicator、value-text、start-value-text、start-label と、end-label、value-hidden です。
  • 要素が定義されるまでは大きさがなく、label-icon の子だけが表示されます。スクリプトなしで動く必要があるページでは、素の <input type="range"> を <label> で囲みます。

ガイドライン

推奨

  • 数字だけでは意味が伝わりにくいときは、formatValue で値を表す言葉を渡します。パーセント、通貨、単位などです。
  • 範囲では、2 つのハンドルの両方に startLabel と endLabel で名前を付けます。label の言葉を含む言葉にします。「価格」の下なら「下限価格」「上限価格」です。
  • ラベルだけでは伝わらないときは、その値で何が変わるかを supportingText で伝えます。
  • 何を受け付けないかは、error と errorText を使って言葉で伝えます。
  • 感覚で選ぶ値で、数値がユーザーに何も伝えないときは、valueHidden を使います。

非推奨

  • ユーザーが動かせるスライダーに、マークアップで 1 回だけ valueText を書かないでください。最初のドラッグのあと、言葉が実際の値と合わなくなります。formatValue を渡すか、input のたびに valueText を書き直します。
  • スライダーフィールドをフィールドの中に入れないでください。すでにフィールドです。デバッグビルドがそう知らせます。
  • aria-label で名前を付けないでください。ラベルを描きたくないときは、label と labelHidden を指定します。
  • 値を見せるために valueIndicator="always" を使わないでください。値を見せるのは値のテキストの役目で、値の表示はラベルの行に重なります。
  • 正確でなければならない値に、スライダーフィールドを使わないでください。数値フィールドを、単独で、またはスライダーフィールドの隣で使います。

アクセシビリティ

ロール
slider
ラベル付け
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 32px · pointer 44px · spacing 8px · touch 48px

キーボード操作

キー 動作
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.

備考

  • 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.

生成元 specs/slider-field.spec.json, tokens/sys/measure.tokens.json

コンポーネントが担うこと

  • ハンドルは、それぞれが 1 つのスライダーです。ハンドルが 1 つのときの名前は label で、描かれていてもいなくても変わりません。範囲の 2 つのハンドルの名前は startLabel と endLabel です。どちらかがないときは label が名前になり、デバッグビルドがそう知らせます。
  • それぞれのハンドルの説明は、表示されている補足またはエラーのテキストで、フィールドが任意の間は任意のテキストが加わります。error が true の間は不正として、disabled が true の間は無効として伝わります。Web のスライダーのロールには必須という状態がないので、必須のスライダーフィールドは requiredText を説明の中で伝えます。
  • それぞれのハンドルが、自分の値を言葉で伝えます。同じ言葉がラベルの行の末尾にも描かれますが、そちらは支援技術から隠されるので、値が読まれるのは 1 回です。
  • 描かれたラベル、必須や任意の印、値のテキストが、もう一度伝わることはありません。値のテキストが変わっても読み上げません。ハンドルが自分の値を伝えるためです。
  • フォーカスが止まる位置はスライダーのハンドルで、1 つ、範囲では 2 つです。キーはどれもスライダーのものです。ラベルの行を押すとフォーカスがハンドルに移り、値は変わりません。補足を押しても何も起きません。
  • 無効の間も、値のテキストは描かれたままです。無効なコントロールが何に設定されているかは、読めるままにします。
  • 書字方向、文字の拡大、強制カラーには、構成要素がそれぞれ応えます。右から左へのレイアウトでは、枠とトラックがそろって左右が入れ替わり、値の言葉は自分の並び順を保ちます。文字を 200% にしても、切れるものはなく、横にスクロールすることもありません。
  • 自分の言葉は持ちません。requiredText と optionalText を空にすると、フィールドがプロダクトの言葉から読みます。

Web での既知の不足は次のとおりです。要素が定義されるまでは、何も描かれません。範囲の 2 つのハンドルは、label を名前とする 1 つのグループとしては伝わりません。

利用者側で行うこと

  • label を必ず指定します。範囲では startLabel と endLabel も指定します。
  • 数字だけでは意味が伝わらないときは、値を表す言葉を渡し、値が変わっても言葉が合っているようにします。
  • 何を受け付けないかは errorText で伝えます。色だけを手がかりにしません。
  • 正確な値を入力する必要があるときは、スライダーの隣に数値フィールドを置きます。ハンドルを動かす手段はドラッグだけではありませんが、それでも値を打ち込む手段にはなりません。