# Bottom Sheet
URL: /react/components/bottom-sheet
Source: https://github.com/daangn/seed-design/blob/dev/docs/content/react/components/bottom-sheet.mdx
화면 하단에서 올라오는 모달 컴포넌트입니다. 추가 정보나 액션 목록을 제공하면서도 현재 컨텍스트를 유지할 때 사용됩니다.
사용 가능 버전: @seed-design/react@0.0.1, @seed-design/css@0.0.1
## Preview
```tsx
import { ActionButton } from "seed-design/ui/action-button";
import {
BottomSheetBody,
BottomSheetContent,
BottomSheetFooter,
BottomSheetRoot,
BottomSheetTrigger,
} from "seed-design/ui/bottom-sheet";
const BottomSheetPreview = () => {
return (
Open
{/* If you need to omit padding, pass px={0}. */}
Content
확인
);
};
export default BottomSheetPreview;
```
Stackflow와 Bottom Sheet를 함께 사용하는 방법에 대해 알아보세요.
## Installation
- npm: npx @seed-design/cli@latest add ui:bottom-sheet
- pnpm: pnpm dlx @seed-design/cli@latest add ui:bottom-sheet
- yarn: yarn dlx @seed-design/cli@latest add ui:bottom-sheet
- bun: bun x @seed-design/cli@latest add ui:bottom-sheet
## Props
### `BottomSheetRoot`
### `BottomSheetTrigger`
### `BottomSheetContent`
### `BottomSheetBody`
### `BottomSheetFooter`
## Examples
### Trigger
``는 `asChild` 패턴을 사용해 자식 요소가 BottomSheet를 열 수 있도록 합니다.
``는 `aria-haspopup="dialog"` 속성을 설정하고, `BottomSheet`의 `open` 상태에 따라 `aria-expanded` 속성을 자동으로 설정합니다. 이 속성은 스크린 리더와 같은 보조 기술에 유용합니다.
```tsx
import { ActionButton } from "seed-design/ui/action-button";
import {
BottomSheetBody,
BottomSheetContent,
BottomSheetFooter,
BottomSheetRoot,
BottomSheetTrigger,
} from "seed-design/ui/bottom-sheet";
const BottomSheetTriggerExample = () => {
return (
Open
Content
확인
);
};
export default BottomSheetTriggerExample;
```
### Controlled
Trigger 외의 방식으로 BottomSheet를 열고 닫을 수 있습니다. 이 경우 `open` prop을 사용하여 BottomSheet의 상태를 제어합니다.
```tsx
import { useState } from "react";
import { ActionButton } from "seed-design/ui/action-button";
import {
BottomSheetBody,
BottomSheetContent,
BottomSheetFooter,
BottomSheetRoot,
} from "seed-design/ui/bottom-sheet";
const BottomSheetControlled = () => {
const [open, setOpen] = useState(false);
const scheduleOpen = () => {
setTimeout(() => {
setOpen(true);
}, 1000);
};
return (
<>
1초 후 열기
{/* If you need to omit padding, pass px={0}. */}
Content
확인
>
);
};
export default BottomSheetControlled;
```
### `onOpenChange` Details
`onOpenChange` 두 번째 인자로 `details`가 제공됩니다.
#### `reason`
**열릴 때** (`open: true`)
- `"trigger"`: `BottomSheetTrigger` (`BottomSheet.Trigger`)로 열림
**닫힐 때** (`open: false`)
- `"closeButton"`: `BottomSheet.CloseButton`으로 닫힘
- `"escapeKeyDown"`: ESC 키 사용
- `"interactOutside"`: 외부 영역 클릭
- `"drag"`: 드래그로 닫힘
- `"handleClickOnLastSnapPoint"`: 마지막 스냅 포인트에서 핸들 클릭으로 닫힘
```tsx
import { HStack, Text, VStack } from "@seed-design/react";
import { useState } from "react";
import { ActionButton } from "seed-design/ui/action-button";
import {
BottomSheetBody,
BottomSheetContent,
BottomSheetRoot,
BottomSheetTrigger,
} from "seed-design/ui/bottom-sheet";
const snapPoints = ["200px", "400px", 1];
export default function BottomSheetOnOpenChangeReason() {
const [open, setOpen] = useState(false);
const [snap, setSnap] = useState(snapPoints[0]);
const [openReason, setOpenReason] = useState(null);
const [closeReason, setCloseReason] = useState(null);
return (
{
setOpen(open);
(open ? setOpenReason : setCloseReason)(details?.reason ?? null);
}}
snapPoints={snapPoints}
activeSnapPoint={snap}
setActiveSnapPoint={setSnap}
>
열기
ESC 키를 누르거나, 외부 영역을 클릭하거나, 아래로 스와이프하거나, 핸들을 탭하여 snap
point를 순환해보세요.
마지막 열림 이유: {openReason ?? "-"}
마지막 닫힘 이유: {closeReason ?? "-"}
);
}
```
### Header Align
``에 `headerAlign` prop을 설정하여 title과 description의 정렬을 설정할 수 있습니다.
```tsx
import { HStack } from "@seed-design/react";
import { ActionButton } from "seed-design/ui/action-button";
import {
BottomSheetBody,
BottomSheetContent,
BottomSheetFooter,
BottomSheetRoot,
BottomSheetTrigger,
} from "seed-design/ui/bottom-sheet";
const BottomSheetHeaderAlign = () => {
return (
Left (기본값)
Content
확인
Center
Content
확인
);
};
export default BottomSheetHeaderAlign;
```
### Max Height
``에 `maxHeight` prop을 전달하여 BottomSheet의 최대 높이를 설정할 수 있습니다.
```tsx
import { Box, VStack } from "@seed-design/react";
import { ActionButton } from "seed-design/ui/action-button";
import {
BottomSheetBody,
BottomSheetContent,
BottomSheetFooter,
BottomSheetRoot,
BottomSheetTrigger,
} from "seed-design/ui/bottom-sheet";
const BottomSheetMaxHeight = () => {
return (
Open
{/* If you need to omit padding, pass px={0}. */}
확인
);
};
export default BottomSheetMaxHeight;
```
### Snap Points
`snapPoints` prop을 사용하여 BottomSheet의 커스텀 스냅 포인트를 설정할 수 있습니다.
```tsx
import { useState } from "react";
import { ActionButton } from "seed-design/ui/action-button";
import {
BottomSheetBody,
BottomSheetContent,
BottomSheetFooter,
BottomSheetRoot,
BottomSheetTrigger,
} from "seed-design/ui/bottom-sheet";
const snapPoints = ["300px", "500px", 1];
const BottomSheetSnapPoints = () => {
const [snap, setSnap] = useState(snapPoints[0]);
return (
Open
Content
확인
);
};
export default BottomSheetSnapPoints;
```
### Fade From Index
``에 `fadeFromIndex` prop을 전달하여 뒷 배경이 어두워지는 시작 인덱스를 설정할 수 있습니다.
```tsx
import { useState } from "react";
import { ActionButton } from "seed-design/ui/action-button";
import {
BottomSheetBody,
BottomSheetContent,
BottomSheetFooter,
BottomSheetRoot,
BottomSheetTrigger,
} from "seed-design/ui/bottom-sheet";
const snapPoints = ["300px", "500px", 1];
const BottomSheetFadeFromIndex = () => {
const [snap, setSnap] = useState(snapPoints[0]);
return (
Open
Content
확인
);
};
export default BottomSheetFadeFromIndex;
```
### Show Handle
``에 `showHandle` prop을 전달하여 Handle을 표시할 수 있습니다.
기본 값은 `false`입니다.
```tsx
import { useState } from "react";
import { ActionButton } from "seed-design/ui/action-button";
import {
BottomSheetBody,
BottomSheetContent,
BottomSheetFooter,
BottomSheetRoot,
BottomSheetTrigger,
} from "seed-design/ui/bottom-sheet";
const BottomSheetShowHandle = () => {
const [isSheetOpen, setIsSheetOpen] = useState(false);
return (
Open
{/* If you need to omit padding, pass px={0}. */}
Content
setIsSheetOpen(false)}>
닫기
);
};
export default BottomSheetShowHandle;
```
### Show Close Button
``에 `showCloseButton` prop을 전달하여 닫기 버튼을 표시할 수 있습니다.
기본 값은 `true`입니다.
showCloseButton을 `false`로 설정하면 닫기 버튼이 표시되지 않습니다.
이 경우 유저가 BottomSheet를 닫을 수 있는 방법을 제공해야 합니다.
```tsx
import { useState } from "react";
import { ActionButton } from "seed-design/ui/action-button";
import {
BottomSheetBody,
BottomSheetContent,
BottomSheetFooter,
BottomSheetRoot,
BottomSheetTrigger,
} from "seed-design/ui/bottom-sheet";
const BottomSheetShowCloseButton = () => {
const [isSheetOpen, setIsSheetOpen] = useState(false);
return (
Open
{/* If you need to omit padding, pass px={0}. */}
Content
setIsSheetOpen(false)}>
닫기
);
};
export default BottomSheetShowCloseButton;
```
### Dismissible
`dismissible` prop을 `false`로 설정하면 closeOnEscape, closeOnInteractOutside, draggable 기능이 비활성화됩니다.
의도적으로 BottomSheet를 닫을 수 없게 하고 싶을 때 사용합니다. 이외에는 유저가 BottomSheet를 닫을 수 있는 방법을 제공해야 합니다.
```tsx
import { useState } from "react";
import { ActionButton } from "seed-design/ui/action-button";
import {
BottomSheetBody,
BottomSheetContent,
BottomSheetFooter,
BottomSheetRoot,
BottomSheetTrigger,
} from "seed-design/ui/bottom-sheet";
const BottomSheetDismissible = () => {
const [open, setOpen] = useState(false);
return (
Open
{/* If you need to omit padding, pass px={0}. */}
Content
setOpen(false)}>
닫기
);
};
export default BottomSheetDismissible;
```
### With Scroll Fog
``에 [Scroll Fog](/react/components/scroll-fog)를 사용하여 스크롤 힌트 효과를 적용할 수 있습니다.
ScrollFog는 항상 효과를 표시하므로, 충분한 padding을 제공해야 합니다.
권장 padding인 하단 `80px`, 상단 `20px`을 유지해야 합니다.
```tsx
import { Box, ScrollFog, VStack } from "@seed-design/react";
import { ActionButton } from "seed-design/ui/action-button";
import {
BottomSheetBody,
BottomSheetContent,
BottomSheetFooter,
BottomSheetRoot,
BottomSheetTrigger,
} from "seed-design/ui/bottom-sheet";
const BottomSheetMaxHeight = () => {
return (
Open
{/* If you need to omit padding, pass px={0}. */}
확인
);
};
export default BottomSheetMaxHeight;
```
### Bottom Inset
``에 `style` prop을 전달하여 아래 여백을 주기 위해 사용합니다.
```tsx
import { ActionButton } from "seed-design/ui/action-button";
import {
BottomSheetBody,
BottomSheetContent,
BottomSheetFooter,
BottomSheetRoot,
BottomSheetTrigger,
} from "seed-design/ui/bottom-sheet";
const BottomSheetBottomInset = () => {
return (
Open
{/* If you need to omit padding, pass px={0}. */}
Content
확인
);
};
export default BottomSheetBottomInset;
```
### Handle Only
``에 `handleOnly` prop을 제공하는 경우 쓸어서(swipe) Bottom Sheet를 움직일 수 있는 영역이 핸들 부분으로 제한됩니다.
이 옵션은 ``와 함께 사용할 때만 작동합니다.
```tsx
import { ActionButton } from "seed-design/ui/action-button";
import {
BottomSheetBody,
BottomSheetContent,
BottomSheetFooter,
BottomSheetRoot,
BottomSheetTrigger,
} from "seed-design/ui/bottom-sheet";
const BottomSheetHandleOnly = () => {
return (
Open
Content
확인
);
};
export default BottomSheetHandleOnly;
```
### Skip Animation
`skipAnimation` prop을 사용하여 BottomSheet의 enter/exit 애니메이션을 건너뛸 수 있습니다.
```tsx
import { ActionButton } from "seed-design/ui/action-button";
import {
BottomSheetBody,
BottomSheetContent,
BottomSheetFooter,
BottomSheetRoot,
BottomSheetTrigger,
} from "seed-design/ui/bottom-sheet";
const BottomSheetSkipAnimation = () => {
return (
Open
Content
확인
);
};
export default BottomSheetSkipAnimation;
```