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

ボタングループ

関連する数個のボタンを 1 行または 1 列に並べます。間隔を空けるか、つなげて 1 つの形にし、完了するアクションと取りやめるアクションを人が期待する位置に置き、グループとして名前を付けます。

content_copyMarkdown で表示
カテゴリ
アクション
トークン
comp.button-group
レベル
基礎

概要

Web
tanrei-button-group
schedule
SwiftUI
TanreiButtonGroup
schedule
Jetpack Compose
TanreiButtonGroup
schedule
Flutter
TanreiButtonGroup
schedule
React Native
ButtonGroup
schedule

生成元 docs/status/status.json, specs/button-group.spec.json

Standard と Connected

キャンセル下書きを保存公開format_boldformat_italicformat_underlined

使い方

中に入れるのは、ふだん使っているボタンです。ラベル付きでも、アイコンだけでもかまいません。プロパティもイベントもそのままです。グループがするのは、ボタンを並べること、Connected のときにつなげること、ラベルがあるときに名前を付けることだけです。

Web と React の例は現在の仕様に沿っています。SwiftUI、Compose、Flutter、React Native は追従待ちで、ボタングループの以前の版を提供しています。そこでは、並べ方は 1 行だけで、orientation、fullWidth、separation、順序のフラグはなく、Connected の項目はいつも狭い隙間を空けて並び、アイコンだけの項目は別のアイコンボタンです。追いつくまで、これらの例はその版のものです。

<!-- dismissive は行の先頭へ、confirming は行の末尾へ置かれます。列では位置が入れ替わります。 -->
<tanrei-button-group>
  <tanrei-button variant="outlined" dismissive>キャンセル</tanrei-button>
  <tanrei-button variant="tonal">下書きを保存</tanrei-button>
  <tanrei-button variant="filled" confirming>公開</tanrei-button>
</tanrei-button-group>

<!-- コンテナの幅いっぱいの列。「許可」が「後で」の上に描かれます。 -->
<tanrei-button-group orientation="vertical" full-width>
  <tanrei-button variant="tonal" dismissive>後で</tanrei-button>
  <tanrei-button variant="tonal" confirming>許可</tanrei-button>
</tanrei-button-group>

<!-- label でグループに名前を付けます。トグルはそれぞれ自分の selected を持ちます。 -->
<tanrei-button-group variant="connected" label="文字スタイル">
  <tanrei-button variant="tonal" toggle label="太字"><span slot="icon">format_bold</span></tanrei-button>
  <tanrei-button variant="tonal" toggle label="斜体"><span slot="icon">format_italic</span></tanrei-button>
  <tanrei-button variant="tonal" toggle label="下線"><span slot="icon">format_underlined</span></tanrei-button>
</tanrei-button-group>

<script type="module">
  import '@tanrei/web/components/button-group';
  import '@tanrei/web/components/button';
  // グループ自身はイベントを発火しません。いつもどおりボタンで受け取ります。
  document.querySelector('[label="太字"]').addEventListener('change', (e) => setBold(e.detail.selected));
</script>
import { Button, ButtonGroup } from '@tanrei/react';

// confirming と dismissive は、グループが子要素から読み取る属性です。
<ButtonGroup>
  <Button variant="outlined" dismissive onClick={cancel}>キャンセル</Button>
  <Button variant="tonal" onClick={saveDraft}>下書きを保存</Button>
  <Button variant="filled" confirming onClick={publish}>公開</Button>
</ButtonGroup>

<ButtonGroup orientation="vertical" fullWidth>
  <Button variant="tonal" dismissive onClick={notNow}>後で</Button>
  <Button variant="tonal" confirming onClick={allow}>許可</Button>
</ButtonGroup>

<ButtonGroup variant="connected" label="文字スタイル">
  <Button variant="tonal" toggle selected={bold} label="太字" onChange={(e) => setBold(e.detail.selected)}><span slot="icon">format_bold</span></Button>
  <Button variant="tonal" toggle selected={italic} label="斜体" onChange={(e) => setItalic(e.detail.selected)}><span slot="icon">format_italic</span></Button>
</ButtonGroup>
import Tanrei

TanreiButtonGroup {
    TanreiButton("キャンセル", variant: .outlined) { cancel() }
    TanreiButton("下書きを保存", variant: .tonal) { saveDraft() }
    TanreiButton("公開") { publish() }
}

TanreiButtonGroup(variant: .connected, label: "文字スタイル") {
    TanreiIconButton("太字", isSelected: $bold, variant: .tonal) { Image(systemName: "bold") }
    TanreiIconButton("斜体", isSelected: $italic, variant: .tonal) { Image(systemName: "italic") }
    TanreiIconButton("下線", isSelected: $underline, variant: .tonal) { Image(systemName: "underline") }
}
import io.github.chnotchy.tanrei.components.TanreiButton
import io.github.chnotchy.tanrei.components.TanreiButtonGroup
import io.github.chnotchy.tanrei.components.TanreiButtonGroupVariant
import io.github.chnotchy.tanrei.components.TanreiIconButton
import io.github.chnotchy.tanrei.primitives.TanreiText
import io.github.chnotchy.tanrei.tokens.TanreiButtonVariant
import io.github.chnotchy.tanrei.tokens.TanreiIconButtonVariant

TanreiButtonGroup {
    TanreiButton(text = "キャンセル", onClick = ::cancel, variant = TanreiButtonVariant.Outlined)
    TanreiButton(text = "下書きを保存", onClick = ::saveDraft, variant = TanreiButtonVariant.Tonal)
    TanreiButton(text = "公開", onClick = ::publish)
}

// contentDescription がグループの名前です。Compose にはグループのロールがないため、走査グループになります。
TanreiButtonGroup(variant = TanreiButtonGroupVariant.Connected, contentDescription = "文字スタイル") {
    TanreiIconButton(
        onClick = {},
        contentDescription = "太字",
        variant = TanreiIconButtonVariant.Tonal,
        checked = bold,
        onCheckedChange = { bold = it },
    ) { TanreiText("format_bold") }
    TanreiIconButton(
        onClick = {},
        contentDescription = "斜体",
        variant = TanreiIconButtonVariant.Tonal,
        checked = italic,
        onCheckedChange = { italic = it },
    ) { TanreiText("format_italic") }
}
import 'package:tanrei/tanrei.dart';

