1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Fluent UI 2 の Toast を理解する — Dialog / Field / MessageBar との違い・アクセシビリティ・Fluent UI Blazor 5 比較

1
Posted at

Fluent UI 2 とは 🎨

Fluent UI 2 は、Microsoft の Fluent 2 デザインシステムに沿って UI を設計・実装するための考え方とコンポーネント群です。見た目をそろえるだけではなく、情報の優先順位、操作の流れ、アクセシビリティ、コンテンツ設計まで含めて一貫した体験を作ることを重視しています。

今回扱う Toast も、単なる「右上に出る通知」ではありません。
「どの情報を一時的に見せてよいか」「どの通知は中断してまで伝えるべきではないか」「支援技術の利用者にどう伝わるべきか」を判断するための設計要素です。


はじめに 🌟

保存完了や送信完了のような結果を伝えたいとき、つい何でも Toast で済ませたくなります。ですが Fluent UI 2 の Toast は、便利だけれど強くはない通知面として設計されています。

そのため、重大な確認を求める Dialog、入力欄の局所的なエラーを扱う Field、面全体の状態を継続表示する MessageBar とは、役割がはっきり分かれています。

この記事では、Fluent UI 2 の Toast のガイダンス、種類、動作、レイアウト、アクセシビリティ、コンテンツ設計を整理したうえで、Fluent UI Blazor 5 の Toast 実装と比較します。特に、アクセシビリティとコンテンツの書き方は実務で差が出やすいので、重点的に見ていきます。Fluent UI 2 シリーズ第 39 回として、判断に迷いやすいポイントを実装寄りにまとめます。

参照した一次情報はこちらです。


今回のゴール ✅

  • ✅ Toast を「軽い通知面」として正しく位置づけられるようになる
  • ✅ Dialog / Field / MessageBar と迷わず使い分けられるようになる
  • ✅ Toast の種類、動作、レイアウトの要点を押さえる
  • ✅ アクセシビリティとコンテンツ設計で外してはいけない点を理解する
  • ✅ Fluent UI Blazor 5 との使い方・機能差を把握する

Fluent UI 2 シリーズ一覧 📚

本記事は第 39 回「Toast」です。シリーズの全ラインナップは以下のとおりです。

