Components

Dialog

사용 예시

값을 입력할 때

제목과 설명은 DialogHeader에, 버튼은 DialogFooter에 둬요.

tsx
<Dialog>  <DialogTrigger render={<Button color="neutral" emphasis="outline" />}>메모 추가</DialogTrigger>  <DialogContent>    <DialogHeader>      <DialogTitle>메모 추가</DialogTitle>      <DialogDescription>이 메모는 나만 볼 수 있어요.</DialogDescription>    </DialogHeader>    <Textarea placeholder="메모를 입력하세요" />    <DialogFooter>      <DialogClose render={<Button color="neutral" emphasis="outline" />}>그대로 두기</DialogClose>      <DialogClose render={<Button color="neutral" emphasis="solid" />}>저장</DialogClose>    </DialogFooter>  </DialogContent></Dialog>

읽고 닫기만 할 때

closable을 주면 헤더 오른쪽 끝에 닫기 버튼이 보여요.

tsx
<Dialog>  <DialogTrigger render={<Button color="neutral" emphasis="outline" />}>단축키 보기</DialogTrigger>  <DialogContent>    <DialogHeader closable>      <DialogTitle>단축키</DialogTitle>    </DialogHeader>    <DialogDescription>      <Kbd>Ctrl</Kbd>과 <Kbd>Enter</Kbd>를 함께 누르면 저장해요.    </DialogDescription>  </DialogContent></Dialog>

전체 화면

사진처럼 기본 크기에 들어가지 않는 내용을 볼 때 써요.

tsx
<Dialog>  <DialogTrigger render={<Button color="neutral" emphasis="outline" />}>사진 크게 보기</DialogTrigger>  <DialogContent size="full">    <DialogHeader closable>      <DialogTitle>바다에서</DialogTitle>    </DialogHeader>    <div className="bg-bg-well min-h-0 flex-1 rounded-r8" />  </DialogContent></Dialog>

크기

담을 내용에 맞춰 sm, md, lg 중에서 골라요.

tsx
<Dialog>  <DialogTrigger render={<Button color="neutral" emphasis="outline" />}>sm</DialogTrigger>  <DialogContent size="sm">    <DialogTitle>이름 바꾸기</DialogTitle>    <Input defaultValue="가족 여행" aria-label="앨범 이름" />    <DialogFooter>      <DialogClose render={<Button color="neutral" emphasis="outline" />}>닫기</DialogClose>    </DialogFooter>  </DialogContent></Dialog><Dialog>  <DialogTrigger render={<Button color="neutral" emphasis="outline" />}>md</DialogTrigger>  <DialogContent>    <DialogTitle>메모 추가</DialogTitle>    <Textarea placeholder="메모를 입력하세요" />    <DialogFooter>      <DialogClose render={<Button color="neutral" emphasis="outline" />}>닫기</DialogClose>    </DialogFooter>  </DialogContent></Dialog><Dialog>  <DialogTrigger render={<Button color="neutral" emphasis="outline" />}>lg</DialogTrigger>  <DialogContent size="lg">    <DialogTitle>사진 고르기</DialogTitle>    <div className="grid grid-cols-4 gap-2">      {PHOTOS.map(name => <div key={name} className="bg-bg-well aspect-square rounded-r8" />)}    </div>    <DialogFooter>      <DialogClose render={<Button color="neutral" emphasis="outline" />}>닫기</DialogClose>    </DialogFooter>  </DialogContent></Dialog>

긴 내용

본문을 DialogBody에 담으면 본문만 스크롤되고 제목과 버튼은 그대로 보여요.

tsx
<Dialog>  <DialogTrigger render={<Button color="neutral" emphasis="outline" />}>이용 약관 보기</DialogTrigger>  <DialogContent>    <DialogHeader>      <DialogTitle>이용 약관</DialogTitle>      <DialogDescription>2026년 10월 1일부터 적용해요.</DialogDescription>    </DialogHeader>    <DialogBody className="flex flex-col gap-stack">      {TERMS.map(term => <p key={term} className="text-prose">{term}</p>)}    </DialogBody>    <DialogFooter>      <DialogClose render={<Button color="neutral" emphasis="outline" />}>닫기</DialogClose>      <DialogClose render={<Button color="neutral" emphasis="solid" />}>동의</DialogClose>    </DialogFooter>  </DialogContent></Dialog>