TanreiButtonGroup(
  children: <Widget>[
    TanreiButton(variant: TanreiButtonVariant.outlined, onPressed: cancel, child: const Text('キャンセル')),
    TanreiButton(variant: TanreiButtonVariant.tonal, onPressed: saveDraft, child: const Text('下書きを保存')),
    TanreiButton(onPressed: publish, child: const Text('公開')),
  ],
);

TanreiButtonGroup(
  variant: TanreiButtonGroupVariant.connected,
  semanticLabel: '文字スタイル',
  children: <Widget>[
    TanreiIconButton(
      isSelected: bold,
      onPressed: () => setState(() => bold = !bold),
      variant: TanreiIconButtonVariant.tonal,
      semanticLabel: '太字',
      icon: const Icon(AppSymbols.formatBold),
    ),
    TanreiIconButton(
      isSelected: italic,
      onPressed: () => setState(() => italic = !italic),
      variant: TanreiIconButtonVariant.tonal,
      semanticLabel: '斜体',
      icon: const Icon(AppSymbols.formatItalic),
    ),
  ],
);
import { Button, ButtonGroup, IconButton } from '@tanrei/react-native';

<ButtonGroup>
  <Button variant="outlined" onPress={cancel}>キャンセル</Button>
  <Button variant="tonal" onPress={saveDraft}>下書きを保存</Button>
  <Button onPress={publish}>公開</Button>
</ButtonGroup>

<ButtonGroup variant="connected" accessibilityLabel="文字スタイル">
  <IconButton variant="tonal" accessibilityLabel="太字" toggle selected={bold} onSelectedChange={setBold}>
    format_bold
  </IconButton>
  <IconButton variant="tonal" accessibilityLabel="斜体" toggle selected={italic} onSelectedChange={setItalic}>
    format_italic
  </IconButton>
</ButtonGroup>

行か列か、そしてアクションの順序

orientation は、ボタンを 1 行に並べるか(horizontal、既定)、1 列に積むか(vertical)を決めます。列では、どのボタンも列と同じ幅になります。fullWidth を付けると、グループがコンテナの幅いっぱいに広がります。行ではボタンが幅を等分し、列ではどのボタンもその幅になります。シートや幅の狭いパネルの最後に置くアクションに向いた形です。

ボタンに付ける 2 つのフラグが、そのボタンの置き場所をグループに伝えます。これで、2 つの向きの間で順序が食い違いません。

フラグ どんなボタンか 行では 列では
confirming タスクを完了する:OK、保存、次へ、削除 末尾 いちばん上
dismissive タスクを取りやめる:キャンセル、戻る、後で 先頭 いちばん下
なし それ以外 2 つの間に、書いた順で 2 つの間に、書いた順で

同じ 3 つのボタンを行と列で

キャンセル下書きを保存公開キャンセル下書きを保存公開

幅いっぱい:幅を分け合う行と、列

後で許可
後で許可

キーボードフォーカスとスクリーンリーダーは、置かれた順序に従います。だれもが、描かれている順にアクションに出会います。フラグが表すのはタスクとの関係で、語調ではありません。「キャンセル · 削除」では、削除が confirming です。破壊的なアクションは、置き場所ではなく、それ自身の見た目(ボタンの destructive)とラベルで見分けさせます。ダイアログとサイドシートも、同じ 2 つのフラグで自分のアクションを置きます。

区切り線でつなぐか、隙間でつなぐか

Connected のグループがボタンをつなぐ方法は 2 つあります。区切り線(divider)では、ボタンどうしが接し、接する側の角は直角になり、継ぎ目ごとに線が引かれます。隙間(gap)では、ボタンどうしが狭い隙間を空けて並び、向かい合う側の角が小さくなります。どちらにするかは、パーツをつなぐすべてのコンポーネントについてデザインシステムが 1 度だけ決めます(既定のシステムは区切り線です)。デザインシステムはボタングループだけを別にでき、separation(auto、divider、gap)は 1 つのグループだけを変えます。Standard のグループはこれを無視します。

区切り線と隙間でつないだ Connected(行と列)

切り取りコピー貼り付け切り取りコピー貼り付けaddremoveaddremove

区切り線のとき、継ぎ目に線が引かれるのは、両側のボタンが同じ塗りの上にあるときだけです。選択中のトグルと選択されていないトグルの間や、Filled のボタンと Outlined のボタンの間では、塗りの端がすでに継ぎ目を示しているので、線は引かれません。

区切り線でつないだトグル:選択中の項目の隣には線がありません

format_boldformat_italicformat_underlinedformat_strikethrough

仕様

Connected:Outlined、large、無効な項目を含むもの

切り取りコピー貼り付け前へ今日次へ切り取りコピー貼り付け

構成要素

パーツ 説明
1 group The row or column that holds the Buttons. It places and spaces the Buttons, joins them in the connected variant, and names them as a group. It draws nothing of its own but the dividers of a connected group.
2 button A Tanrei Button placed in the group: icon-only, label-only or both, its icon on either side, a toggle or not. It is drawn from its own tokens and keeps its own states, focus, events and semantics.
3 inner-corner · 任意 In the connected variant, a corner of a Button that faces its neighbour. The group sets it.
4 outer-corner · 任意 In the connected variant, a corner at an end of the joined shape: the start corners of the first Button and the end corners of the last in a row, the top corners of the first and the bottom corners of the last in a column. The group sets it.
5 divider · 任意 In the connected variant under divider, the line on the seam between two Buttons that touch. The group draws it; under gap there is none.

プロパティ

