Dialog
답할 때까지 페이지를 가리는 modal sheet입니다. 확인이 필요한 작업이나 흐름을 끊고 처리해야 하는 입력에 씁니다.
import { Button, Dialog, DialogClose } from 'neba';
<Dialog
trigger={<Button color="danger">워크스페이스 삭제</Button>}
title="이 워크스페이스를 삭제할까요?"
description="안에 있는 프로젝트·배포·로그가 함께 사라집니다."
actions={<DialogClose render={<Button color="danger">삭제</Button>} />}
>
되돌릴 수 없습니다.
</Dialog>;Props
| Prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
| locale | string | — | BCP 47 태그. ×의 접근성 이름을 이 언어로 씁니다. 지원하지 않는 태그는 영어로 |
| size공통 | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'md' | 타입 스케일과 여백, 그리고 시트가 넓어질 수 있는 한계까지 함께 정합니다. maxWidth라는 두 번째 축을 만들지 않은 이유입니다 |
| color공통 | 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info' | 'primary' | 의미론적 색 역할. 시트는 물들지 않으므로 가장자리와 포커스 링에만 나타납니다 |
| density공통 | 'default' | 'compact' | 'default' | 여백만 바꿉니다 |
| open | boolean | — | 열림 여부. onOpenChange와 함께 쓰면 제어 컴포넌트가 됩니다 |
| defaultOpen | boolean | false | 비제어 다이얼로그의 초기 상태 |
| onOpenChange | (open: boolean) => void | — | 열리거나 닫힐 때 호출 |
| trigger | ReactElement | — | 다이얼로그를 여는 요소. Base UI가 연결합니다. 선택 사항, 다른 곳에서 여는 제어 다이얼로그에는 필요 없습니다 |
| title | ReactNode | — | 제목. 다이얼로그의 이름이 되는 h2로 렌더링됩니다 |
| description | ReactNode | — | 제목 아래 한 줄이자 다이얼로그의 접근성 설명 |
| actions | ReactNode | — | 아래쪽 버튼 줄. 끝 정렬됩니다. DialogClose가 그중 하나를 닫기 버튼으로 만듭니다 |
| dividers | boolean | false | 구역 사이를 여백 대신 하이라인으로 나눕니다. 본문이 스크롤되는 순간부터 켜는 편이 좋습니다 |
| showClose | boolean | true | 모서리의 ×. 라이브러리의 다른 불리언과 달리 기본이 켜짐입니다. 모달은 답할 때까지 페이지를 가져가므로 나가는 길이 보여야 합니다 |
| closeLabel | string | — | × 버튼의 접근성 이름 |
| width | number | string | — | size가 정한 최대 너비를 대신할 값. 숫자는 픽셀입니다 |
| fullWidth | boolean | true | size가 허용하는 너비를 가득 채웁니다. 다른 컴포넌트와 반대로 기본이 켜짐입니다. 다이얼로그의 컨테이너는 뷰포트입니다 |
| fullScreen | boolean | false | 뷰포트를 가장자리까지 채웁니다 |
| modal | boolean | 'trap-focus' | true | 뒤 페이지를 가져갈지. trap-focus는 스크롤과 클릭은 남기고 포커스만 가둡니다 |
| dismissible | boolean | true | Esc와 바깥 클릭으로 닫히는지. 끄려면 답할 수 있는 actions를 반드시 함께 주세요 |
| children | ReactNode | — | 본문. 스크롤되는 유일한 구역입니다 |
| classNames | NebaSlots<'backdrop' | 'viewport' | 'title' | 'description' | 'close' | 'body' | 'actions'> | — | 루트 뒤에 있는 각 파트의 class. 루트 자체는 className이 맡으므로 root 키는 없습니다 |
<div>의 native 속성은 popup으로 전달됩니다. color · title · children만 위 표와 이름이 겹쳐 제외됩니다.
variant와 elevation은 없습니다. modal은 항상 3단계 그림자를 답니다.
예시
size와 width
size는 타입 스케일과 여백은 물론 sheet의 최대 너비까지 함께 정합니다. 작은 글씨로 넓은 표나 diff를 보여 줘야 하는 경우처럼 그 조합에서 벗어나야 할 때는 width에 길이를 직접 지정하세요.
dividers
본문이 길면 본문만 스크롤되고 제목과 액션은 제자리에 남습니다. dividers는 그 경계에 선을 그어, 헤더가 함께 스크롤되지 않았음을 보여 줍니다.
dismissible
dismissible={false}는 Esc와 바깥 클릭을 함께 막습니다. actions에 답할 수 있는 버튼이 있을 때만 끄세요. 그 외에는 나갈 방법이 없습니다.
DialogClose
open 상태를 직접 들지 않고도 버튼으로 Dialog를 닫을 수 있습니다. render로 원하는 컨트롤을 넣으세요.
actions={
<>
<DialogClose render={<Button variant="text" color="secondary">취소</Button>} />
<DialogClose render={<Button color="danger">삭제</Button>} />
</>
}classNames
className은 popup(sheet 자체이며, 부르는 사람이 "dialog"라고 할 때 가리키는 것)에 붙습니다. 그 바깥과 안쪽은 모두 classNames로 갑니다.
<Dialog
title="Delete this?"
classNames={{ backdrop: 'backdrop-blur-none', actions: 'justify-between' }}
/>slot은 backdrop, viewport, title, description, close, body, actions입니다. 앞의 둘은 달리 닿을 방법이 없는 것들입니다. 둘 다 popup 바깥, <body> 끝에 그려지므로 sheet를 기준으로 쓴 선택자로는 찾을 수 없습니다. 넘긴 class가 컴포넌트 자신의 class와 어떻게 겨루는지는 prop 규약을 보세요.
접근성
title과description은 각각aria-labelledby,aria-describedby로 연결됩니다.title은 실제<h2>로 렌더링됩니다.- focus trap, scroll lock, 뒤 페이지 inert 처리, 닫을 때 trigger로 focus 복귀가 모두 적용됩니다.
showClose는 기본값이 켜짐입니다. modal에서 나가는 길은 항상 보여야 하고, 터치 screen reader가 팝업을 빠져나오는 통로이기도 합니다.- ×의 접근성 이름은
locale이 정합니다.closeLabel로 직접 쓸 수도 있습니다.