StepFormDialog

Dialog の variant。複数ステップに分けたフォームを内包するダイアログ。ウィザード形式で複数の操作を順に進めるタスクをダイアログで提供するときに使う。ダイアログ表示中は裏側の領域がスクリムで隠れ、操作を受け付けない。

プレビュー

トリガーを押すとウィザードが開く。戻る (左) / キャンセル + 次へ (右) の 3 ボタン構成。最初の step では 戻る が disabled、最後の step は 次へ が 登録 に切り替わる。

実装例

"use client";

import { useState } from "react";
import { Button } from "@/components/Button";
import {
  Dialog,
  DialogClose,
  DialogContent,
  DialogTitle,
  DialogTrigger,
} from "@/components/ui/dialog";

const STEPS = [
  { title: "顧客情報を入力", body: "..." },
  { title: "問い合わせ内容を選択", body: "..." },
  { title: "内容の確認", body: "..." },
];

export function Example() {
  const [step, setStep] = useState(0);
  const total = STEPS.length;
  const isFirst = step === 0;
  const isLast = step === total - 1;
  const current = STEPS[step];

  return (
    <Dialog onOpenChange={(next) => { if (!next) setStep(0); }}>
      <DialogTrigger asChild>
        <Button variant="primary" size="m">新規登録</Button>
      </DialogTrigger>
      <DialogContent
        showCloseButton={false}
        className="!w-[var(--width-dialog-s)] !max-w-none !gap-0 !p-0 !ring-0 shadow-layer-4 overflow-hidden"
      >
        <div className="p-[var(--spacing-xs)] border-b border-[var(--border-default)] bg-[var(--bg-surface)]">
          <DialogTitle className="!text-[length:var(--font-size-l)] !font-medium !leading-[1.25]">
            {`ステップ ${step + 1} / ${total} : ${current.title}`}
          </DialogTitle>
        </div>
        <div className="p-[var(--spacing-xs)] bg-[var(--bg-surface)] text-[color:var(--text-primary)] tds-text-body-m">
          {current.body}
        </div>
        <div className="p-[var(--spacing-xs)] border-t border-[var(--border-default)] bg-[var(--bg-surface)] flex items-center justify-between">
          <Button
            variant="secondary"
            size="s"
            disabled={isFirst}
            onClick={() => setStep((s) => Math.max(0, s - 1))}
          >
            戻る
          </Button>
          <div className="flex items-center gap-[var(--spacing-xxs)]">
            <DialogClose asChild>
              <Button variant="secondary" size="s">キャンセル</Button>
            </DialogClose>
            {isLast ? (
              <DialogClose asChild>
                <Button variant="primary" size="s">登録</Button>
              </DialogClose>
            ) : (
              <Button
                variant="primary"
                size="s"
                onClick={() => setStep((s) => Math.min(total - 1, s + 1))}
              >
                次へ
              </Button>
            )}
          </div>
        </div>
      </DialogContent>
    </Dialog>
  );
}

仕様

  • primitive: src/components/ui/dialog.tsx をベースに Figma 仕様のヘッダー / ボディ / フッター 3 枠構造でラップする
  • 幅: var(--width-dialog-s) (424px 相当)
  • ヘッダー: p-16 / border-b、タイトル 20px medium。「ステップ X / N : タイトル」形式でステップ位置を明示するのが基本
  • ボディ: p-16、本文 16px。step 内のフォームや説明を配置する
  • フッター: p-16 / border-t、justify-between で 戻る (左) と キャンセル + 次へ (右) を配置
  • 最初の step では 戻る を disabled、最後の step では 次へ を 登録 / 完了 に切り替える
  • ダイアログを閉じるとき、次回開いたときに step を先頭に戻す (onOpenChange で reset)
  • 閉じるボタン(×)は表示しない。キャンセル / Esc / overlay click で閉じる
  • shadow: shadow-layer-4

使い分け

  • StepFormDialog: 複数の入力・選択を順に進める必要があるとき
  • FormDialog (未実装): 1 画面で完結する入力フォーム
  • ActionDialog: 入力を伴わない単純な確認・実行