왼쪽에 보조 동작

layout을 between으로 하면 첫 버튼이 왼쪽 끝으로 가요. 지우기처럼 저장과 다른 성격의 동작에 써요.

tsx
<Dialog>  <DialogTrigger render={<Button color="neutral" emphasis="outline" />}>일정 수정</DialogTrigger>  <DialogContent>    <DialogHeader>      <DialogTitle>일정 수정</DialogTitle>    </DialogHeader>    <Input defaultValue="주간 회의" aria-label="일정 이름" />    <DialogFooter layout="between">      <DialogClose render={<Button color="danger" emphasis="ghost" />}>지우기</DialogClose>      <DialogClose render={<Button color="neutral" emphasis="outline" />}>그대로 두기</DialogClose>      <DialogClose render={<Button color="neutral" emphasis="solid" />}>저장</DialogClose>    </DialogFooter>  </DialogContent></Dialog>

버튼을 넓게

fill은 버튼 폭을 똑같이 나누고, grow-last는 마지막 버튼만 남은 폭까지 넓혀요.

tsx
<Dialog>  <DialogTrigger render={<Button color="neutral" emphasis="outline" />}>fill</DialogTrigger>  <DialogContent size="sm">    <DialogTitle>메모를 저장할까요?</DialogTitle>    <DialogFooter layout="fill">      <DialogClose render={<Button color="neutral" emphasis="outline" />}>그대로 두기</DialogClose>      <DialogClose render={<Button color="neutral" emphasis="solid" />}>저장</DialogClose>    </DialogFooter>  </DialogContent></Dialog><Dialog>  <DialogTrigger render={<Button color="neutral" emphasis="outline" />}>grow-last</DialogTrigger>  <DialogContent size="sm">    <DialogTitle>메모를 저장할까요?</DialogTitle>    <DialogFooter layout="grow-last">      <DialogClose render={<Button color="neutral" emphasis="outline" />}>그대로 두기</DialogClose>      <DialogClose render={<Button color="neutral" emphasis="solid" />}>저장</DialogClose>    </DialogFooter>  </DialogContent></Dialog>

화면 폭마다 다른 배치

넓은 화면에서는 버튼을 오른쪽에 모으고 좁은 화면에서는 누르기 쉽게 넓힐 때 써요. 창 폭을 줄여 보세요.

tsx
<Dialog>  <DialogTrigger render={<Button color="neutral" emphasis="outline" />}>할 일 추가</DialogTrigger>  <DialogContent>    <DialogHeader>      <DialogTitle>할 일 추가</DialogTitle>    </DialogHeader>    <Input placeholder="할 일을 입력하세요" aria-label="할 일" />    <DialogFooter layout={{ narrow: 'grow-last', wide: 'end' }}>      <DialogClose render={<Button color="neutral" emphasis="outline" />}>그대로 두기</DialogClose>      <DialogClose render={<Button color="neutral" emphasis="solid" />}>추가</DialogClose>    </DialogFooter>  </DialogContent></Dialog>

겹쳐 열기

DialogContent 안에 Dialog를 두면 앞 창의 overlay가 뒤 창을 어둡게 하고 뒤 창은 조금 작아져요.

tsx
<Dialog>  <DialogTrigger render={<Button color="neutral" emphasis="outline" />}>공유 설정</DialogTrigger>  <DialogContent size="lg">    <DialogHeader>      <DialogTitle>공유 설정</DialogTitle>      <DialogDescription>링크가 있는 사람은 누구나 볼 수 있어요.</DialogDescription>    </DialogHeader>    <DialogFooter>      <Dialog>        <DialogTrigger render={<Button color="neutral" emphasis="outline" />}>링크 보기</DialogTrigger>        <DialogContent size="sm">          <DialogTitle>공유 링크</DialogTitle>          <Input readOnly defaultValue="pantoia.com/s/8412" aria-label="공유 링크" />          <DialogFooter>            <DialogClose render={<Button color="neutral" emphasis="solid" />}>닫기</DialogClose>          </DialogFooter>        </DialogContent>      </Dialog>      <DialogClose render={<Button color="neutral" emphasis="solid" />}>닫기</DialogClose>    </DialogFooter>  </DialogContent></Dialog>

