Motile UI

Modal

중앙에 표시되는 Modal 컴포넌트입니다. 4가지 애니메이션 variant(scale, slideDown, slideUp, bottomSheet)를 제공하며, ESC 키와 외부 클릭으로 닫기 옵션을 세밀하게 제어할 수 있습니다. Portal을 사용하여 DOM 트리의 최상단에 렌더링됩니다.

미리보기

사용법

1"use client";
2
3import { useState } from "react";
4import { Button, Modal } from "motile-ui";
5
6export default function PreviewExample() {
7  const [open, setOpen] = useState(false);
8
9  return (
10    <>
11      <Button onClick={() => setOpen(true)} variant="primary">
12        Open Modal
13      </Button>
14      <Modal.Root open={open} onOpenChange={setOpen}>
15        <Modal.Overlay>
16          <Modal.Content style={{ padding: "0" }}>
17            <Modal.Header>
18              <Modal.Title>알림</Modal.Title>
19              <Modal.Close />
20            </Modal.Header>
21            <Modal.Body style={{ padding: "24px" }}>
22              <p style={{ margin: 0, color: "#6b7280", lineHeight: 1.6, fontSize: "14px" }}>
23                Modal 컴포넌트입니다. ESC 키를 누르거나 외부를 클릭하여 닫을 수 있습니다.
24              </p>
25            </Modal.Body>
26            <Modal.Footer>
27              <Modal.Close asChild>
28                <Button variant="primary">확인</Button>
29              </Modal.Close>
30            </Modal.Footer>
31          </Modal.Content>
32        </Modal.Overlay>
33      </Modal.Root>
34    </>
35  );
36}

API 레퍼런스

Modal.Root

Modal의 상태를 관리하는 최상위 컨텍스트 프로바이더 (제어 컴포넌트)

속성타입기본값설명
openboolean-Modal 열림/닫힘 상태
onOpenChange(open: boolean) => void-상태가 변경될 때 실행되는 함수

Modal.Overlay

Modal 배경 오버레이 및 Portal

속성타입기본값설명
variant"scale" | "slideDown" | "slideUp" | "bottomSheet""scale"Modal 애니메이션 스타일
closeOnBackdropboolean | objecttrue백드롭 인터랙션으로 닫기 제어 (boolean 또는 escapeKey, clickOutside 속성을 가진 객체)
disableScrollLockbooleanfalse배경 스크롤 잠금 비활성화
widthstring-Modal 너비
maxWidthstring-Modal 최대 너비
zIndexnumber1000z-index 값
containerHTMLElementdocument.bodyModal을 렌더링할 DOM 컨테이너

기본 <code>div</code> HTML 속성을 모두 사용할 수 있습니다.

Modal.Content

Modal 메인 콘텐츠 컨테이너

기본 <code>div</code> HTML 속성을 모두 사용할 수 있습니다.

Modal.Header

Modal 헤더 영역

기본 <code>div</code> HTML 속성을 모두 사용할 수 있습니다.

Modal.Title

Modal 제목

기본 <code>h2</code> HTML 속성을 모두 사용할 수 있습니다.

Modal.Body

Modal 본문 콘텐츠

기본 <code>div</code> HTML 속성을 모두 사용할 수 있습니다.

Modal.Footer

Modal Footer 영역

기본 <code>div</code> HTML 속성을 모두 사용할 수 있습니다.

Modal.Close

Modal을 닫는 버튼

속성타입기본값설명
asChildbooleanfalse래퍼 없이 자식 요소만 렌더링

기본 <code>button</code> HTML 속성을 모두 사용할 수 있습니다.

예제

SlideDown 애니메이션

1"use client";
2
3import { useState } from "react";
4import { Button, Modal } from "motile-ui";
5
6export default function SlideDownExample() {
7  const [open, setOpen] = useState(false);
8
9  return (
10    <>
11      <Button onClick={() => setOpen(true)} variant="secondary" size="small">
12        SlideDown
13      </Button>
14      <Modal.Root open={open} onOpenChange={setOpen}>
15        <Modal.Overlay variant="slideDown">
16          <Modal.Content style={{ padding: "0" }}>
17            <Modal.Header>
18              <Modal.Title>SlideDown Animation</Modal.Title>
19              <Modal.Close />
20            </Modal.Header>
21            <Modal.Body>
22              <p style={{ margin: 0, color: "#6b7280", lineHeight: 1.6 }}>
23                화면 위에서 중앙으로 떨어지며 나타나는 애니메이션입니다.
24              </p>
25            </Modal.Body>
26          </Modal.Content>
27        </Modal.Overlay>
28      </Modal.Root>
29    </>
30  );
31}

SlideUp 애니메이션

1"use client";
2
3import { useState } from "react";
4import { Button, Modal } from "motile-ui";
5
6export default function SlideUpExample() {
7  const [open, setOpen] = useState(false);
8
9  return (
10    <>
11      <Button onClick={() => setOpen(true)} variant="secondary" size="small">
12        SlideUp
13      </Button>
14      <Modal.Root open={open} onOpenChange={setOpen}>
15        <Modal.Overlay variant="slideUp">
16          <Modal.Content style={{ padding: "0" }}>
17            <Modal.Header>
18              <Modal.Title>SlideUp Animation</Modal.Title>
19              <Modal.Close />
20            </Modal.Header>
21            <Modal.Body>
22              <p style={{ margin: 0, color: "#6b7280", lineHeight: 1.6 }}>
23                화면 아래에서 중앙으로 올라오며 나타나는 애니메이션입니다.
24              </p>
25            </Modal.Body>
26          </Modal.Content>
27        </Modal.Overlay>
28      </Modal.Root>
29    </>
30  );
31}