プロパティ 型 既定値 説明
variant standard | connected "standard" standard spaces the Buttons apart. connected joins them into one shape with rounded outer ends, by a divider or by a narrow gap (separation), for a closely related set (Bold, Italic, Underline; Previous, Today, Next).
orientation horizontal | vertical "horizontal" horizontal lays the Buttons out in one row; vertical stacks them in one column, every Button as wide as the column. The confirming and dismissive Buttons change places with the orientation (BGR-13, BGR-14).
separation auto | divider | gap "auto" How the Buttons of a connected group are joined. divider: they touch, and a line is drawn on each seam. gap: they stand a narrow gap apart, with tighter corners where they face each other. Auto takes comp.button-group.connected.separation, the design system's answer (divider in the default system). Ignored while variant is standard.
fullWidth boolean false The group fills its container's width and its Buttons share it equally (in a column, each is the container's width). For the actions at the foot of a dialog, a picker or a side sheet.
label string "" The accessible name of the group ("Text style"). Optional: a group of actions that are each named by their own label needs none.

アイテム

このコンポーネントが繰り返すアイテムの種類です。フィクスチャはアイテムを順に並べ、各プラットフォームはそれぞれの流儀で種類ごとに名前を付けます。

button

A Button in the group: the button component, placed, spaced and (when connected) given its corners and minimum size by the group, otherwise drawn and behaving as it does anywhere.

プロパティ 型 既定値 説明
variant filled | tonal | elevated | outlined | text "filled" Its emphasis, as the Button's variant.
size small | medium | large "medium" Its height, as the Button's size. Give every Button of a group the same size.
width default | narrow | wide "default" An icon-only Button's width, as the Button's width. A connected group still widens it to its minimum (BGR-3).
icon string "" The glyph in the Button's icon slot, by its name in the system's icon set. Empty for a label-only Button. It is how a fixture fills that slot; in an application the icon slot is filled as the Button's own spec says.
iconPosition leading | trailing "leading" Which side of the label the icon is on, as the Button's iconPosition.
label string "" Its accessible name, as the Button's label prop. Required for an icon-only Button.
toggle boolean false As the Button's toggle.
selected boolean false As the Button's selected.
disabled boolean false As the Button's disabled.
confirming boolean false The Button completes the task (OK, Save, Next, Delete). The group places it at the end of a row and at the top of a column (BGR-13, BGR-14). It changes the Button's place only, never its look (BGR-19).
dismissive boolean false The Button backs out of the task (Cancel, Back, Not now). The group places it at the start of a row and at the bottom of a column (BGR-13, BGR-14). It changes the Button's place only, never its look (BGR-19).
スロット 説明
label Its label, as the Button's default slot. A fixture item's content is this label; an icon-only item has none.
icon Its glyph, as the Button's icon slot. A fixture fills it through the icon prop.
イベント 説明
click The Button was activated, as the Button's click.
change A toggle Button was switched, as the Button's change.
仕様 Web SwiftUI Jetpack Compose Flutter React Native
アイテム tanrei-button TanreiButton TanreiButton TanreiButton Button
variant · プロパティ variant variant variant variant variant
size · プロパティ size size size size size
width · プロパティ width width width width width
icon · プロパティ slot="icon" icon icon icon icon
iconPosition · プロパティ iconPosition iconPosition iconPosition iconAlignment iconPosition
label · プロパティ label label contentDescription semanticLabel accessibilityLabel
toggle · プロパティ toggle isSelected onCheckedChange isSelected toggle
selected · プロパティ selected isSelected checked isSelected selected
disabled · プロパティ disabled disabled enabled onPressed disabled
confirming · プロパティ confirming tanreiGroupPlacement(.confirming) Modifier.confirming() TanreiButtonGroupItem.placement confirming
dismissive · プロパティ dismissive tanreiGroupPlacement(.dismissive) Modifier.dismissive() TanreiButtonGroupItem.placement dismissive
click · イベント click action onClick onPressed onPress
change · イベント change isSelected onCheckedChange onPressed onSelectedChange
備考 A tanrei-button child, as anywhere: its label is its content and its glyph a tanrei-icon in its icon slot. confirming and dismissive are boolean attributes on the child that the group reads (a MutationObserver re-places the items when they change, BGR-11); the Button itself draws nothing for them. A TanreiButton child, as anywhere. A toggle is a Button given an isSelected binding. The two flags are one modifier, .tanreiGroupPlacement(.confirming) or (.dismissive), a LayoutValueKey the group's layout reads, as .layoutPriority is read by a stack; one enum cannot be both (BGR-18 cannot arise). A TanreiButton child, as anywhere; a toggle is a Button given checked and onCheckedChange, and enabled is disabled's inverse. The two flags are modifiers of the group's scope, Modifier.confirming() and Modifier.dismissive(), parent data the group's layout reads, as RowScope.weight is. A TanreiButton child, as anywhere; a null onPressed disables it, and a non-null isSelected makes it a toggle. The two flags are one ParentDataWidget, TanreiButtonGroupItem(placement: TanreiGroupPlacement.confirming | .dismissive, child:), as Flexible is for a Flex; one enum cannot be both (BGR-18 cannot arise). A Button child, as anywhere. confirming and dismissive are props on the child that the group reads from its children; the Button itself draws nothing for them.

状態

振る舞い

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

