Motile UI

Sheet

화면 왼쪽 또는 오른쪽에서 슬라이드되는 사이드 패널 컴포넌트입니다. Compound Component 구조(Root, Trigger, Portal, Overlay, Content, Header, Title, Body, Close)로 동작하며, 설정, 필터, 네비게이션 등의 용도로 사용됩니다. 모바일 최적화를 위해 768px 이하에서는 maxWidth가 무시되고 화면 전체 너비로 표시되며, 히스토리 기반 뒤로가기 제스처를 지원합니다.

미리보기

사용법

1"use client";
2
3import { useState } from "react";
4import { Button, Sheet } from "motile-ui";
5
6export default function PreviewExample() {
7  const [open, setOpen] = useState(false);
8
9  return (
10    <div style={{ display: "flex", justifyContent: "center" }}>
11      <Sheet.Root open={open} onOpenChange={setOpen}>
12        <Sheet.Trigger asChild>
13          <Button variant="primary">Sheet 열기</Button>
14        </Sheet.Trigger>
15        <Sheet.Portal>
16          <Sheet.Overlay />
17          <Sheet.Content>
18            <Sheet.Header>
19              <Sheet.Title>Sheet 제목</Sheet.Title>
20              <Sheet.Close />
21            </Sheet.Header>
22            <Sheet.Body>
23              <p>Sheet 컴포넌트의 내용이 여기에 표시됩니다.</p>
24              <p>화면 오른쪽에서 슬라이드되는 사이드 패널입니다.</p>
25            </Sheet.Body>
26          </Sheet.Content>
27        </Sheet.Portal>
28      </Sheet.Root>
29    </div>
30  );
31}

API 레퍼런스

Sheet.Root

Sheet의 상태와 설정을 관리하는 최상위 컴포넌트

속성타입기본값설명
position"left" | "right""right"Sheet가 나타나는 위치 (left: 왼쪽, right: 오른쪽)
closeOnBackdropboolean | { escapeKey?: boolean; clickOutside?: boolean }true백드롭 클릭 또는 ESC 키로 닫기 제어 - boolean 또는 객체로 세밀한 제어 가능
maxWidthstring"600px"Sheet 최대 너비 (데스크톱 전용, 모바일은 전체 너비)
zIndexnumber1000Sheet의 z-index 값
openboolean-Sheet 열림 상태 (제어 모드)
defaultOpenbooleanfalseSheet 초기 열림 상태 (비제어 모드)
onOpenChange(open: boolean) => void-Sheet 열림 상태 변경 시 호출되는 콜백

Sheet.Trigger

Sheet를 여는 트리거 요소

속성타입기본값설명
childrenReact.ReactElement-트리거로 사용할 React 요소
asChildbooleanfalse래퍼 없이 자식 요소만 렌더링

Sheet.Portal

Sheet를 특정 DOM 위치에 렌더링하는 Portal 컴포넌트

속성타입기본값설명
childrenReact.ReactNode-Portal에 렌더링할 내용
containerHTMLElementdocument.bodyPortal이 렌더링될 DOM 요소

Sheet.Overlay

Sheet 뒤에 표시되는 오버레이 배경

속성타입기본값설명
classNamestring-추가 CSS 클래스명
styleReact.CSSProperties-인라인 스타일

Sheet.Content

Sheet의 메인 콘텐츠를 담는 컴포넌트

속성타입기본값설명
childrenReact.ReactNode-Sheet 콘텐츠
classNamestring-추가 CSS 클래스명
styleReact.CSSProperties-인라인 스타일

Sheet.Header

Sheet 헤더 영역 (Title과 Close 버튼 포함)

속성타입기본값설명
childrenReact.ReactNode-Sheet 헤더 내용
classNamestring-추가 CSS 클래스명

Sheet.Title

Sheet 제목을 표시하는 컴포넌트

속성타입기본값설명
childrenReact.ReactNode-Sheet 제목 텍스트
classNamestring-추가 CSS 클래스명

Sheet.Body

Sheet 본문 내용을 담는 스크롤 가능한 영역

속성타입기본값설명
childrenReact.ReactNode-Sheet 본문 내용
classNamestring-추가 CSS 클래스명

Sheet.Close

Sheet를 닫는 버튼

속성타입기본값설명
childrenReact.ReactNodeX icon닫기 버튼 내용 (기본: X 아이콘)
asChildbooleanfalse래퍼 없이 자식 요소만 렌더링

예제

왼쪽 위치

