Dialog
현재 화면 위에서 짧고 집중된 작업이나 정보를 처리합니다.
목적
Dialog는 현재 화면의 맥락을 유지한 채 짧은 설명, 선택, 편집을 집중해서 완료하게 한다. 배경 작업과의 연결은 유지하되 사용자가 열린 layer의 목적과 닫은 뒤 돌아갈 위치를 잃지 않게 한다.
선택 기준
- 현재 화면을 떠나지 않고 짧은 작업을 끝내야 할 때 사용한다.
- 반드시 명시적인 결정을 받아야 하는 위험 행동에는 AlertDialog를 사용한다.
- 긴 form, 여러 단계, 깊은 탐색은 별도 화면이나 Sheet를 검토한다.
- 잠깐 보충 정보를 보여주는 정도라면 Popover가 더 적절하다.
구조
Dialog 아래에 DialogTrigger와 DialogContent를 둔다. Content는 theme 경계 안의 portal, overlay, 오른쪽 위 close control을 함께 렌더한다. 내부에서는 DialogHeader에 DialogTitle과 DialogDescription, DialogFooter에 행동을 배치한다. 별도 닫기 동작에는 DialogClose를 사용할 수 있다.
DialogPortal과 DialogOverlay는 고급 구성이 아니면 직접 조합하지 않는다.
변형과 크기
별도 size prop은 없다. Content는 전체 너비를 사용하되 max-w-lg, 24px padding, 16px gap을 가진다. 작은 화면에서는 화면 가장자리와 이어지고 sm 이상에서 둥근 모서리를 사용한다. 크기를 임의로 키우기 전에 작업을 별도 화면으로 분리할지 검토한다.
상태와 동작
Dialog는 open, defaultOpen, onOpenChange로 제어·비제어 상태를 지원한다. 열린 동안 focus는 Dialog 안에서 관리되고 닫히면 Trigger 맥락으로 돌아간다. Content에 기본 close control이 포함된다.
제출 중에는 주 행동을 비활성화하고 진행 문구를 유지한다. 저장 성공 후 닫을지, 결과를 보여준 뒤 닫을지는 사용자가 다음 작업을 이해할 수 있는 흐름으로 결정한다.
콘텐츠
Title은 Dialog 안에서 끝낼 일을 한 문장으로 말한다. Description은 판단에 필요한 조건이나 현재 대상을 알려준다. Button은 저장 대신 변경사항 저장처럼 결과를 쓴다. 닫기만 필요한 정보 Dialog에 의미 없는 확인 Button을 추가하지 않는다.
접근성
DialogTitle과 DialogDescription을 제공한다. 시각적으로 숨기더라도 screen reader가 목적을 알 수 있어야 한다. Content의 기본 close control에는 접근 가능한 이름이 포함되어 있다. Trigger와 내부 모든 조작은 keyboard로 사용할 수 있어야 하며 focus ring을 제거하지 않는다.
좁은 화면과 긴 콘텐츠
Footer는 좁은 화면에서 세로로 쌓인다. 긴 본문을 고정 높이에 숨기지 말고 필요한 경우 명시적인 scroll 영역과 고정된 제목·행동 구조를 설계한다. 화면 대부분을 차지하거나 keyboard 입력이 많은 작업은 Sheet 또는 별도 화면으로 옮긴다.
공개 API
Dialog,DialogTrigger,DialogClose: root와 열기·닫기 controlDialogContent,DialogOverlay,DialogPortal: layer 표면DialogHeader,DialogFooter: 내부 레이아웃DialogTitle,DialogDescription: 제목과 설명
래퍼가 별도 선언하지 않은 props는 각 기반 요소의 props를 그대로 전달한다.
예제
import {
Button,
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
Input,
Label,
} from '@classum/dot-design-system/ui';
export function RenameDialog() {
return (
<Dialog>
<DialogTrigger asChild>
<Button variant="outline">이름 변경</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>커리큘럼 이름 변경</DialogTitle>
<DialogDescription>목록과 학습자 화면에 표시되는 이름이에요.</DialogDescription>
</DialogHeader>
<div className="grid gap-2">
<Label htmlFor="curriculum-name">이름</Label>
<Input id="curriculum-name" defaultValue="신규 입사자 온보딩" />
</div>
<DialogFooter>
<DialogClose asChild>
<Button type="button" variant="outline">
취소
</Button>
</DialogClose>
<Button type="button">이름 저장</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}피해야 할 사용
- 여러 단계의 복잡한 작업을 작은 Dialog에 밀어 넣지 않는다.
- Title이나 Description 없이 시각적 배치만으로 목적을 전달하지 않는다.
- 닫으면 손실되는 변경이 있는데 별도 확인 없이 닫히게 하지 않는다.
- Dialog 안에 Dialog를 연속해서 중첩하지 않는다.
- 배경 화면의 중요한 상태가 바뀌었는데 사용자가 알 수 없게 조용히 닫지 않는다.