# コンポーネント URL
1 🪗 Accordion https://qiita.com/tomokusaba/items/6a9a8bd2eb278cffb83b
2 🍞 Breadcrumb https://qiita.com/tomokusaba/items/337b0de5fb5bd238c2a8
3 🗂️ Card https://qiita.com/tomokusaba/items/d9b72ccddacd948aaec4
4 ☑️ Checkbox https://qiita.com/tomokusaba/items/6b43dddf9803786f01ed
5 🔘 Button https://qiita.com/tomokusaba/items/14928a4a52850c4eb09f
6 🏷️ Badge https://qiita.com/tomokusaba/items/1b334d303ed207f956c6
7 👤 Avatar https://qiita.com/tomokusaba/items/db6f552e0e853d0ce0f2
8 🗨️ Dialog https://qiita.com/tomokusaba/items/5dcfce6246b5f5017bec
9 ⌨️ Combobox https://qiita.com/tomokusaba/items/af200d11891210cfc03b
10 ♿ アクセシビリティ実装 https://qiita.com/tomokusaba/items/5603457cab9f2cbb1757
11 🎨 色と WCAG https://qiita.com/tomokusaba/items/c1c5d0faed184fb27da4
12 🏷️ Label https://qiita.com/tomokusaba/items/5fb6729fb6caa207f335
13 💬 Popover https://qiita.com/tomokusaba/items/d5209f1b271ef9ad267e
14 ✏️ Input https://qiita.com/tomokusaba/items/0e2f80eff7e8afbb51ee
15 ➖ Divider https://qiita.com/tomokusaba/items/fd3a94940a76a3a08498
16 🖼️ Image https://qiita.com/tomokusaba/items/6f522ad550c6a853e623
17 📋 Menu https://qiita.com/tomokusaba/items/f2e681262a8e304981c8
18 🧭 Nav https://qiita.com/tomokusaba/items/c323de23e753455eeb7c
19 🔣 Icon https://qiita.com/tomokusaba/items/4446e4ab89b5eaa55987
20 🔗 Link https://qiita.com/tomokusaba/items/bf6f2d4d6cd875042d2a
21 📢 MessageBar https://qiita.com/tomokusaba/items/7152b61fdf418239bbb8
22 🚪 Drawer https://qiita.com/tomokusaba/items/0ea1e4cdea16dcaaf97c
23 📋 Field https://qiita.com/tomokusaba/items/f8adff1e4bdff753a8e4
24 🪪 Persona https://qiita.com/tomokusaba/items/5ca07275ad4a3a685aee
25 📊 Progress Bar https://qiita.com/tomokusaba/items/221c4b8bf08e8b700a84
26 🔽 Dropdown https://qiita.com/tomokusaba/items/7f92dfabf9b32967b2f1
27 🔘 Radio Group https://qiita.com/tomokusaba/items/65e2c45869018cd1f06d
28 ⭐ Rating https://qiita.com/tomokusaba/items/d3b54e147dec86ec7086
29 🔍 Searchbox https://qiita.com/tomokusaba/items/47ecb093c6ffb2f5bebe
30 🔡 Select https://qiita.com/tomokusaba/items/733d0c8e090821b6f0f1
31 📉 Slider https://qiita.com/tomokusaba/items/591d70614596fe9e0d6c
32 🔢 Spin button https://qiita.com/tomokusaba/items/28bd93e45092da9e5bfb
33 🔀 Switch https://qiita.com/tomokusaba/items/3ec4910ba6e9cd8deeb8
34 📑 Tablist https://qiita.com/tomokusaba/items/2cf98c08dc5453806785
35 🏷 Tag https://qiita.com/tomokusaba/items/cde32ec554277a611692
36 🏷️ Tag picker https://qiita.com/tomokusaba/items/cdaed61579a607045c5d
37 🔤 Text (近日公開)
38 📝 Textarea https://qiita.com/tomokusaba/items/f1bd203381707eb5139b
39 🍞 Toast 本記事

Toast とは / 役割 🍞

公式は Toast を次のように説明しています。

A toast communicates the status of an action someone is trying to take or that something happened elsewhere in the app. Toasts are temporary surfaces. Use them for information that's useful and relevant, but not critical.

Fluent 2 Toast usage

つまり Toast は、有用だけれど致命的ではない情報を、一時的に伝えるための面です。保存完了、送信完了、バックグラウンド処理の進行状況、別の場所で起きたイベント通知などが代表例です。

逆に言うと、次のような用途には向いていません。

  • 今すぐ判断してもらわないと進めない
  • 入力欄のその場での修正を促したい
  • ページやカード全体の状態として残し続けたい
  • 見逃すと困る必須アクションを要求したい

Toast は便利ですが、通知を軽く見せるためのものであって、強い注意喚起の代用品ではありません。この前提を持つと、似たコンポーネントとの違いがかなり明確になります。


Dialog / Field / MessageBar との違い 🧭

Fluent UI 2 の Toast は、見た目や目的が似たコンポーネントと混同しやすいです。ただ、実務では次のように割り切って考えると迷いにくいです。

コンポーネント 何をしたいときに使うか Toast を使わない理由
🗨️ Dialog 重要な判断、確認、入力をいったん止めて求めたいとき Toast は作業を止めず一時的に流れるため、重要な意思決定には弱すぎます
📋 Field のエラー 入力欄ごとの誤りを、その場で具体的に直してほしいとき Toast だと「どの欄を直すのか」が弱く、ローカルな修正導線になりません
📢 MessageBar ページやカードなど、面全体の状態を継続的に見せたいとき Toast は消える前提なので、状態の持続表示には向きません

Dialog との違い

Dialog、特に modal / alert dialog は「いまの作業を止めて判断してもらう」ための面です。たとえば削除確認、未保存変更の扱い、重要設定の承認などです。
Toast はその逆で、判断を止めずに結果だけ伝えるときに向いています。