ID 要件
BGR-1 WHILE orientation is horizontal THE button group SHALL lay out its items in one row, in the order BGR-13 gives, each at its own size and width unless fullWidth is true (BGR-17): WHILE variant is standard comp.button-group.standard.gap apart and centred on the row's middle; WHILE variant is connected joined as its separation names (BGR-21) — comp.button-group.connected.gap apart under gap, touching under divider — and each stretched to the height of the tallest item (a Button's height is a minimum), so that the joined shape stays even when a label wraps or text is enlarged.
BGR-2 WHILE variant is connected and orientation is horizontal THE button group SHALL give the start corners of the first item and the end corners of the last the radius comp.button-group.connected.horizontal.outer-shape, and each corner that faces a neighbouring item the radius comp.button-group.connected.inner-shape WHILE its separation is gap and no radius, a square corner, WHILE its separation is divider (BGR-21), each capped at half the item's height and eased by sys.shape.corner-smoothing; the item's fill, outline, state layer, ripple and focus ring SHALL follow the resulting shape. WHILE variant is standard THE button group SHALL leave every corner of every item as the item draws it.
BGR-3 WHILE variant is connected THE button group SHALL make each item at least sys.target.touch for touch input and sys.target.pointer for fine pointers along the direction in which it meets its neighbours — wide in a row, high in a column — because joined items cannot extend a hit area over each other: an icon-only Button narrower than that widens its container around its centred icon, and a Button lower than that in a column grows its container around its centred content. Across the other direction the items SHALL extend their hit areas as BTN-5 says. A platform that cannot tell the input type SHALL use sys.target.touch.
BGR-4 WHILE variant is standard and the hit areas that two neighbouring items extend (BTN-5) overlap THE button group SHALL give every press on an item's visible bounds to that item, and a press in the gap between two items to the nearer one, so that neighbouring hit areas meet at the middle of the gap. comp.button-group.standard.gap is what keeps each item's target whole there: at sys.target.touch minus an item's width (in a row) or height (in a column) or more, no hit areas overlap and every item keeps its full target between its neighbours, as the default system's gap does for every Button size; a layer that narrows the gap narrows the targets between items.
BGR-5 THE button group SHALL NOT restyle its items beyond BGR-2, BGR-3, BGR-12, BGR-16, BGR-17, BGR-22 and BGR-23: each item SHALL render from its own tokens, answer hover, focus and press itself, switch itself WHILE its toggle is true, emit its own events, keep its own semantics and be its own Tab stop in the order BGR-15 gives; the group itself SHALL NOT take focus, SHALL NOT handle arrow keys and SHALL keep no selection of its own.
BGR-6 WHILE label is not empty THE button group SHALL expose itself to assistive technology as a group named by label that contains its items; WHILE label is empty THE button group SHALL expose no element of its own, only its items, unless the product names it (BGR-25).
BGR-7 WHERE orientation is horizontal, fullWidth is false and the row is wider than the space its layout gives it THE button group SHALL narrow its labelled Buttons in proportion to their widths, down to the width of their longest word, letting their labels wrap as a Button's label does when its layout gives it less width, and SHALL keep icon-only Buttons at their width; it SHALL NOT wrap the row onto a second line or scroll it, and in debug builds SHALL report a row that still does not fit.
BGR-8 WHEN the layout direction is right-to-left THE button group SHALL, in a row, put its start at the right — the dismissive items at the right and the confirming items at the left (BGR-13), the first placed item's outer corners on its right — and mirror which corners are inner corners; in a column it SHALL keep the top-to-bottom order of BGR-14. Each item's content SHALL follow the layout direction as the Button's does.
BGR-9 WHEN variant, orientation or separation names a value the button group does not define THE button group SHALL render with that prop's default (standard, horizontal, auto), and in debug builds report the unknown value.
BGR-10 WHILE the group holds fewer than two items, or content that is not a Tanrei Button, THE button group SHALL still render it, a single item keeping every corner as it draws it, and in debug builds report it; a platform that cannot inspect its content SHALL state the rule in its README and docs page.
BGR-11 WHEN an item becomes disabled, is added or is removed, or its confirming or dismissive changes, THE button group SHALL place its items again by BGR-13 and BGR-14 and recompute which corners are inner and outer corners, where its dividers are (BGR-24) and which items carry the outer padding of BGR-23, at once, without animation; a disabled item SHALL keep its place, its gap or its dividers, and its corners, and an item that has focus while it moves SHALL keep it.
BGR-12 WHILE orientation is vertical THE button group SHALL lay out its items in one column, top to bottom in the order BGR-14 gives, comp.button-group.standard.gap apart WHILE variant is standard and, WHILE variant is connected, comp.button-group.connected.gap apart under gap and touching under divider (BGR-21), and SHALL make every item as wide as the column — the widest item's width, or the container's width WHILE fullWidth is true — its content centred as a Button centres it in a wider container. WHERE the column is given less width than its widest item every item SHALL take that width and its label SHALL wrap as BGR-7 says; the column SHALL NOT scroll.
BGR-13 WHILE orientation is horizontal THE button group SHALL place its items from start to end in three runs: first the items whose dismissive is true, then the items with neither flag, then the items whose confirming is true; within each run the items SHALL keep the order they were given in. The start is the left in a left-to-right layout and the right in a right-to-left one (BGR-8).
BGR-14 WHILE orientation is vertical THE button group SHALL place its items from top to bottom in three runs: first the items whose confirming is true, then the items with neither flag, then the items whose dismissive is true; within each run the items SHALL keep the order they were given in, the first on top, in either layout direction.
BGR-15 THE button group SHALL make the focus order, and the order in which assistive technology reads its items, the placed order of BGR-13 and BGR-14 — start to end in a row, top to bottom in a column — whatever order the items were given in; a platform whose visual reordering the focus order does not follow (the web's CSS order) SHALL reorder the items themselves in the tree that focus and assistive technology walk.
BGR-16 WHILE variant is connected and orientation is vertical THE button group SHALL give the top corners of the first item and the bottom corners of the last the radius comp.button-group.connected.vertical.outer-shape, and every other corner of every item comp.button-group.connected.inner-shape WHILE its separation is gap and no radius, a square corner, WHILE its separation is divider (BGR-21), each capped at half the item's height and eased by sys.shape.corner-smoothing; the item's fill, outline, state layer, ripple and focus ring SHALL follow the resulting shape.
BGR-17 WHILE fullWidth is true and orientation is horizontal THE button group SHALL take the whole width its container gives it and divide it, less the gaps (none under divider), into equal shares, one per item, whatever each item holds: a label shorter than its share SHALL be centred in it, a label longer SHALL wrap as BGR-7 says, and an icon-only Button SHALL widen its container around its centred icon. WHERE a share is narrower than an item's minimum width (BGR-3, or an icon-only Button's own width) THE button group SHALL give that item its minimum, share the rest equally among the others, and in debug builds report it. WHILE fullWidth is false THE button group SHALL take its natural width.
BGR-18 IF an item's confirming and dismissive are both true THE button group SHALL place it among the items with neither flag and in debug builds report it.
BGR-19 THE button group SHALL NOT change an item's look, emphasis or semantics for its confirming or dismissive: the flags decide its place only. A destructive confirming action (Delete) takes its look from its own variant and its own destructive (BTN-40), and a Button is not made filled, or destructive, by being confirming.
BGR-20 THE button group SHALL take its layout direction from where it is used — the direction of the nearest ancestor that sets one, and the platform's own where none does — and SHALL have no direction setting of its own; WHEN that direction changes while the button group is shown THE button group SHALL draw itself for the new direction at once, without a motion of its own, keeping what it shows and its state.
BGR-21 WHILE variant is connected THE button group SHALL join its items as its separation names: WHILE separation is auto, as comp.button-group.connected.separation names, which follows sys.behavior.separation unless a design system sets it apart; WHILE separation is divider or gap, as that value names, whatever the tokens say. Under gap the items SHALL stand comp.button-group.connected.gap apart with nothing drawn between them and the inner corners of BGR-2 and BGR-16; under divider the items SHALL touch, with square inner corners and the divider of BGR-22 on each seam. WHILE variant is standard THE button group SHALL ignore separation and space its items by comp.button-group.standard.gap. WHEN separation, or the token it follows, changes THE button group SHALL draw the other form at once, without animation, keeping the order, the focus and the state of its items. A platform that cannot draw a choice SHALL fall back to the first value, divider, and state that in its README.
BGR-22 WHILE variant is connected and its separation is divider THE button group SHALL draw, on each seam between two neighbouring items that BGR-24 says carries one, a line comp.button-group.connected.divider.thickness thick, in the color BGR-24 names (comp.button-group.connected.divider.color, or comp.button-group.connected.divider.on-fill.color between two emphasis fills), centred on the seam, over the items' fills and state layers, running along the seam — top to bottom in a row, start to end in a column — and stopping comp.button-group.connected.divider.inset short of each end of it. The line SHALL take no space of its own, SHALL NOT take a press (a press on it goes to the item under the point), SHALL NOT be exposed to assistive technology and SHALL keep its color whatever state its neighbours are in. Each item SHALL draw neither its outline nor the ring of its elevation along an edge that meets a seam, whether or not a line is drawn on it, so that the divider is the only line a seam can carry and the outline of an outlined group runs once around the joined shape, in the color of its rules in the default system; an item's state layer, ripple and focus ring SHALL still follow that item's own shape.
BGR-23 WHILE variant is connected and orientation is horizontal THE button group SHALL add comp.button-group.connected.horizontal.outer-inset to the inline padding of the first item at its start and of the last item at its end, under either separation, so that content beside a rounded outer end looks as far from it as from the tighter corner on its other side: a labelled Button SHALL be wider by that amount with its content moved inward by it, and an icon-only Button SHALL be wider by that amount with its glyph centred in what is left, half of it nearer its neighbour. A single item (BGR-10) SHALL get none; a column SHALL add none, its ends not being full (BGR-16); WHILE fullWidth is true the shares of BGR-17 SHALL be divided first and the padding taken inside the end items' shares. In a right-to-left layout the start is the right, as BGR-8 says.
BGR-24 WHILE variant is connected and its separation is divider THE button group SHALL draw the line of BGR-22 on a seam only WHILE the two items it joins rest on the same fill: the colors from which they render their containers at rest — comp.button.outlined.container.color for an outlined Button, and so on for each variant, and for a toggle the selected or the unselected part of its variant (BTN-15) — are the same color in the active scheme, two containers that have no fill counting as the same. WHILE the two fills differ (a selected toggle beside an unselected one, a filled Button beside an outlined one) THE button group SHALL draw no line on that seam, because the edge of the fill already marks it, and the two items SHALL still draw neither outline nor elevation ring along it (BGR-22). A toggle of the text variant has no fill, selected or not, so its seams keep their lines. THE button group SHALL draw the line in comp.button-group.connected.divider.color, and in comp.button-group.connected.divider.on-fill.color WHILE both items rest on an emphasis fill: a filled Button that is not a toggle, or a selected toggle of the filled, tonal, elevated or outlined variant. It SHALL compare the fills the items have at rest: hover, focus and press SHALL neither add nor remove a line nor change its color, and a disabled item SHALL be compared by the look it has when enabled, so that disabling an item moves no line (BGR-11). WHEN an item's selected, toggle or variant changes THE button group SHALL add, remove or recolor the lines beside it at once, without animation.
BGR-25 WHERE the platform has ARIA attributes (the web), the host carries its group role (BGR-6) itself, so what the product writes on it is not moved, but for a name: WHILE label is not empty THE button group SHALL hold the product's aria-label and aria-labelledby on that host as their data-aria- twins, so that label is its whole name although the platform gives aria-labelledby the precedence, and WHEN label is emptied SHALL give them back as they were written; WHILE label is empty a name the product gives so — aria-label, or aria-labelledby naming an element — SHALL be its name. WHILE label is empty and the product names it so THE button group SHALL be exposed as a group named by that name, as with a label: a group the product names is a named group, and a name on an element with no role would name nothing. WHEN the product removes one, or its data-aria- twin, or sets the ARIA property that reflects it (ariaLabel, ariaLabelledByElements) to null, THE button group SHALL take it away.

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

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