하단 Modal

1"use client";
2
3import { useState } from "react";
4import { Button, Modal } from "motile-ui";
5
6export default function BottomSheetExample() {
7  const [open, setOpen] = useState(false);
8
9  return (
10    <>
11      <Button onClick={() => setOpen(true)} variant="secondary" size="small">
12        하단 Modal
13      </Button>
14      <Modal.Root open={open} onOpenChange={setOpen}>
15        <Modal.Overlay variant="bottomSheet">
16          <Modal.Content style={{ padding: "24px" }}>
17            <h2 style={{ fontSize: "20px", fontWeight: 600, marginBottom: "16px" }}>
18              옵션 선택
19            </h2>
20            <p style={{ margin: "0 0 24px", color: "#6b7280", lineHeight: 1.6 }}>
21              원하는 옵션을 선택해주세요. 화면 하단에서 올라오는 bottomSheet 스타일입니다.
22            </p>
23            <Modal.Close asChild>
24              <Button variant="primary" size="large" style={{ width: "100%" }}>
25                확인
26              </Button>
27            </Modal.Close>
28          </Modal.Content>
29        </Modal.Overlay>
30      </Modal.Root>
31    </>
32  );
33}

ESC 키로만 닫기

1"use client";
2
3import { useState } from "react";
4import { Button, Modal } from "motile-ui";
5
6export default function EscKeyOnlyExample() {
7  const [open, setOpen] = useState(false);
8
9  return (
10    <>
11      <Button onClick={() => setOpen(true)} variant="secondary" size="small">
12        ESC Only
13      </Button>
14      <Modal.Root open={open} onOpenChange={setOpen}>
15        <Modal.Overlay closeOnBackdrop={{ escapeKey: true, clickOutside: false }}>
16          <Modal.Content style={{ padding: "0" }}>
17            <Modal.Header>
18              <Modal.Title>ESC 키로만 닫기</Modal.Title>
19              <Modal.Close />
20            </Modal.Header>
21            <Modal.Body>
22              <p style={{ margin: 0, color: "#6b7280", lineHeight: 1.6 }}>
23                이 Modal은 ESC 키로만 닫을 수 있습니다. 외부 클릭은 비활성화되어 있습니다.
24              </p>
25            </Modal.Body>
26          </Modal.Content>
27        </Modal.Overlay>
28      </Modal.Root>
29    </>
30  );
31}

버튼으로만 닫기

1"use client";
2
3import { useState } from "react";
4import { Button, Modal } from "motile-ui";
5
6export default function NoBackdropCloseExample() {
7  const [open, setOpen] = useState(false);
8
9  return (
10    <>
11      <Button onClick={() => setOpen(true)} variant="secondary" size="small">
12        No Backdrop Close
13      </Button>
14      <Modal.Root open={open} onOpenChange={setOpen}>
15        <Modal.Overlay closeOnBackdrop={false}>
16          <Modal.Content style={{ padding: "0" }}>
17            <Modal.Header>
18              <Modal.Title>버튼으로만 닫기</Modal.Title>
19              <Modal.Close />
20            </Modal.Header>
21            <Modal.Body>
22              <p style={{ margin: 0, color: "#6b7280", lineHeight: 1.6 }}>
23                이 Modal은 닫기 버튼으로만 닫을 수 있습니다.
24                ESC 키와 외부 클릭 모두 비활성화되어 있습니다.
25              </p>
26            </Modal.Body>
27          </Modal.Content>
28        </Modal.Overlay>
29      </Modal.Root>
30    </>
31  );
32}

커스텀 너비

1"use client";
2
3import { useState } from "react";
4import { Button, Modal } from "motile-ui";
5
6export default function CustomWidthExample() {
7  const [open, setOpen] = useState(false);
8
9  return (
10    <>
11      <Button onClick={() => setOpen(true)} variant="secondary" size="small">
12        Custom Width
13      </Button>
14      <Modal.Root open={open} onOpenChange={setOpen}>
15        <Modal.Overlay width="600px">
16          <Modal.Content style={{ padding: "0" }}>
17            <Modal.Header>
18              <Modal.Title>넓은 Modal (600px)</Modal.Title>
19              <Modal.Close />
20            </Modal.Header>
21            <Modal.Body>
22              <div style={{ color: "#6b7280", lineHeight: 1.6 }}>
23                <p style={{ marginTop: 0 }}>
24                  이 Modal은 사용자 정의 너비(600px)를 가지며,
25                  더 많은 콘텐츠를 표시하는 데 적합합니다.
26                </p>
27                <p>
28                  모바일 기기에서는 자동으로 전체 너비로 조정되어
29                  작은 화면에서 최적의 사용성을 보장합니다.
30                </p>
31                <p style={{ marginBottom: 0 }}>
32                  이러한 유연성은 모든 기기 크기에서
33                  작동해야 하는 반응형 디자인에 완벽합니다.
34                </p>
35              </div>
36            </Modal.Body>
37          </Modal.Content>
38        </Modal.Overlay>
39      </Modal.Root>
40    </>
41  );
42}
Modal | Motile UI