たとえば、次のように分けると実務でぶれにくいです。

  • 「削除してよいですか?」→ Dialog
  • 「削除しました」→ Toast

Field との違い

Field のエラーは、入力中の文脈に密着しています。メールアドレス形式の誤り、必須未入力、桁数不足などは、入力欄の近くで示すべきです。
Toast で「入力エラーがあります」とだけ出しても、どこを直せばよいのか分かりにくくなります。

つまり Field エラーは局所的で修正可能な問題、Toast は局所文脈から少し離れた一時通知です。

MessageBar との違い

MessageBar は、ページ・カード・ダイアログ・ドロワーなど、その面全体の状態を継続的に伝えるコンポーネントです。
Toast は時間依存の軽い通知なので、状態を残し続けるには向いていません。

特に Warning / Error で解決のためのリンクやボタンが必須になるようなケースは、Toast ではなく MessageBar のほうが安全です。Toast は見逃せることが前提だからです。

「利用者がその通知を見逃しても前に進めるか」を判断軸にすると、Toast の誤用をかなり防げます。見逃して困るなら、Dialog・Field・MessageBar を優先したほうが安全です。


Toast の種類 🧩

Fluent UI 2 のガイダンスでは、Toast は大きく 3 種類に分かれます。

種類 役割 代表例
✅ Confirmation 利用者の操作結果を伝える 保存完了、コピー完了、送信完了
⏳ Progress 開始済みの処理の進行を知らせる アップロード中、ダウンロード中、移行中
💬 Communication システムや他者からの出来事を伝える メンション、リマインダー、返信、更新通知

ここで大事なのは、種類(type)と意図 / 緊急度(intent)を分けて考えることです。

  • 種類: confirmation / progress / communication
  • 意図: info / success / warning / error

たとえば confirmation toast でも success とは限りません。保存失敗の confirmation toast なら error になり得ます。
Blazor 側でも ToastTypeToastIntent が分かれているので、この整理はそのまま役に立ちます。


動作(dismissal / progress) ⏱️

1. Timed dismissal

アクション不要の Toast は、7 秒で自動的に閉じるのが基本です。成功通知のように「結果だけ知れればよい」ケースに向いています。

また、マウス操作の利用者は hover でタイマーを一時停止できます。
ただし、アクションを持たない Toast はキーボード中心の利用者に自動でフォーカスされません。ここがかなり重要です。

つまり、「見せれば気づいてもらえるはず」と考えるのは危険です。特にキーボード利用者や支援技術利用者にとって、通知が唯一の導線になってはいけません。

2. Conditional dismissal

進行状況を示す Toast は、条件が満たされるまで残してよいとされています。たとえばアップロード完了や移行完了まで閉じない、という設計です。

React の公式 Progress toast story でも、timeout: -1 にして、処理完了時に明示的に閉じています。

dispatchToast(
  <Toast>
    <ToastTitle>Downloading file</ToastTitle>
    <ToastBody>
      <Text>This may take a while</Text>
      <ProgressBar value={value} max={100} />
    </ToastBody>
  </Toast>,
  { timeout: -1, toastId, intent: "success" }
);

3. Express dismissal

閉じるボタンで利用者が明示的に消せる設計は、その情報を別の場所でも後から見返せる場合だけに留めるべきです。
たとえば通知センターがあり、そこに同じ情報が残るなら安全です。

逆に、Toast でしか参照できない情報を、利用者が閉じられるようにするのは危険です。

4. Determinate / Indeterminate progress

進捗が読めるなら、進捗バー + パーセンテージで determinate progress を使います。
完了時刻を読めないなら、spinner で indeterminate progress を使います。

そして重要なのは、spinner と progress bar を同じ Toast で併用しないことです。
「いまどの粒度で進捗を説明しているのか」がぶれると、利用者はかえって不安になります。


レイアウト 📐

Toast は画面のどこにでも出してよいわけではありません。Fluent UI 2 では、一貫した場所に出すことが強く勧められています。一般的には右上か右下です。

