© TOOLS BOX — Next.js / React / TypeScript コードサンプル集

サンプルガイド
←サンプル一覧
reactui-component

Radix UI の Dialog でアクセシブルなモーダルを作る

Radix UI の Dialog コンポーネントを使ってアクセシビリティに配慮したモーダルダイアログを実装する。Tailwind CSS でスタイリングする例も示す。

難易度: 中級·更新: 2026-04-15·
radix-uitailwindcss

対応バージョン

react 19typescript 5radix-ui 1tailwindcss 4

前提環境

React の基本的な使い方(useState, イベントハンドラ)を理解していること

概要

Radix UI の Dialog は WAI-ARIA 準拠のモーダルを提供する headless コンポーネント。 フォーカストラップ・スクリーンリーダー対応・Escape キーでの閉鎖などが組み込まれている。

インストール

npm install @radix-ui/react-dialog

基本実装

import * as Dialog from "@radix-ui/react-dialog";

export function ConfirmDialog() {
  return (
    <Dialog.Root>
      <Dialog.Trigger asChild>
        <button className="rounded bg-blue-600 px-4 py-2 text-sm text-white hover:bg-blue-700">
          削除する
        </button>
      </Dialog.Trigger>

      <Dialog.Portal>
        {/* オーバーレイ */}
        <Dialog.Overlay className="fixed inset-0 bg-black/50 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0" />

        {/* コンテンツ */}
        <Dialog.Content className="fixed left-1/2 top-1/2 w-full max-w-md -translate-x-1/2 -translate-y-1/2 rounded-lg bg-white p-6 shadow-lg focus:outline-none">
          <Dialog.Title className="text-lg font-semibold text-gray-900">
            本当に削除しますか?
          </Dialog.Title>

          <Dialog.Description className="mt-2 text-sm text-gray-500">
            この操作は元に戻せません。
          </Dialog.Description>

          <div className="mt-6 flex justify-end gap-3">
            <Dialog.Close asChild>
              <button className="rounded border border-gray-300 px-4 py-2 text-sm text-gray-700 hover:bg-gray-50">
                キャンセル
              </button>
            </Dialog.Close>

            <button
              onClick={() => console.log("deleted")}
              className="rounded bg-red-600 px-4 py-2 text-sm text-white hover:bg-red-700"
            >
              削除
            </button>
          </div>

          <Dialog.Close className="absolute right-4 top-4 text-gray-400 hover:text-gray-600">
            ✕
          </Dialog.Close>
        </Dialog.Content>
      </Dialog.Portal>
    </Dialog.Root>
  );
}

制御コンポーネント(open を外部管理)

import { useState } from "react";
import * as Dialog from "@radix-ui/react-dialog";

export function ControlledDialog() {
  const [open, setOpen] = useState(false);

  const handleConfirm = () => {
    // 処理実行
    setOpen(false);
  };

  return (
    <Dialog.Root open={open} onOpenChange={setOpen}>
      <Dialog.Trigger asChild>
        <button onClick={() => setOpen(true)}>開く</button>
      </Dialog.Trigger>

      <Dialog.Portal>
        <Dialog.Overlay className="fixed inset-0 bg-black/50" />
        <Dialog.Content className="fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-lg bg-white p-6 shadow-lg">
          <Dialog.Title>確認</Dialog.Title>
          <div className="mt-4 flex gap-3">
            <button onClick={() => setOpen(false)}>キャンセル</button>
            <button onClick={handleConfirm}>確認</button>
          </div>
        </Dialog.Content>
      </Dialog.Portal>
    </Dialog.Root>
  );
}

ポイント

  • Dialog.Portal でモーダルを body 直下にレンダリングする(z-index 問題を回避)
  • asChild を使うと任意の要素をトリガーにできる
  • data-[state=open] / data-[state=closed] でアニメーションを制御できる
  • フォーカストラップは自動的に適用される

注意点

Radix UI はスタイルを持たない headless UI ライブラリ。スタイリングは Tailwind CSS などで行う

関連サンプル

同じテーマや技術スタックを使った実装例

  • Next.js 15 + Zustand でモーダル状態管理を作る

    Zustand を使ってモーダルの開閉状態をグローバルに管理する実装例。複数モーダルへの対応と型安全な設計を示す。

  • Next.js Intercepting Routes で URL 付きモーダルを実装する

    Intercepting Routes((..) 記法)と Parallel Routes を組み合わせ、リスト画面の URL を維持したままモーダルで詳細を表示する実装例。

  • React でコマンドパレット風のキーワードフィルタ UI を実装する

    キーボードショートカットで開くモーダル内で候補リストをリアルタイムフィルタし、キーボードナビゲーションで選択するコマンドパレット UI の実装例。

  • React でフォームフィールドにヘルプテキストとエラーメッセージを表示する

    入力フィールドの下にヘルプテキスト(説明)とバリデーションエラーメッセージを表示し、スクリーンリーダー対応の aria-describedby で関連付けるアクセシブルなフォームパターン。

  • React でフォームラベルに必須・任意バッジを表示する

    フォームラベルの横に「必須」「任意」バッジを表示し、aria-required と組み合わせてアクセシブルなフォーム入力欄を実装するパターン。

関連仕様

このサンプルを理解するのに役立つ仕様や概念

  • FrameworkReactUI 構築のための JavaScript ライブラリ。コンポーネントベースで宣言的に UI を記述できる。
←サンプル一覧に戻る