仕様 Web SwiftUI Jetpack Compose Flutter React Native
コンポーネント tanrei-button-group TanreiButtonGroup TanreiButtonGroup TanreiButtonGroup ButtonGroup
variant · プロパティ variant variant variant variant variant
orientation · プロパティ orientation orientation orientation orientation orientation
separation · プロパティ separation separation separation separation separation
fullWidth · プロパティ fullWidth fullWidth fullWidth fullWidth fullWidth
label · プロパティ label label contentDescription semanticLabel accessibilityLabel
備考 <tanrei-button-group variant="connected" orientation="vertical" full-width label="Text style"> holds tanrei-button children. It places them without moving them in the author's DOM: its shadow root has three slots in the order of the orientation (dismissive, unflagged, confirming in a row; confirming, unflagged, dismissive in a column) and assigns each child to one with manual slot assignment, so focus and the accessibility tree, which walk the flat tree, follow the placed order (BGR-15) and CSS order is not used. It sets role group and aria-label on its own element only while label is not empty (ElementInternals is not used for the role: axe-core does not see semantics set through it). It gives a connected item its corners and minimum size through CSS custom properties that Button reads on its container (--tanrei-group-start-radius, --tanrei-group-end-radius, and in a column the top and bottom radii, --tanrei-group-min-width, --tanrei-group-min-height); these are an internal contract between Tanrei elements, not a styling API. Each item also learns its place in the group through an internal controller, because three things cannot be done with custom properties alone: a label that may wrap (BGR-7, BGR-17), corners that never animate and pill ends held to half the measured height (BGR-11), and a hit area that stops at half the gap (BGR-4). It reports other children in debug builds (BGR-10). separation is an attribute (auto, divider, gap); auto reads the name in --tanrei-comp-button-group-connected-separation. Under divider the group draws each rule itself, in its shadow root over the seam, and tells each item through the same internal controller which of its edges meet a seam (no outline, no ring) and how much padding to add at an outer end (BGR-22, BGR-23). Owed on the web: orientation="vertical" must really stack the items (BGR-12, BGR-14, BGR-16) — today the element and the review gallery draw every vertical fixture as a row — and its fixtures must be drawn as columns in the gallery and the baselines. Lagging: ships an earlier revision, a row of Buttons and the retired icon-only kind with no orientation, placement flags or full width. The target: TanreiButtonGroup(variant:, orientation:, fullWidth:, label:) { TanreiButton … }, a custom Layout that places its subviews by BGR-13 and BGR-14 and gives them .accessibilitySortPriority in that order so VoiceOver and keyboard focus follow it (BGR-15). The group passes a connected item its corners and minimum size through an environment value that TanreiButton reads (internal to the package). With a label it is .accessibilityElement(children: .contain) with .accessibilityLabel(label). The group reads its content through a variadic view, as the menu and tabs do, so it reports fewer than two items and content that is not a Tanrei Button in debug builds (BGR-10). Also owed: separation (auto, divider, gap), the divider of BGR-22, the outer padding of BGR-23 and the nine new fixtures; reading comp.button-group.connected.separation as a typed choice needs the native token emitters to write a component's choice of kind as a typed enumeration, which they do not yet. Lagging: ships an earlier revision, a row of Buttons and the retired icon-only kind with no orientation, placement flags or full width. The target: TanreiButtonGroup(variant, orientation, fullWidth, contentDescription) { TanreiButton(…) }, a custom Layout whose items read a CompositionLocal for their corners and minimum size (internal to the library). It places the items by BGR-13 and BGR-14 and sets traversalIndex in that order so TalkBack and focus follow it (BGR-15). With a content description it is semantics { isTraversalGroup = true; contentDescription = … }; Compose has no group role. Debug builds report content that is not a Tanrei Button, and a group of fewer than two items (BGR-10). Also owed: separation (auto, divider, gap), the divider of BGR-22, the outer padding of BGR-23 and the nine new fixtures; reading comp.button-group.connected.separation as a typed choice needs the native token emitters to write a component's choice of kind as a typed enumeration, which they do not yet. Lagging: ships an earlier revision, a row of Buttons and the retired icon-only kind with no orientation, placement flags or full width. The target: TanreiButtonGroup(variant:, orientation:, fullWidth:, semanticLabel:, children: [TanreiButton(…)]), a MultiChildRenderObjectWidget that places its children by BGR-13 and BGR-14 and wraps each in a FocusTraversalOrder and Semantics(sortKey:) in that order (BGR-15); the items read an InheritedWidget for their corners and minimum size (internal to the package). With a label it is Semantics(container: true, label:, explicitChildNodes: true). Children of another type are reported in debug builds (BGR-10). Also owed: separation (auto, divider, gap), the divider of BGR-22, the outer padding of BGR-23 and the nine new fixtures; reading comp.button-group.connected.separation as a typed choice needs the native token emitters to write a component's choice of kind as a typed enumeration, which they do not yet. Lagging: ships an earlier revision, a row of Buttons and the retired icon-only kind with no orientation, placement flags or full width. The target: <ButtonGroup variant orientation fullWidth accessibilityLabel>{…}</ButtonGroup> with Button children, which it renders in the order of BGR-13 and BGR-14 (reordering the children themselves, so focus and the screen reader follow it, BGR-15) and which read a React context for their corners and minimum size (internal to the package). With a label it has role="group" and accessibilityLabel; without one it adds no accessibility element. Children of another type are reported in development builds (BGR-10). Also owed: separation (auto, divider, gap), the divider of BGR-22, the outer padding of BGR-23 and the nine new fixtures; reading comp.button-group.connected.separation as a typed choice needs the native token emitters to write a component's choice of kind as a typed enumeration, which they do not yet.