観点 推奨
📍 表示位置 右上または右下など、常に同じ位置
🚫 主コンテンツとの関係 本文や主要操作をふさがない
🧱 件数 1 つの toaster に最大 4 件まで
↕️ 間隔 Toast 間は 16px 程度
🧭 配置戦略 アプリ内で複数の位置を乱用しない

React 側の story では Toaster limit={3} のように上限を設ける例も示されています。
実務でも「出せるだけ出す」のではなく、見える件数を制限して超過分は待たせるほうが安全です。

また、Toaster を複数置ける仕組み自体はありますが、公式の Best practices ではアプリ内で複数 Toaster を使うことは推奨されていません。通知の探索場所がぶれるからです。


アクセシビリティ(重点) ♿

Toast は「通知」なので、アクセシビリティが後回しにされやすいです。ですが実際には、live region とフォーカス設計が重要です。

intent / politeness / aria-live を理解する

Fluent UI 2 では intent に応じて、スタイル、アイコン、aria-liverole が決まります。
特に重要なのは、info 以外の状態は assertive になり、スクリーンリーダーの現在の読み上げを中断し得るという点です。

Intent 伝え方の目安 読み上げ上の注意
ℹ️ Info 補足的、非緊急 割り込みを最小化したい
✅ Success 完了通知 多発すると割り込みが多くなります
⚠️ Warning 問題の予兆 必要最低限に絞るべきです
❌ Error 失敗や異常 乱発すると作業の流れを壊します

assertive は便利ですが、強いからこそ危険です。
複数の assertive な Toast が短時間に連続すると、スクリーンリーダー利用者はいま読んでいた内容を何度も遮られます。結果として、通知の内容以前に、元の作業文脈を見失いやすくなります。

「情報が重要」でも「Toast が正しい」とは限らない

Toast は一時的な面です。だから、重要な情報を載せるほど設計上の緊張が高まります。
もしその情報が本当に重要なら、そもそも Toast ではなく MessageBar や Dialog のほうが適切な可能性があります。

特に次のケースは Toast だけに頼らないほうが安全です。

  • エラーの原因と対処をしっかり読ませたい
  • 操作しないと先へ進めない
  • 後から参照し直す必要がある
  • 画面外で起きた出来事だが見逃してほしくない

永続面が必要な理由

React の ToastDescription.md でも、Toast のアクセシビリティを確保するには、同じ通知を永続面でも参照できるようにするべきと明記されています。代表例は通知センターです。

これが大切なのは、Toast が次の性質を持つからです。

  1. 一定時間で消える
  2. 非アクション Toast はキーボードフォーカスを受けない
  3. 読み上げは一度きりになることがある

つまり、Toast は「いま気づけたら便利」ですが、「後から必ず参照できる」ことは保証しません。だから永続面が必要です。

アクション付き Toast にはキーボード導線を用意する

React の Best practices では、最新のアクション付き Toast にフォーカスを移すキーボードショートカットを作ることも推奨されています。公式 story では Ctrl+M の例が使われています。

<Toaster
  toasterId={toasterId}
  shortcuts={{ focus: e => e.ctrlKey && e.key === "m" }}
/>

この考え方は Blazor でも同じです。
ライブラリが自動で全てを解決してくれるわけではないので、通知へ戻る導線をアプリ側で考える必要があります。

Toast を「見えた人だけが得をする補助通知」として扱うのは問題ありません。ですが、「見えなかったら困る通知」を Toast だけに載せるのは危険です。


コンテンツの説明(重点) ✍️

Toast は小さく、しかも消えます。だから文言設計は、通常の本文よりずっと厳しく考える必要があります。

1. タイトルが主役です

Fluent UI 2 では、利用者が本文を読まなくても要点が分かるよう、最重要メッセージをタイトルに置くことが勧められています。

パターン ポイント
✅ Confirmation / Communication File saved / App was updated 名詞 + 過去形で結果をすぐ伝える
⏳ Progress Uploading file / Migrating your data -ing 形で進行中だと分かる

