フィードバック

フィードバックの概要

処理結果、進行状況、注意、完了をユーザーへ返すためのコンポーネント群です。通知の強さ、表示時間、操作を求めるかどうかで使い分けます。

カテゴリ概要

コンポーネント一覧

各コンポーネントの詳細ページへ移動して、プレビュー、コード、プロパティを確認できます。

アラート

Alert

注意を促すためのコールアウトを表示します。

詳細を見る

バナー

Banner

ページ全体に関係するお知らせや状態を横長のバーで表示します。

詳細を見る

通知センター

NotificationCenter

通知の一覧と管理用の UI です。

詳細を見る

進捗バー

Progress

タスクの進捗を示すインジケーターです。

詳細を見る

進捗ウィジェット

ProgressWidget

進捗値、補足文、進捗バーをカードとしてまとめて表示します。

詳細を見る

安全バナー

SafetyBanner

重要な警告や安全確認を強調し、必要に応じて明示的な確認状態を管理します。

詳細を見る

スピナー

Spinner

処理中であることを示すインジケーターです。

詳細を見る

ステータスバー

StatusBar

ステータスや情報を表示するバーです。

詳細を見る

ステータス画面

StatusScreen

404、エラー、オフライン、権限なし、メンテナンス、公開前など、全画面の状態フィードバックを表示します。

詳細を見る

ステッパー

Stepper

複数ステップの進行状況を、完了・現在地・未完了の状態で示すコンポーネントです。

詳細を見る

追従告知バー

StickyNoticeBar

アクションにつなげたいサイト告知を、明示的に選んだ上端または下端の一方へ追従表示します。

詳細を見る

トースト

Toast

一時的に表示する短いメッセージです。

詳細を見る

トーストプロバイダ

ToastProvider

トーストの表示と管理を行います。

詳細を見る

補足情報

一覧でコンポーネントを選んだあとに確認する、カテゴリ全体の責務、共通ルール、使い分けです。

このカテゴリの責務

ページや操作の結果を、ユーザーが次に判断できる粒度で返します。永続表示、短時間表示、進行中表示を混ぜずに選びます。

このページの使い方

まずカテゴリの責務を確認し、迷いやすい使い分けから該当コンポーネントへ移動します。

パターンで確認する場面

フォーム送信、メディア操作、チャット、管理画面など、複数コンポーネントを組み合わせた場面で通知の強さと位置を確認します。

フィードバック系の共通ルール

カテゴリ内で共通して守るべき判断基準です。

状態色だけで意味を伝えず、タイトルや説明で何が起きたかを明示します。

操作できない状態や失敗時は、理由と次の行動を近くに置きます。

迷いやすい使い分け

似ているコンポーネントを選ぶ時の入口です。

ページ内に残す注意は Alert、画面上部の横長通知は Banner、短時間の完了通知は Toast を使います。

単純な進捗は Progress、進捗に状態や操作が伴う場合は ProgressWidget を使います。

避ける使い方

フィードバックは目立たせるだけでなく、次に何をすべきかを伝える必要があります。

色だけで成功、警告、失敗を伝える。

破壊的な操作や復旧不能な操作を Toast だけで済ませる。

処理中の残り作業や失敗理由を、進捗バーから切り離して遠くに置く。

まとめて使う見本

この分類のコンポーネントをまとめて、取り込みの進み具合と結果を伝える1画面を組んだ例です。そのまま貼り付けて動きます。

import { useState } from "react";
import {
    Alert,
    Banner,
    Button,
    Card,
    CardContent,
    CardHeader,
    CardTitle,
    Progress,
    Spinner,
    Stepper,
} from "@gunjo/ui";

const STEP_LABELS = ["読み込み", "検証", "取り込み"];

const STEP_MESSAGE = [
    "ファイルを読んでいます。このタブは閉じないでください。",
    "1行ずつ、決めた形式に合っているか確かめています。",
    "通った行をワークスペースに書き込んでいます。",
];

export function ImportJobStatus() {
    const [step, setStep] = useState(1);
    const [dismissed, setDismissed] = useState(false);

    const running = step < STEP_LABELS.length;
    const percent = Math.round(((step + 1) / (STEP_LABELS.length + 1)) * 100);

    return (
        <Card className="max-w-2xl">
            {dismissed ? null : (
                <Banner
                    variant="info"
                    onDismiss={() => setDismissed(true)}
                    dismissLabel="閉じる"
                >
                    取り込みは裏で進みます。このページを離れても大丈夫です。
                </Banner>
            )}
            <CardHeader>
                <CardTitle>顧客データの取り込み</CardTitle>
            </CardHeader>
            <CardContent className="space-y-6">
                <Stepper
                    steps={STEP_LABELS.map((label, index) => ({
                        label,
                        state:
                            index < step ? "completed" : index === step ? "current" : "upcoming",
                    }))}
                />

                <div className="space-y-2">
                    <div className="flex items-center gap-2 text-sm text-muted-foreground">
                        {running ? <Spinner size="sm" /> : null}
                        <span>{running ? STEP_MESSAGE[step] : "取り込みが終わりました。"}</span>
                    </div>
                    <Progress
                        value={percent}
                        label="取り込みの進み具合"
                        valueText={percent + "% 完了"}
                        tone={running ? "primary" : "success"}
                    />
                </div>

                {step === 1 ? (
                    <Alert
                        variant="warning"
                        title="12行に確認が必要です"
                        description="メールアドレスが無い行は取り込みません。"
                    />
                ) : null}

                {running ? null : (
                    <Alert
                        variant="success"
                        title="1,204件を取り込みました"
                        description="残る12行は取り込まず、一覧として書き出せます。"
                    />
                )}

                <div className="flex gap-3">
                    <Button
                        onClick={() => setStep(Math.min(step + 1, STEP_LABELS.length))}
                        disabled={!running}
                    >
                        次へ進む
                    </Button>
                    <Button variant="outline" onClick={() => setStep(0)}>
                        最初からやり直す
                    </Button>
                </div>
            </CardContent>
        </Card>
    );
}

設計の判断

通知や状態表示のコンポーネントをいつ使い、いつ使わないかは、UIXHERO の「UIコンポーネント完全ガイド」にある「カテゴリ 07|フィードバック・状態」の節にまとめています。画面に残して読ませるのか、短い時間だけ出して消すのかで、選ぶコンポーネントが変わります。

UIXHERO: UIコンポーネント完全ガイド(カテゴリ 07|フィードバック・状態)(新しいタブで開きます)