トークン

トークン 参照先 解決値(ライト)
--tanrei-comp-button-group-connected-divider-color sys.color.outline-variant #000000 · 8%
--tanrei-comp-button-group-connected-divider-inset sys.space.space100 8px
--tanrei-comp-button-group-connected-divider-on-fill-color sys.color.outline #848484
--tanrei-comp-button-group-connected-divider-thickness sys.border.hairline 1px
--tanrei-comp-button-group-connected-gap sys.space.space25 2px
--tanrei-comp-button-group-connected-horizontal-outer-inset sys.space.space50 4px
--tanrei-comp-button-group-connected-horizontal-outer-shape sys.shape.corner.full 9999px
--tanrei-comp-button-group-connected-inner-shape sys.shape.corner.small 6px
--tanrei-comp-button-group-connected-separation sys.behavior.separation 0
--tanrei-comp-button-group-connected-vertical-outer-shape sys.shape.corner.large 12px
--tanrei-comp-button-group-standard-gap — 16px

フィクスチャ

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

生成元 specs/button-group.spec.json, tokens/comp/button-group.tokens.json, design/tokens/

ガイドライン

使う場面

数個のボタンがひとまとまりになるときに使います。フォームの最後の「キャンセル」「下書きを保存」「公開」、エディターの「太字」「斜体」「下線」、カレンダーの「前へ」「今日」「次へ」などです。グループはボタンどうしの間隔を決め、1 組のものならつなげ、役に立つときは名前を付けます。中のボタンはあくまでボタンのままです。

いまの画面や選択に対するアクションを 1 行に並べ、Tab で 1 か所に止まって矢印キーでその中を移るなら、それはツールバーです。主なアクションと、その変化形を並べたメニューをつなげたものは、メニュー付きボタンです。2 つのボタンをつなげた Connected のグループに見えますが、2 つ目の半分は必ずメニューを開きます。