さらに、タイトルは最初の単語だけ大文字、末尾ピリオドなしが基本です。
日本語でも同じで、文末の句点を省いて短く保つほうが、Toast の面積に合います。

2. 本文は「補足」に徹する

本文には、次の一手や補足説明を入れます。
ただし長く書きすぎると、Toast の役割から外れます。公式ガイダンスでは、できれば 60 文字以内で、ひと目で流し読みできる長さが望ましいとされています。

たとえば次の違いです。

書き方 評価
✅ 短く要点がある Files で確認できます すぐ理解できます
⚠️ 長く説明しすぎる 保存が正常に完了しました。必要に応じて左側メニューの Files 画面に移動して内容をご確認ください Toast としては重すぎます

3. ステータステキストは形式をそろえる

進捗系 Toast では、自由文より一定の型を持たせるほうが理解しやすいです。

  • 10 minutes remaining
  • 65% complete
  • 10 of 17 GB

このように型がそろうと、利用者は文章を読むのではなく状態をスキャンできます。Toast はまさにそのほうが向いています。

4. ボタンはタイトルへの返答にする

ボタンやリンクは、タイトルへの自然な返答になるべきです。
たとえばタイトルが An app was shared with you なら、ボタンは Open app が自然です。

逆に 確認する 開く のような単語だけだと、何を確認するのか、何を開くのかが弱くなります。1〜2 語で十分ですが、対象が曖昧なら名詞を足すべきです。

タイトル よいアクション 微妙なアクション
File saved Open file Open
Meeting starts soon Join meeting Join
Upload failed Retry upload Retry

5. なぜここまで短さにこだわるのか

理由はシンプルで、Toast は「読む面」ではなく「気づく面」だからです。
長文にすると、視覚的にも読み上げ的にも負荷が増え、しかも消えるまでに読み切れない可能性が出ます。

私としては、Toast の文言は「説明」ではなく要約として設計するのが大切だと感じます。


Fluent UI Blazor 5 との違い(usage + features) ⚛️➡️🧱

まず結論から言うと、React の Fluent UI 2 Toast は Toaster を描画して、useToastController で命令的に dispatch する設計です。
一方、Fluent UI Blazor 5 は FluentToastProvider を置いて、ToastService / IToastService 経由で ToastOptions を渡す設計です。

使い方の違い

観点 Fluent UI 2(React) Fluent UI Blazor 5
🧭 入口 <Toaster /> を置いて useToastController() を使う <FluentToastProvider /> を置いて ToastService を使う
🧱 Toast 本体 Toast はレイアウト部品 FluentToastToastService から表示する前提
⚙️ 通知の出し方 dispatchToast(<Toast>...</Toast>, options) ShowToastAsync(options => { ... })
🔄 更新 dismissToast() や state / callback で制御 ShowToastInstanceAsync() + UpdateAsync()
🏷️ 分類 intent と構造で表現 ToastTypeToastIntent を明示
📍 位置 Toaster 側で管理 Position で指定可能
⏱️ 時間制御 timeout を options で指定 Timeout の既定は 7000ms
🖱️ hover / blur ガイダンス上は hover で一時停止できます PauseOnHover / PauseOnWindowBlur は使えるが既定は false
🔘 アクション ToastTitle actionToastFooter DismissAction / QuickAction1 / QuickAction2
📝 補助要素 ToastBody / subtitle / ToastFooter Subtitle / BodyContent / Icon / Inverted

React の最小例

import * as React from "react";
import {
  Button,
  Link,
  Toast,
  ToastBody,
  ToastTitle,
  Toaster,
  useId,
  useToastController,
} from "@fluentui/react-components";

export function SaveToastExample() {
  const toasterId = useId("toaster");
  const { dispatchToast } = useToastController(toasterId);

  const notify = () =>
    dispatchToast(
      <Toast>
        <ToastTitle action={<Link>Undo</Link>}>File saved</ToastTitle>
        <ToastBody>Files で確認できます</ToastBody>
      </Toast>,
      { intent: "success" }
    );

  return (
    <>
      <Toaster toasterId={toasterId} />
      <Button onClick={notify}>Make toast</Button>
    </>
  );
}

