はじめに 🌟
Fluent UI 2 の Radio Group は、複数の選択肢から 1 つだけを選ぶための UI コンポーネントです。
「どうせラジオボタンでしょう」と思いがちですが、いつ使うか、どのコンポーネントと差別化するか、アクセシビリティをどう担保するかを考えると、設計判断の厚みが出てきます。
参照した一次情報:
- Fluent UI 2 Radio Group Usage
- Fluent UI 2 Checkbox Usage
- Fluent UI 2 Dropdown Usage
- Fluent UI 2 Switch Usage
- Fluent UI Blazor v5 RadioGroup
Fluent UI 2 とは
Fluent UI 2 は、Microsoft の Fluent 2 デザインシステムを実装に落とし込むための UI コンポーネント群とガイダンスです。
単に「Microsoft らしい見た目にする」ためのものではなく、情報設計・操作の一貫性・アクセシビリティ・コンテンツ設計を一体として扱うことを前提にしています。
Radio Group もその考え方の延長にあります。
「いくつかの選択肢から 1 つを選ばせる」という目的は単純に見えますが、何個まで並べるか、縦か横か、初期選択を設けるか、選択肢の文言をどう書くかまで、ガイドが明確に定めています。
過去のシリーズ記事は本記事末尾の一覧を参照してください。
今回のゴール ✅
- Fluent UI 2 の Radio Group の役割と適切な用途を理解する
- Dropdown・Checkbox・Switch との使い分けを整理する
- Fluent UI 2 と Fluent UI Blazor 5 の実装差を把握する
- ガイドライン・動作・レイアウト・アクセシビリティ・コンテンツ設計の要点を押さえる
Radio Group の役割と定義
Fluent UI 2 の公式説明では、Radio Group は「短いリストから 1 つのアイテムを選ぶためのもの」と定義されています。
Radio groups let people select a single item from a short list. Use them in layouts that offer enough space to list up to five options or if it's important to view all options at once.
— Fluent UI 2 Radio Group Usage
ポイントは 2 つです。
- 選択肢がすべて一度に見える状態が前提
- 上限は 5 つ。それ以上になるなら Dropdown を検討する
つまり Radio Group は「少数の選択肢を横断的に比較しながら、最終的に 1 つを決める」操作に向いています。
では、似た役割を持つ Dropdown・Checkbox・Switch とどう使い分ければよいのでしょうか。
Dropdown・Checkbox・Switch との使い分け 🔀
「選ぶ系」のコンポーネントは複数あり、使い分けを間違えると操作性とアクセシビリティの両方が損なわれます。
| コンポーネント | 選択数 | 選択肢の表示 | 即時反映 | 選択肢の上限目安 |
|---|---|---|---|---|
| 🔘 Radio Group | 1 つだけ | 常時表示 | ❌ フォーム送信まで保留 | 2〜5 |
| 🔽 Dropdown | 1 つまたは複数 | 折りたたみ | ❌ フォーム送信まで保留 | 制限なし(多くても可) |
| ☑️ Checkbox | 1 つまたは複数 | 常時表示 | ❌ フォーム送信まで保留 | 2〜5 程度 |
| 🔄 Switch | 1 つ(オン/オフ) | 常時表示 | ✅ 操作と同時に反映 | 2(オン/オフのみ) |
Radio Group を選ぶとき
- 選択肢が 2〜5 個で、すべてを同時に見せたい
- 選択肢が排他的(同時に複数は選べない)
- フォームの一部として送信や確定の操作を挟む設計
Dropdown を選ぶとき
- 選択肢が 6 個以上あってスペースに余裕がない
- モバイルでのフォーム入力が主な対象(ネイティブ
<select>の UX に近い体験)
Radio Group と Dropdown は「1 つを選ぶ」点で共通していますが、選択肢の可視性とスペース効率が異なります。常に選択肢を見せることで比較を促したいなら Radio Group、スペースを節約したいなら Dropdown です。
Checkbox を選ぶとき
- 複数選択を許可したい
- または 1 つの項目を「有効/無効」で切り替えるが、フォーム送信まで確定しない設計
Switch を選ぶとき
- 操作した瞬間に設定が反映される(送信不要)
- オン/オフの 2 択で十分
Switch と Radio Group は見た目が似た場面があるため混同されがちです。Switch は「操作 = 即時反映」、Radio Group は「選んで後で確定」という本質的な違いがあります。設定画面では Switch が多く、フォームの選択肢では Radio Group が適切です。
使い分けの判断軸を押さえたところで、React と Blazor の実装の違いを見ていきます。
Fluent UI 2 と Fluent UI Blazor 5 の比較 ⚖️
Fluent UI 2(React)と Fluent UI Blazor 5 の FluentRadioGroup は、同じ Fluent 2 デザインシステムを基盤にしながらも、実装の考え方にいくつかの違いがあります。
| 観点 | Fluent UI 2(React) | Fluent UI Blazor 5(FluentRadioGroup) |
|---|---|---|
| 🧭 主眼 | ガイダンス+設計中心 | 実装 API 中心 |
| 🏗️ 構成 |
<RadioGroup> + <Radio> の 2 コンポーネント |
<FluentRadioGroup> + <FluentRadio> の 2 コンポーネント |
| 📦 型 | 文字列ベース(value prop) |
ジェネリック型対応(TValue)で string / int / カスタム型を直接バインド |
| 🔗 バインディング |
onChange コールバック |
@bind-Value で双方向バインディング |
| 📋 一括生成 | 個別に <Radio> を並べる |
Items パラメーターでコレクションから一括生成可能 |
| 🏷️ ラベルテンプレート | JSX で自由に記述 |
LabelTemplate フラグメントで Razor 記法のカスタムラベルを使用可能 |
| ↔️ 向き |
layout="horizontal" / layout="vertical"
|
Orientation="Orientation.Horizontal" / Orientation.Vertical
|
| 🔒 disabled |
<Radio disabled> で各アイテムを個別に無効化 |
RadioDisabled="@(item => ...)" で Items から関数ベースで制御可能 |
| ✅ バリデーション | フォームライブラリと組み合わせて実装 |
Required / Message / MessageState で組み込みバリデーション対応 |
| ♿ アクセシビリティ |
aria-labelledby / aria-label の手動設定が基本 |
AriaLabel / Label パラメーターで WAI-ARIA の role="radiogroup" が自動付与 |
Fluent UI 2(React)の実装例
基本的な構成は RadioGroup と Radio を組み合わせるシンプルな形です。
import { RadioGroup, Radio } from "@fluentui/react-components";
export function FruitSelection() {
return (
<RadioGroup defaultValue="apple" label="好きな果物">
<Radio value="apple" label="りんご" />
<Radio value="banana" label="バナナ" />
<Radio value="orange" label="オレンジ" />
<Radio value="kiwi" label="キウイ" />
</RadioGroup>
);
}
値の変化を取得したい場合は onChange を使います。
import { RadioGroup, Radio, RadioGroupOnChangeData } from "@fluentui/react-components";
export function FruitSelection() {
const handleChange = (
_: React.FormEvent<HTMLDivElement>,
data: RadioGroupOnChangeData
) => {
console.log("選択された値:", data.value);
};
return (
<RadioGroup defaultValue="apple" label="好きな果物" onChange={handleChange}>
<Radio value="apple" label="りんご" />
<Radio value="banana" label="バナナ" />
<Radio value="orange" label="オレンジ" disabled />
<Radio value="kiwi" label="キウイ" />
</RadioGroup>
);
}
Fluent UI Blazor 5 の実装例
Blazor では @bind-Value で双方向バインディングが使えます。
<FluentRadioGroup @bind-Value="@Fruit" Label="好きな果物" Wrap="true">
<FluentRadio Value="@("apple")" Label="りんご" />
<FluentRadio Value="@("banana")" Label="バナナ" />
<FluentRadio Value="@("orange")" Label="オレンジ" Disabled="true" />
<FluentRadio Value="@("kiwi")" Label="キウイ" />
</FluentRadioGroup>
<FluentLabel>選択中: @Fruit</FluentLabel>
@code {
string Fruit = "banana";
}
Items パラメーターを使うと、コレクションから自動でラジオボタンを生成できます。
<FluentRadioGroup Label="担当者"
Orientation="Orientation.Vertical"
Items="@People"
@bind-Value="@SelectedPerson"
RadioLabel="@(p => p.Name)"
RadioValue="@(p => p.Id)"
RadioDisabled="@(p => !p.IsActive)" />
@code {
record Person(string Id, string Name, bool IsActive);
Person[] People = new[]
{
new Person("001", "田中 太郎", true),
new Person("002", "鈴木 花子", true),
new Person("003", "佐藤 一郎", false),
};
Person? SelectedPerson;
}
Fluent UI Blazor 5 特有の注意点 ⚠️
Blazor の FluentRadioGroup でジェネリック型を使う際には、型の一致に関するルールがあります。
{{! 文字列リテラルのバインド方法(必ずこの記法を使う) }}
<FluentRadio Value="@("apple")" Label="りんご" />
{{! nullable 型の場合はキャストが必要 }}
<FluentRadio Value="@((int?)1)" Label="1番" />
FluentRadioGroup の TValue と FluentRadio の Value の型が一致しない場合、コンパイルエラーではなくランタイムエラー(InvalidOperationException)が発生します。nullable 型を使う際は TValue="int?" を明示するか、各 FluentRadio の Value を明示的にキャストする必要があります。
実装差分を把握したところで、公式ガイドラインと動作・レイアウトの要点を確認します。
動作・レイアウトのガイドライン 📐
デフォルト選択を設ける
公式ガイドでは、Radio Group には必ずデフォルト選択を設けることが推奨されています。
デフォルト選択には、ユーザーにとって「最も論理的な回答」または「最も安全な選択肢」を先頭に置くのが原則です。
Present a selected option in radio groups by default. The default selection should be placed first and should be the most logical response.
— Fluent UI 2 Radio Group Usage
ただし、「どれも選ばない」という選択肢が有効な文脈では、「なし(None)」を選択肢として含めることも推奨されています。強制的に何かを選ばせる設計が必ずしも正しいわけではありません。
選択肢は論理的な順序で並べる
- 最も選ばれやすいものから順に並べる
- 単純なものから複雑なもの、リスクが低いものから高いものへの順序も有効
- アルファベット順・五十音順はローカライズ後に順序が変わるため避ける
キーボード操作
Radio Group は WAI-ARIA の role="radiogroup" を持つため、標準的なキーボード操作が定義されています。
| キー | 動作 |
|---|---|
Tab |
グループ全体へフォーカスを移動(未選択時は最初の項目、選択済みなら選択中の項目) |
↑ / ←
|
前の選択肢へ移動して選択 |
↓ / →
|
次の選択肢へ移動して選択 |
Space |
フォーカスがある選択肢を選択 |
選択肢間の移動には矢印キーを使います。Tab キーは Radio Group 全体を 1 つの単位として扱います。これは ARIA のベストプラクティスに沿った設計で、キーボードユーザーがグループを素早く通過できます。
レイアウト:縦か横か
| 配置 | 特徴 | 推奨場面 |
|---|---|---|
| ↕️ 縦(Vertical、推奨) | スキャンしやすく、ローカライズ後の文字幅変動に強い | デフォルト |
| ↔️ 横(Horizontal) | スペースを節約できる | 2〜3 択でラベルが短い場合 |
公式ガイドは縦配置を優先としています。横配置は選択肢が少なく(2〜3 個)、ラベルが短い場合に限って有効です。
横配置時のラベル位置は「選択肢の横(After)」または「選択肢の下(Below)」を選べます。
React での横配置:
<RadioGroup layout="horizontal" label="配送方法">
<Radio value="standard" label="通常配送" />
<Radio value="express" label="速達" />
</RadioGroup>
Blazor での横配置:
<FluentRadioGroup @bind-Value="@Delivery"
Orientation="Orientation.Horizontal"
Label="配送方法">
<FluentRadio Value="@("standard")" Label="通常配送" />
<FluentRadio Value="@("express")" Label="速達" />
</FluentRadioGroup>
レイアウトの指針を踏まえたうえで、アクセシビリティの要点を整理します。
アクセシビリティ ♿
Radio Group のアクセシビリティは、グループ全体のラベルと個別の選択肢ラベルの 2 層で成り立っています。
グループラベルは必須
スクリーンリーダーは Radio Group を読み上げる際、まずグループ全体のラベルを伝えてから個々の選択肢を読み上げます。
グループラベルが設定されていないと、ユーザーは「何を選ぶための選択肢なのか」を理解できなくなります。
React での例:
{{! ✅ 良い例: label prop でグループラベルを明示 }}
<RadioGroup label="配送先の都道府県">
<Radio value="tokyo" label="東京都" />
<Radio value="osaka" label="大阪府" />
</RadioGroup>
{{! ✅ 良い例: 視覚的に見出しがある場合は aria-labelledby を使う }}
<h2 id="delivery-heading">配送先の都道府県</h2>
<RadioGroup aria-labelledby="delivery-heading">
<Radio value="tokyo" label="東京都" />
<Radio value="osaka" label="大阪府" />
</RadioGroup>
Fluent UI Blazor 5 では Label パラメーターが role="radiogroup" の aria-labelledby に自動的に対応します。
AriaLabel パラメーターを使えば、視覚的なラベルなしで読み上げ用テキストのみを設定することもできます。
フォーカス管理
公式ガイドによると:
- 未選択の状態でタブ移動してきた場合、フォーカスは最初の選択肢に移ります
- 選択済みの状態でタブ移動してきた場合、フォーカスは選択中の選択肢に移ります
この動作は WAI-ARIA の radiogroup パターンに準拠しており、Fluent UI 2 のコンポーネントはこの挙動を標準で実装しています。
When tabbing, focus will fall on the first option if no options are selected. If there is a selection, focus will fall on that option first.
— Fluent UI 2 Radio Group Usage
disabled の扱い
disabled な選択肢は、スクリーンリーダーに「存在するが操作できない」と読み上げられます。
なぜその選択肢が無効なのかを補足する情報(サブテキストや説明)を添えると、ユーザーの混乱を防げます。
{{! 無効化した選択肢にはサブテキストで理由を添える }}
<Radio
value="premium"
label="プレミアムプラン"
disabled
subtext="現在このプランは提供終了しています"
/>
アクセシビリティの次は、ラベルや選択肢文言の書き方を整理します。
コンテンツ設計 ✍️
コンテンツの質は、Radio Group の使いやすさに直結します。
ラベルは短く、明確に
個々の選択肢のラベルは、できる限り短く・具体的に書きます。
フレーズ(語句)を優先し、完全な文(センテンス)は使いません。
ラベルが長くなる場合は折り返しが発生しますが、省略記号(…)で切ることは禁止されています。
Never truncate radio text with an ellipsis.
— Fluent UI 2 Radio Group Usage
文頭のみ大文字(Sentence case)
英語の場合は先頭の単語だけ大文字にします(例: Next week、Send immediately)。
タイトルケース(Next Week)は使いません。
日本語では通常影響ありませんが、英語混じりの UI では意識する必要があります。
末尾の句読点は使わない
各選択肢の末尾にはコロン(:)やピリオド(.)を付けません。
グループのラベル(ヘッダーになる文言)も同様です。
サブテキストの使い方
選択肢の説明がどうしても必要な場合は、サブテキストを使います。
ただし、すべての選択肢に説明が必要な場合のみ使うのが原則です。
一部の選択肢だけに説明が必要な場合は、Info Label とツールチップの組み合わせが推奨されます。
サブテキストは完全な文(センテンス)として書きます。日本語では句点(。)で終え、英語では period(.)で終えます。
<Radio
value="standard"
label="通常配送"
subtext="3〜5 営業日以内にお届けします。"
/>
<Radio
value="express"
label="速達配送"
subtext="翌営業日中にお届けします。追加料金が発生します。"
/>
「なし(None)」の選択肢
「選択しない」ことを許容する設計では、「なし」や「指定しない」の選択肢を明示的に含めます。
ラジオボタンは一度選択すると通常は未選択に戻せないため、「どれも選ばない」という状態を表す選択肢を用意することがアクセシビリティと UX の両面で重要です。
<RadioGroup label="優先度" defaultValue="none">
<Radio value="none" label="指定しない" />
<Radio value="low" label="低" />
<Radio value="medium" label="中" />
<Radio value="high" label="高" />
</RadioGroup>
してはいけないこと 🚫
| ❌ やってはいけないこと | ✅ 代わりにすること |
|---|---|
| グループラベルなしで Radio Group を配置する |
label / aria-labelledby を必ず設定する |
| ラベルを省略記号(…)で切る | ラベルを短く書き直すか折り返しを許容する |
| 選択肢の順序をアルファベット順にする | 論理的な順序(頻度・重要度・リスク)にする |
| 1 つだけの選択肢で Radio Group を使う | Checkbox(単体)または Switch を使う |
| 選択肢に長い文章(センテンス)を使う | フレーズ(語句)で簡潔に書く |
| 一部の選択肢だけにサブテキストを付ける | 全選択肢に統一するか Info Label を使う |
おわりに 🎉
Radio Group は「単純なラジオボタン」ではなく、選択肢の見せ方・数・順序・ラベルの書き方・アクセシビリティが一体になって初めて機能するコンポーネントです。
特に Dropdown・Checkbox・Switch との使い分けは、視覚的な見た目だけで判断せず、即時反映かどうか・排他的かどうか・選択肢の数の 3 軸で考えると整理しやすくなります。
Fluent UI Blazor 5 の FluentRadioGroup は、ジェネリック型バインディングや Items パラメーターによる一括生成など、React 版にはない便利な機能を備えています。ただし型の不一致がランタイムエラーになる点は要注意です。
次回も引き続き Fluent UI 2 シリーズを進めていきます。
関連記事:
- Fluent UI 2 の Checkbox を理解する
- Fluent UI 2 の Dropdown を理解する
- Fluent UI 2 の Field を理解する
- Fluent UI 2 で始めるアクセシビリティ実装
これまでの Fluent UI 2 シリーズ(公開済み)📚
※ 2026-06-16 時点で公開済みのシリーズ記事です。