1"use client";
2
3import { useState } from "react";
4import { Button, Sheet } from "motile-ui";
5
6export default function LeftExample() {
7  const [open, setOpen] = useState(false);
8
9  return (
10    <div style={{ display: "flex", justifyContent: "center" }}>
11      <Sheet.Root open={open} onOpenChange={setOpen} position="left">
12        <Sheet.Trigger asChild>
13          <Button variant="secondary">왼쪽 Sheet 열기</Button>
14        </Sheet.Trigger>
15        <Sheet.Portal>
16          <Sheet.Overlay />
17          <Sheet.Content>
18            <Sheet.Header>
19              <Sheet.Title>왼쪽 Sheet</Sheet.Title>
20              <Sheet.Close />
21            </Sheet.Header>
22            <Sheet.Body>
23              <p>화면 왼쪽에서 슬라이드되는 Sheet입니다.</p>
24              <p>position="left" prop을 사용했습니다.</p>
25            </Sheet.Body>
26          </Sheet.Content>
27        </Sheet.Portal>
28      </Sheet.Root>
29    </div>
30  );
31}

커스텀 닫기 버튼

1"use client";
2
3import { useState } from "react";
4import { Button, Sheet } from "motile-ui";
5
6export default function CustomCloseExample() {
7  const [open, setOpen] = useState(false);
8
9  return (
10    <div style={{ display: "flex", justifyContent: "center" }}>
11      <Sheet.Root open={open} onOpenChange={setOpen}>
12        <Sheet.Trigger asChild>
13          <Button variant="primary">커스텀 닫기 버튼</Button>
14        </Sheet.Trigger>
15        <Sheet.Portal>
16          <Sheet.Overlay />
17          <Sheet.Content>
18            <Sheet.Header>
19              <Sheet.Title>커스텀 닫기 버튼</Sheet.Title>
20              <Sheet.Close asChild>
21                <button
22                  style={{
23                    padding: "8px 16px",
24                    backgroundColor: "#ef4444",
25                    color: "white",
26                    border: "none",
27                    borderRadius: "6px",
28                    cursor: "pointer",
29                    fontSize: "14px",
30                    fontWeight: "500",
31                  }}
32                >
33                  닫기
34                </button>
35              </Sheet.Close>
36            </Sheet.Header>
37            <Sheet.Body>
38              <p>asChild prop을 사용하여 커스텀 닫기 버튼을 만들 수 있습니다.</p>
39              <p>이 예제에서는 빨간색 버튼을 사용했습니다.</p>
40            </Sheet.Body>
41          </Sheet.Content>
42        </Sheet.Portal>
43      </Sheet.Root>
44    </div>
45  );
46}

닫기 옵션 제어

1"use client";
2
3import { useState } from "react";
4import { Button, Sheet } from "motile-ui";
5
6export default function CloseOptionsExample() {
7  const [open, setOpen] = useState(false);
8
9  return (
10    <div style={{ display: "flex", justifyContent: "center" }}>
11      <Sheet.Root
12        open={open}
13        onOpenChange={setOpen}
14        closeOnBackdrop={{ escapeKey: true, clickOutside: false }}
15      >
16        <Sheet.Trigger asChild>
17          <Button variant="secondary">닫기 옵션</Button>
18        </Sheet.Trigger>
19        <Sheet.Portal>
20          <Sheet.Overlay />
21          <Sheet.Content>
22            <Sheet.Header>
23              <Sheet.Title>닫기 옵션 예제</Sheet.Title>
24              <Sheet.Close />
25            </Sheet.Header>
26            <Sheet.Body>
27              <p>ESC 키로만 닫히고 외부 클릭으로는 닫히지 않습니다.</p>
28              <p>closeOnBackdrop 옵션을 세밀하게 제어할 수 있습니다.</p>
29              <ul>
30                <li>ESC 키: 활성화</li>
31                <li>외부 클릭: 비활성화</li>
32              </ul>
33            </Sheet.Body>
34          </Sheet.Content>
35        </Sheet.Portal>
36      </Sheet.Root>
37    </div>
38  );
39}

최대 너비 설정

1"use client";
2
3import { useState } from "react";
4import { Button, Sheet } from "motile-ui";
5
6export default function MaxWidthExample() {
7  const [open, setOpen] = useState(false);
8
9  return (
10    <div style={{ display: "flex", justifyContent: "center" }}>
11      <Sheet.Root open={open} onOpenChange={setOpen} maxWidth="400px">
12        <Sheet.Trigger asChild>
13          <Button variant="ghost">좁은 Sheet</Button>
14        </Sheet.Trigger>
15        <Sheet.Portal>
16          <Sheet.Overlay />
17          <Sheet.Content>
18            <Sheet.Header>
19              <Sheet.Title>최대 너비 제한</Sheet.Title>
20              <Sheet.Close />
21            </Sheet.Header>
22            <Sheet.Body>
23              <p>maxWidth="400px"로 설정된 Sheet입니다.</p>
24              <p>데스크톱에서는 최대 400px 너비로 제한됩니다.</p>
25              <p>모바일에서는 전체 너비를 차지합니다.</p>
26            </Sheet.Body>
27          </Sheet.Content>
28        </Sheet.Portal>
29      </Sheet.Root>
30    </div>
31  );
32}
Sheet | Motile UI