セグメントボタン、ボタングループ、チップ、タブの使い分け

この 4 つは、どれも関連するものを数個、横に並べます。見た目が似ているので混同しやすいのですが、押したときに何が起こるか、キーボードでどう移動するかが違います。

コンポーネント 何か 選択 キーボード 用途
セグメントボタン(Material と cupertino のプリセットのみ。Tanrei システムにはありません) 1 つの問いに答える 2〜5 個の選択肢を、つなげて 1 つにしたコントロール。 自分で持ちます(値で)。1 つ、または複数。 Tab で止まるのは 1 か所。矢印キーで選択肢の間を移動し、単一選択では移動と同時に選びます。 すぐに反映される、答えの決まった設定。日・週・月、左揃え・中央揃え・右揃えなど。
ボタングループ 独立したボタンを並べた行または列。間隔を空けて並べるか、つなげて 1 つの形にします。 持ちません。グループの中のトグルボタンは、それぞれ自分のオン・オフを持ちます。 ボタンごとに Tab で止まります。 関連するアクション。キャンセル・下書きを保存・公開、互いに独立したトグルとしての太字・斜体・下線など。
チップ 折り返すかスクロールする 1 行に並ぶ、独立した小さなコントロール。 絞り込みチップが、それぞれ単独でオン・オフを持ちます。 チップごとに Tab で止まります。 リストの上の絞り込み、返信の候補、ユーザーが入力した項目。
タブ 1 つの主題を分けたビュー。それぞれがパネルを持ちます。 1 つ。いま表示しているビューです。 Tab で止まるのは 1 か所。矢印キーで移動と同時に選びます。 表示する内容の切り替え。概要・アクティビティ・設定など。

迷ったときの見分け方:押すと何かが実行されるならボタングループです。下の内容が入れ替わるならタブです。値を 1 つ設定するならラジオボタンで、セグメントボタンを提供するシステムならセグメントボタンも使えます。選択肢が多いときや互いに独立しているときはチップです。

バリアントの選び方

バリアント 何をするか 用途
Standard(既定) ボタンどうしを、両隣の間でもそれぞれがタッチターゲット全体を保てるだけ離して並べます。角は各ボタンのままです。 一緒に置くが、それぞれ独立しているアクション。フォームの「キャンセル」と「保存」など。
Connected 区切り線か狭い隙間でボタンをつなげ、外側の端が丸い 1 つの形にします(区切り線でつなぐか、隙間でつなぐかを参照)。どのボタンも幅は最小ターゲット以上になり、いちばん高いボタンに合わせて伸びます。 1 つのコントロールとして読める、密接に関連した組。「太字・斜体・下線」「前へ・今日・次へ」など。

Connected のグループで変わるのは、隣と接する側の角だけです。区切り線のときは直角に、隙間のときは小さな角になります。塗り、輪郭、ステートレイヤー、リップル、フォーカスリングは、つなげた形に沿って描かれます。つなげた行の丸い外側の端にはパディングが少し加わり、両端のボタンの中身が均等な余白に見えます。つながったボタンは互いの上にヒット領域を広げられないので、小さなアイコンだけのボタンは、アイコンを中央に置いたまま最小ターゲットの幅まで広がります。

行か列か

ふつうは行にします。列にするのは、ラベルを省略せずに横に並べると収まらないとき(幅の狭いシートや、スマートフォンの幅のパネルのアクションなど)や、地図のズームのコントロールのように、縦に並ぶ内容の横に置くときです。タスクを完了するボタンと取りやめるボタンに印を付けておけば、レイアウトが行と列の間で変わっても、順序は人が期待するとおりのままです。

推奨

  • グループ内のボタンは、すべて同じサイズにします。
  • 強調の使い方はふだんと同じです。Filled ボタンは多くても 1 つにし、たいていは末尾に置きます。
  • 一緒に見て初めて意味の通るボタンなら、グループにラベルを付けます。「文字スタイル」などです。それぞれのボタンが何をするかを自分で表しているアクションの並びなら、ラベルは要りません。
  • Connected のグループでは、ボタンのバリアントをそろえます。つなげた形が 1 つのものとして読めるようにするためです。
  • タスクを完了するボタンに confirming を、取りやめるボタンに dismissive を付け、置き場所はグループに任せます。書く順序は自由です。グループがマークアップの中でボタンを動かすことはありません。
  • separation は、1 つのグループだけを変える必要がない限り auto のままにします。プロダクトの中の、つなげたコントロールの区切り方がそろいます。

非推奨

  • 左揃え・中央揃え・右揃えのように互いに排他的な選択に、グループ内のトグルボタンを使わない。グループはトグルを排他的にしません。選択によって下の内容が変わるならタブを、値を設定するならラジオボタンを使います。セグメントボタンを提供するシステムなら、セグメントボタンも使えます。
  • Tanrei のボタン(ラベル付き、またはアイコンだけ)以外のものをグループに入れない。フィールド、チップ、メニューは入れません。それ以外の内容はデバッグビルドで報告されます。
  • フラグを語調のために使わない。タスクを完了する破壊的な「削除」は confirming で、見た目は自身の destructive から取ります。両方のフラグを付けたボタンは、どちらも付けていないものとして置かれ、報告されます。
  • 行が折り返すことを当てにしない。収まらない行は、ボタンを狭めてラベルを折り返します。2 行目に送ったり、スクロールしたりすることはありません。
  • 1 つのグループの中でサイズを混ぜない。グループはボタンのサイズを変えません。

アクセシビリティ

ロール
group
ラベル付け
label, when given, names the group ("Text style"). Each item is named as it is anywhere: a Button by its label text, an icon-only Button by its label prop.
最小ターゲット
見た目のサイズが小さくても、ヒット領域は最小ターゲットサイズを満たします。 minimum 32px · pointer 44px · spacing 8px · touch 48px

キーボード操作

キー 動作
Tab / Shift+Tab Moves focus to each enabled item in turn in the placed order (BGR-15): start to end in a row, top to bottom in a column.
Enter / Space Activates the focused item, as the Button itself says (a toggle switches).