React 側では、Toaster が通知の置き場で、useToastController が命令的 API です。
そして Toast 自体は、ToastTitle / ToastBody / ToastFooter を並べるレイアウト部品として扱います。

Blazor の最小例

まず、レイアウト側に provider を置きます。

<FluentToastProvider />
@Body

次に、任意のコンポーネントから ToastService で表示します。

@inject IToastService ToastService

<FluentButton OnClick="ShowSavedToastAsync">Make toast</FluentButton>

@code {
    private async Task ShowSavedToastAsync()
    {
        await ToastService.ShowToastAsync(options =>
        {
            options.Type = ToastType.Confirmation;
            options.Intent = ToastIntent.Success;
            options.Title = "File saved";
            options.Body = "Files で確認できます";
            options.QuickAction1 = "Open file";
            options.Position = ToastPosition.BottomEnd;
            options.Timeout = 7000;
            options.PauseOnHover = true;
        });
    }
}

Blazor 側は ToastOptions に設定を集約する形なので、サービス + オプションの感覚が強いです。
また、ShowToastInstanceAsync() を使えば、進行状況の Toast を更新しながら表示し続けることもできます。

機能差として特に押さえたい点

  1. React は設計ガイダンスが主、Blazor は API の選択肢が主
    React のドキュメントは「どう使うべきか」に比重があります。Blazor はそれを実装するためのプロパティやサービスが充実しています。

  2. Blazor はできてしまうことが多い
    たとえば spinner と progress bar の併用をライブラリが完全には防ぎません。Politeness の上書きもできます。だからこそ、Fluent UI 2 の設計ガイダンスを先に理解しておく必要があります。

  3. Blazor は通知センターを提供しません
    ドキュメントでも、他面での再掲を支援する仕組みはまだない旨が書かれています。つまり、express dismissal は React と同様に慎重に使うべきです。


特筆したいポイント / 実務での注意点 📌

1. Toast を「軽い Dialog」にしない

操作必須の通知を Toast で済ませると、見逃し、後から再確認できないこと、読み上げの割り込みがまとめて起きます。
「軽く見せたい」よりも先に、「見逃されてもよいか」を考えるべきです。

2. type と intent を混同しない

Confirmation / Progress / Communication は役割の分類です。
Info / Success / Warning / Error は意味や緊急度の分類です。ここを分けるだけで、Blazor の ToastTypeToastIntent も理解しやすくなります。

3. 位置は一貫させる

右上に出たり右下に出たりすると、通知の探索コストが上がります。
通知センターが右上にあるなら、Toast も右上に寄せる、というように視線の習慣を作るとよいです。

4. アクションは短く、でも曖昧にしない

短い文言は大事ですが、短すぎて意味が落ちるのは逆効果です。
Retry より Retry uploadOpen より Open app のほうが、Toast らしい短さを保ちつつ意味が伝わります。

5. Blazor では既定値をそのまま鵜呑みにしない

Timeout = 7000 は Fluent UI 2 の timed dismissal と整合していますが、PauseOnHoverPauseOnWindowBlur は既定で false です。
React のガイダンスに近づけたいなら、必要に応じて明示設定したほうが安全です。


まとめ

Fluent UI 2 の Toast は、有用で関連性はあるものの、致命的ではない情報を一時的に伝えるための面です。
強い確認には Dialog、局所的な入力修正には Field のエラー、面全体の状態表示には MessageBar を使う、という切り分けが基本になります。

特に重要なのは次の 4 点です。

  1. Toast は見逃される前提を受け入れた設計で使う
  2. assertive な通知は乱発しない
  3. 永続面や再訪導線を考える
  4. 文言は本文ではなく要約として設計する

Fluent UI Blazor 5 は Toast の API が豊富ですが、豊富だからこそ Fluent UI 2 のガイダンスを先に理解しておく価値があります。
私としては、Toast は「出せる通知」ではなく、「出してよい通知」を選ぶためのコンポーネントだと捉えるのが、いちばん実務に効くと感じます。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?