Dialog
Dialog
주 창이나 다른 다이얼로그 창 위에 겹쳐서, 아래 콘텐츠를 비활성(inert)으로 렌더링하는 창 컴포넌트예요.
출처: 문서
본문
현재 화면 위에 모달 창을 띄우는 다이얼로그 컴포넌트예요. 모달/비모달 모드를 모두 지원하고, 모달에서는 포커스가 자동으로 트랩되며 Esc 키로 닫혀요. 스크린 리더 공지는 Title/Description 컴포넌트로 관리해요.
Features
- 모달/비모달 모드 지원.
- 모달 내에서 포커스가 자동으로 트랩돼요.
- 제어(controlled)/비제어(uncontrolled) 방식 모두 지원.
Title과Description컴포넌트로 스크린 리더 공지 관리.Esc키로 컴포넌트가 자동으로 닫혀요.
Anatomy
모든 파트를 임포트해 조립해요.
import { Dialog } from "radix-ui";
export default () => (
<Dialog.Root>
<Dialog.Trigger />
<Dialog.Portal>
<Dialog.Overlay />
<Dialog.Content>
<Dialog.Title />
<Dialog.Description />
<Dialog.Close />
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
);
API Reference
Root
다이얼로그의 모든 파트를 담아요.
| Prop | Type | Default |
|---|---|---|
defaultOpen |
boolean |
No default value |
open |
boolean |
No default value |
onOpenChange |
function |
No default value |
modal |
boolean |
true |
Trigger
다이얼로그를 여는 버튼이에요.
| Prop | Type | Default |
|---|---|---|
asChild |
boolean |
false |
| Data attribute | Values |
|---|---|
[data-state] |
"open" | "closed" |
Portal
사용하면 overlay와 content 파트를 body로 포털해요.
| Prop | Type | Default |
|---|---|---|
forceMount |
boolean |
No default value |
container |
HTMLElement |
document.body |
Overlay
다이얼로그가 열려 있을 때 뷰의 비활성 부분을 덮는 레이어예요.
| Prop | Type | Default |
|---|---|---|
asChild |
boolean |
false |
forceMount |
boolean |
No default value |
| Data attribute | Values |
|---|---|
[data-state] |
"open" | "closed" |
Content
열린 다이얼로그에 렌더링할 콘텐츠를 담아요.
| Prop | Type | Default |
|---|---|---|
asChild |
boolean |
false |
forceMount |
boolean |
No default value |
onOpenAutoFocus |
function |
No default value |
onCloseAutoFocus |
function |
No default value |
onEscapeKeyDown |
function |
No default value |
onPointerDownOutside |
function |
No default value |
onInteractOutside |
function |
No default value |
| Data attribute | Values |
|---|---|
[data-state] |
"open" | "closed" |
Close
다이얼로그를 닫는 버튼이에요.
| Prop | Type | Default |
|---|---|---|
asChild |
boolean |
false |
Title
다이얼로그가 열렸을 때 공지될 접근 가능한 제목이에요.
제목을 숨기고 싶다면 Visually Hidden 유틸리티로 <VisuallyHidden asChild>처럼 감싸면 돼요.
| Prop | Type | Default |
|---|---|---|
asChild |
boolean |
false |
Description
다이얼로그가 열렸을 때 공지될 선택적 접근 가능한 설명이에요.
설명을 숨기고 싶다면 Visually Hidden 유틸리티로 <VisuallyHidden asChild>처럼 감싸면 돼요. 설명을 완전히 제거하고 싶다면 이 파트를 빼고 Dialog.Content에 aria-describedby={undefined}를 전달하세요.
| Prop | Type | Default |
|---|---|---|
asChild |
boolean |
false |
Examples
비동기 폼 제출 후 닫기
제어 props를 사용해 비동기 작업이 완료된 후 Dialog를 프로그래밍 방식으로 닫을 수 있어요.
import * as React from "react";
import { Dialog } from "radix-ui";
const wait = () => new Promise((resolve) => setTimeout(resolve, 1000));
export default () => {
const [open, setOpen] = React.useState(false);
return (
<Dialog.Root open={open} onOpenChange={setOpen}>
<Dialog.Trigger>Open</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Overlay />
<Dialog.Content>
<form
onSubmit={(event) => {
wait().then(() => setOpen(false));
event.preventDefault();
}}
>
{/** some inputs */}
<button type="submit">Submit</button>
</form>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
);
};
스크롤 가능한 오버레이
콘텐츠를 overlay 안으로 옮겨 overflow가 있는 다이얼로그를 렌더링해요.
// index.jsx
import { Dialog } from "radix-ui";
import "./styles.css";
export default () => {
return (
<Dialog.Root>
<Dialog.Trigger />
<Dialog.Portal>
<Dialog.Overlay className="DialogOverlay">
<Dialog.Content className="DialogContent">...</Dialog.Content>
</Dialog.Overlay>
</Dialog.Portal>
</Dialog.Root>
);
};
/* styles.css */
.DialogOverlay {
background: rgba(0 0 0 / 0.5);
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: grid;
place-items: center;
overflow-y: auto;
}
.DialogContent {
min-width: 300px;
background: white;
padding: 30px;
border-radius: 4px;
}
커스텀 포털 컨테이너
다이얼로그가 포털될 요소를 커스터마이즈할 수 있어요.
import * as React from "react";
import { Dialog } from "radix-ui";
export default () => {
const [container, setContainer] = React.useState(null);
return (
<div>
<Dialog.Root>
<Dialog.Trigger />
<Dialog.Portal container={container}>
<Dialog.Overlay />
<Dialog.Content>...</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
<div ref={setContainer} />
</div>
);
};
Accessibility
Dialog WAI-ARIA 디자인 패턴을 준수해요.
키보드 상호작용
| Key | Description |
|---|---|
Space |
Opens/closes the dialog. |
Enter |
Opens/closes the dialog. |
Tab |
Moves focus to the next focusable element. |
Shift + Tab |
Moves focus to the previous focusable element. |
Esc |
Closes the dialog and moves focus to Dialog.Trigger. |
Custom APIs
primitive 파트를 자신의 컴포넌트로 추상화해 나만의 API를 만들 수 있어요.
Overlay와 닫기 버튼 추상화
이 예제는 Dialog.Overlay와 Dialog.Close 파트를 추상화해요.
사용법
import { Dialog, DialogTrigger, DialogContent } from "./your-dialog";
export default () => (
<Dialog>
<DialogTrigger>Dialog trigger</DialogTrigger>
<DialogContent>Dialog Content</DialogContent>
</Dialog>
);
구현
// your-dialog.jsx
import * as React from "react";
import { Dialog as DialogPrimitive } from "radix-ui";
import { Cross1Icon } from "@radix-ui/react-icons";
export const DialogContent = React.forwardRef(({ children, ...props }, forwardedRef) => (
<DialogPrimitive.Portal>
<DialogPrimitive.Overlay />
<DialogPrimitive.Content {...props} ref={forwardedRef}>
{children}
<DialogPrimitive.Close aria-label="Close">
<Cross1Icon />
</DialogPrimitive.Close>
</DialogPrimitive.Content>
</DialogPrimitive.Portal>
));
export const Dialog = DialogPrimitive.Root;
export const DialogTrigger = DialogPrimitive.Trigger;
더 알아보기 (Learn more)
modalprop을false로 하면 비모달 다이얼로그(팝오버처럼)로 동작해요.Dialog.Content를Dialog.Overlay안에 배치하면 오버레이를 스크롤 컨테이너로 활용한 스크롤 가능한 다이얼로그를 만들 수 있어요.