備考

  • A button group is a layout of actions: each item is its own Tab stop with its own semantics. A row that should be one Tab stop with arrow keys is a toolbar; one choice among several is a single-selection control: tabs where it changes the content below, a radio group where it sets a value, or a segmented button in a system that ships one.
  • A toggle Button in a group keeps its own on/off state; the group does not make its toggles exclusive. One choice among several is a single-selection control: tabs where it changes the content below, a radio group where it sets a value, or a segmented button in a system that ships one.
  • confirming and dismissive are not announced: they decide where a Button is, and focus and reading follow that place, so a screen-reader user meets the actions in the same order a sighted user sees them.
  • The two flags describe the task, not the tone: in "Cancel · Delete" Delete is confirming. A destructive action is told apart by its own look (the Button's destructive) and its label, not by its place.
  • Compose has no group role: the group is a traversal group whose content description is label, and each item keeps its own role.
  • Text size: Buttons in a group grow as they do anywhere; a connected row stretches every item to the tallest, and a column makes every item as wide as the widest.
  • A divider is decoration: it is not exposed, takes no press and is no boundary a person must find. What tells two joined Buttons apart for assistive technology is that each is its own button with its own name; for sight, their content and the line or the gap between them.
  • A seam between a selected and an unselected toggle carries no line: the fill of the selected item ends there, at a contrast far above 3:1 against its neighbour, and that edge is the boundary. The selected state itself is exposed by the toggle (BTN-14), never by the line.
  • In the default system the outline of an outlined group and its rules are the hairline (the divider's color), far below 3:1 against the surface. That is within WCAG 1.4.11: each Button is identified by its label or its icon, not by its edge.

生成元 specs/button-group.spec.json, tokens/sys/measure.tokens.json

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

  • どのボタンも、自分のロール、名前、状態、Tab で止まる位置を保ちます。Tab は置かれた順序でボタンをたどります。行では先頭から末尾へ、列では上から下へです。グループ自身はフォーカスを受け取らず、矢印キーも扱わず、選択状態も持ちません。
  • confirming と dismissive は読み上げられません。ボタンの置き場所を決めるだけで、フォーカスと読み上げはその場所に従います。
  • 区切り線は装飾です。支援技術からは隠され、押しても何も起こりません。つなげた 2 つのボタンを区別させるのは、それぞれが自分の名前を持つ別々のボタンであることです。
  • ラベルがあるとき、グループはそのラベルを名前とし、中のボタンを含むグループとして伝わります。ラベルがなければ、アクセシビリティツリーには何も足しません。
  • Connected のグループでは、どのボタンも幅が最小ターゲット以上になり、ヒット領域は行の上下に最小ターゲットまで広がります。Standard のグループでは、ボタンの見た目の範囲を押せば必ずそのボタンに届き、隙間を押せば近いほうのボタンに届きます。
  • フォーカスインジケーターは、つなげた角も含めて各ボタンの形に沿います。
  • 文字を大きくすると、ボタンはふだんと同じように伸びます。Connected の行はすべてのボタンをいちばん高いものに合わせ、列はすべてのボタンをいちばん幅の広いものに合わせるので、つなげた形がそろったままです。
  • 既定のシステムでは、Outlined のグループの輪郭と区切り線は細い線で、あえて控えめにしてあります。それぞれのボタンを見分けさせるのは輪郭ではなく、ラベルやアイコンです。
  • 項目が 2 個未満の場合、Tanrei のボタン以外の内容がある場合、両方のフラグを付けたボタンがある場合、未知の variant・orientation・separation が指定された場合、幅いっぱいの行でボタンが幅を等分できない場合、ボタンを狭めても行が収まらない場合は、デバッグビルドで報告します。

プラットフォームごとの既知の制約:

  • Web:Connected のアイコンボタンの幅は、マウスのような細かいポインターではポインター用のターゲット、粗いポインターではタッチ用のターゲットになります。項目自体の形がピルのときは、隣に向いた角が、角のスムージングのかかった曲線ではなく円弧で描かれます。ボタンのラベルが折り返すのはグループの中だけで、グループの外では 1 行のままです。行が収まらないことの報告は、グループの大きさや子要素が変わったときに確かめており、項目のラベルが変わったときには確かめていません。
  • SwiftUI にはグループのロールがありません。ラベルのあるグループは、ラベルを名前とし、ボタンを中に含むコンテナになります。タイトルが LocalizedStringKey のボタン(文字列リテラルもこれにあたります)は、いちばん長い単語より細く狭められることがあり、そのときは単語の途中で改行されます。行が収まらないことの報告はデバッグビルドではアサーションの失敗になるため、幅がアニメーションするコンテナのように一瞬だけ狭くなるレイアウトでも、デバッグ中のアプリが止まります。
  • Compose にはグループのロールがありません。ラベルのあるグループは、ラベルを contentDescription とする走査グループになり、各ボタンは自分のロールを保ちます。
  • React Native:2 つのボタンの間の隙間を押したとき iOS と Android がどちらに渡すか、文字を大きくしたときに Connected のボタンがそろって伸びるか、フォーカスがグループに入ったときに VoiceOver と TalkBack がグループ名を読み上げるかは、実機でまだ確かめていません。
  • React Native:React Native のレイアウトには文字の最小内容幅がないため、狭められたボタンがいちばん長い単語より細くなり、単語が途中で改行されることがあります。
  • Standard のグループでは、隣り合うヒット領域は隙間の中ほどで接します。既定のシステムの隙間(16)は、小さいアイコンボタンも含めて、どのアイコンボタンも両隣の間で 48 のタッチターゲット全体を保てる幅です。隙間を狭くしたデザインシステムでは、ボタンの間のターゲットも狭くなります。

利用者側で行うこと

  • アイコンボタンには、それぞれ名前を付けます。グループのラベルは、中のボタンの名前にはなりません。
  • グループは、読み上げの順序の中で、ボタンがあるべき位置に置きます。支援技術は、並んでいる順に 1 つずつボタンをたどります。
  • トグルを互いに排他的にしたいなら、単一選択のコントロールを使います。選択によって下の内容が変わるならタブ、値を設定するならラジオボタン、セグメントボタンを提供するシステムならセグメントボタンです。どれも 1 つを選ぶものとして伝わります。トグルボタンを並べただけでは、そうは伝わりません。