Modal
Modalは、メインコンテンツの上にオーバーレイ表示されるダイアログコンポーネントです。通常のModalと、ユーザーの確認が必要なAlertModalの2タイプを提供します。
2
Types
6
Sizes
2
Scroll Mode
Radix
Base
Playground
Preview
SMModal
Modal
Type
Size
Scroll
Content
Options
Button Style
Cancel
Confirm
const [open, setOpen] = useState(false)
<Modal open={open} onOpenChange={setOpen}>
<Modal.Trigger asChild>
<Button variant="outline">Open Modal</Button>
</Modal.Trigger>
<Modal.Content>
<Modal.Header>
<Modal.Title>Modal Title</Modal.Title>
<Modal.Description>This is a description of the modal.</Modal.Description>
</Modal.Header>
<Modal.Body>
<p>This is a modal dialog. You can place any content here, including forms, confirmations, or informational messages.</p>
</Modal.Body>
<Modal.Footer>
<Modal.Close asChild>
<Button variant="ghost" size="md" pressEffect={false}>Cancel</Button>
</Modal.Close>
<Button size="md" pressEffect={false}>Confirm</Button>
</Modal.Footer>
</Modal.Content>
</Modal>Sizes
xs簡単な確認・アラートmax-width360px
sm (default)標準(デフォルト)max-width480px
md標準フォームmax-width600px
lg複雑なフォームmax-width760px
xlテーブル・ダッシュボードmax-width960px
fullフル幅max-widthFull
パディング(全サイズ共通)
Header24px · 下 0
Body24px
Footer24px · 上 0
Closeright 16px, top 16px
| Size | max-width | タイトル | 説明文 | 用途 |
|---|---|---|---|---|
xs | 360px | 18px semibold | 14px normal | 簡単な確認 |
sm | 480px | 18px semibold | 14px normal | 確認・アラート(デフォルト) |
md | 600px | 18px semibold | 14px normal | 標準フォーム |
lg | 760px | 18px semibold | 14px normal | 複雑なフォーム |
xl | 960px | 18px semibold | 14px normal | テーブル・ダッシュボード |
full | Full | 18px semibold | 14px normal | フル幅 |
パディング — 全サイズ共通
Header
p-6 pb-0
24px · 下 0
Body
p-6
24px
Footer
p-6 pt-0
24px · 上 0
Close
right-4 top-4
16px
Features
Scroll Behavior
"outside": モーダル全体スクロール。"inside": Bodyのみスクロール、Header/Footer固定。
{/* Outside scroll — entire modal scrolls within viewport */}
<Modal.Content scrollBehavior="outside">
<Modal.Header>
<Modal.Title>Outside Scroll</Modal.Title>
<Modal.Description>The entire modal scrolls within the viewport.</Modal.Description>
</Modal.Header>
<Modal.Body>
<p>Long content here...</p>
</Modal.Body>
</Modal.Content>
{/* Inside scroll — only body scrolls; header stays fixed */}
<Modal.Content scrollBehavior="inside">
<Modal.Header>
<Modal.Title>Inside Scroll</Modal.Title>
<Modal.Description>Only the body scrolls; header and footer stay fixed.</Modal.Description>
</Modal.Header>
<Modal.Body>
<p>Long content here...</p>
</Modal.Body>
</Modal.Content>Sidebar Layout
lg / xl / full サイズ限定。Modal.Body を p-0 flex で分割し、左ナビ+右コンテンツのレイアウトを構成できます。
const [active, setActive] = useState(0)
const navItems = ['General', 'Security', 'Notifications']
<Modal.Content size="lg" scrollBehavior="inside" showCloseButton={false}>
<Modal.Body className="p-0 flex min-h-0">
{/* Left sidebar */}
<div className="w-48 shrink-0 flex flex-col">
<div className="p-3">
<Modal.Close asChild>
<Button variant="ghost" size="md" pressEffect={false} className="w-9 h-9 p-0">
<X className="icon-sm" />
<span className="sr-only">Close</span>
</Button>
</Modal.Close>
</div>
<nav className="flex-1 px-2 pb-4 space-y-1">
{navItems.map((item, i) => (
<button key={item} onClick={() => setActive(i)}
className={cn("w-full text-left px-3 py-2 text-md rounded-lg transition-colors",
active === i
? "bg-background-muted text-foreground font-semibold"
: "text-text-muted hover:text-foreground hover:bg-background-muted"
)}>
{item}
</button>
))}
</nav>
</div>
<Divider orientation="vertical" color="muted" className="mx-0 h-auto" />
{/* Right content */}
<div className="flex-1 flex flex-col min-w-0 overflow-hidden">
<div className="px-6 pt-6 pb-4 shrink-0">
<h2 className="text-lg font-semibold">{navItems[active]}</h2>
</div>
<div className="flex-1 px-6 pb-6 overflow-y-auto">
<p className="text-md text-text-muted">Content area...</p>
</div>
</div>
</Modal.Body>
</Modal.Content>Close Button
falseで閉じるボタン非表示。closeIcon propでアイコン差し替え可能。
{/* With close button (default) — X only */}
<Modal.Content showCloseButton>
<Modal.Header>...</Modal.Header>
<Modal.Body>...</Modal.Body>
</Modal.Content>
{/* Without close button — footer actions provide exit */}
<Modal.Content showCloseButton={false}>
<Modal.Header>...</Modal.Header>
<Modal.Body>...</Modal.Body>
<Modal.Footer>
<Modal.Close asChild>
<Button variant="ghost" size="md" pressEffect={false}>Cancel</Button>
</Modal.Close>
<Button size="md" pressEffect={false}>Confirm</Button>
</Modal.Footer>
</Modal.Content>API
Component Structure
ModalRadix Dialog.Trigger.ContentProps.Header.Title.Description.Body.Footer.CloseProps.Overlay.Portal
.Triggerトリガー要素.ContentPropsパネル(size・scroll・close).Headerヘッダー領域.Titleタイトル(aria-labelledby).Description補足テキスト(aria-describedby).Bodyコンテンツ領域.Footerアクション領域.CloseProps閉じるボタン.Overlay背景オーバーレイ.PortalポータルAlertModalRadix AlertDialog.Trigger.ContentProps.Header.Title.Description.Body.Footer.Action.Cancel.Overlay.Portal
.Triggerトリガー要素.ContentPropsパネル(size: xs / sm).Headerヘッダー領域.Titleタイトル(aria-labelledby).Description補足テキスト(aria-describedby).Bodyコンテンツ領域.Footerアクション領域.Action確認アクション.Cancelキャンセル.Overlay背景オーバーレイ.PortalポータルProps
Modal.Content
size"sm""xs" | "sm" | "md" | "lg" | "xl" | "full"コンテンツの最大幅 (360/480/600/760/960/full)
scrollBehavior"outside""inside" | "outside"オーバーフロー時のスクロール位置
showCloseButtontrueboolean内蔵の閉じるボタンを表示
closeIconBuilt-in SVG iconReactNodeカスタム閉じるアイコン
| Name | Type | Default | Description |
|---|---|---|---|
size | "xs" | "sm" | "md" | "lg" | "xl" | "full" | "sm" | コンテンツの最大幅 (360/480/600/760/960/full) |
scrollBehavior | "inside" | "outside" | "outside" | オーバーフロー時のスクロール位置 |
showCloseButton | boolean | true | 内蔵の閉じるボタンを表示 |
closeIcon | ReactNode | Built-in SVG icon | カスタム閉じるアイコン |
AlertModal.Content
size"sm""xs" | "sm"コンテンツの最大幅 (360/480)
| Name | Type | Default | Description |
|---|---|---|---|
size | "xs" | "sm" | "sm" | コンテンツの最大幅 (360/480) |
Modal.Close
asChildfalseboolean子要素をトリガーとして使用
| Name | Type | Default | Description |
|---|---|---|---|
asChild | boolean | false | 子要素をトリガーとして使用 |
Anatomy
1
2
3
4
Modal title
5
Modal description
6
7
8
1
Overlay
背景オーバーレイ
2
Content
ダイアログ本体
3
Header
タイトル領域
4
Title
見出しテキスト
5
Description
補足説明テキスト
6
Close
閉じるボタン
7
Body
メインコンテンツ
8
Footer
アクションボタン
Best Practices
✓
推奨
- ✓破壊的操作にはAlertModalを使用する
- ✓モーダルのタイトルと説明を必ず設定する
- ✓長いコンテンツにはscrollBehavior="inside"を使用する
- ✓コンテンツに適したサイズを選択する
✕
避けるべき
- ✗モーダルの中にモーダルをネストしない
- ✗簡単な通知にモーダルを使わない(Toastを推奨)
- ✗閉じる手段なしのモーダルを作らない
- ✗通常の操作にAlertModalを使わない(確認が必要な場面のみ)
Accessibility
キーボード操作
Escapeキーでモーダルを閉じることができます。AlertModalではオーバーレイクリックでは閉じません。モーダル内ではTabキーでフォーカスがトラップされ、モーダル外の要素にフォーカスが移動しません。
ARIA / WCAG
role="dialog"Radix Dialogが自動設定role="alertdialog"AlertModalが自動設定aria-labelledbyModal.Titleへ自動リンクaria-describedbyModal.Descriptionへ自動リンク- フォーカストラップ(モーダル内にフォーカスを制限)
- 閉じるボタンにsr-onlyラベル設定