감춘 제목

화면에 제목을 보일 곳이 없어도 DialogTitle은 둬요. 스크린 리더가 Dialog의 이름으로 읽어요.

tsx
<Dialog>  <DialogTrigger render={<Button color="neutral" emphasis="outline" />}>사진 찾기</DialogTrigger>  <DialogContent>    <DialogTitle className="sr-only">사진 찾기</DialogTitle>    <DialogDescription className="sr-only">이름으로 찾아요.</DialogDescription>    <Input placeholder="사진 이름" />  </DialogContent></Dialog>

코드로 열기

오래 걸리는 작업이 끝난 뒤 결과를 보일 때처럼 트리거 없이 열 때 써요.

tsx
const [resultOpen, setResultOpen] = useState(false)return (  <>    <Button color="neutral" emphasis="outline" onClick={() => setResultOpen(true)}>사진 올리기</Button>    <Dialog open={resultOpen} onOpenChange={setResultOpen}>      <DialogContent>        <DialogHeader>          <DialogTitle>사진을 올렸어요</DialogTitle>          <DialogDescription>앨범에 12장을 추가했어요.</DialogDescription>        </DialogHeader>        <DialogFooter>          <DialogClose render={<Button color="neutral" emphasis="solid" />}>닫기</DialogClose>        </DialogFooter>      </DialogContent>    </Dialog>  </>)

컨트롤

tsx
<Dialog>  <DialogTrigger render={<Button color="neutral" emphasis="outline" />}>프로필 편집</DialogTrigger>  <DialogContent>    <DialogHeader>      <DialogTitle>프로필 편집</DialogTitle>      <DialogDescription>저장하면 다른 사람에게 바로 보여요.</DialogDescription>    </DialogHeader>    <DialogFooter>      <DialogClose render={<Button color="neutral" emphasis="outline" />}>그대로 두기</DialogClose>      <DialogClose render={<Button color="neutral" emphasis="solid" />}>저장</DialogClose>    </DialogFooter>  </DialogContent></Dialog>

명세

이름
이름값기본
Dialog
openboolean-
호출하는 쪽에서 열림 상태를 관리해요.
defaultOpenbooleanfalse
처음에 열어 둘지 정해요.
onOpenChange(open: boolean, eventDetails) => void-
열리거나 닫히면 호출돼요.
renderReactElement-
기본 요소 대신 그릴 요소예요. DialogTrigger와 DialogClose에 Button을 넘길 때 써요.
classNamestring-
모든 하위 컴포넌트에 쓸 수 있어요.
DialogContent
sizesm, md, lg, full, topmd
sm은 448px, md는 480px, lg는 640px까지 넓어지고 좁은 화면에서는 양옆에 16px 여백을 둬요. top은 CommandPalette에 쓰는 크기예요.
DialogHeader
leadReactNode-
제목 앞에 보여요.
trailReactNode-
헤더 오른쪽 끝에 보여요.
closablebooleanfalse
헤더 오른쪽 끝에 닫기 버튼을 보여요. trail이 있으면 trail 다음에 와요.
closeLabelstring닫기
닫기 버튼의 접근성 이름이에요.
DialogBody
childrenReactNode-
내용이 길면 이 영역만 스크롤되고 헤더와 푸터는 그대로 보여요.
DialogFooter
layoutend, between, fill, grow-last, { narrow, wide }end
between은 첫 버튼을 왼쪽 끝으로 보내고, fill은 버튼 폭을 똑같이 나누고, grow-last는 마지막 버튼만 넓혀요. { narrow, wide }를 넘기면 640px(sm)보다 좁을 때 narrow, 넓을 때 wide를 써요.