BottomSheet
BottomSheet와 useBottomSheet usage를 기준으로 하단 시트 구조와 컴포넌트 등록형 popup 흐름을 정리한 가이드 페이지입니다.
BottomSheet
BottomSheet는 PopupBase를 기반으로 한 하단 시트형 팝업입니다. 필터, 짧은 선택지, 빠른 액션처럼 현재 화면을 유지한 채 즉시 반응해야 하는 흐름을 정리합니다.
title | children | footer | hasCloseButton | shouldCloseOnBackdrop | shouldCloseOnEscape | className
ReactNode | ReactNode | ReactNode | boolean | boolean | boolean | string- BottomSheet는 `PopupBase`의 shell을 유지한 채 variant만 하단 시트로 고정한 팝업입니다.
- hook에서는 `component`만 등록하고, 필터 목록이나 선택지처럼 실제 콘텐츠 데이터는 각 BottomSheet 컴포넌트 내부에서 직접 구성합니다.
- backdrop 닫힘과 close button 노출 여부도 개별 시트 컴포넌트 안의 `BottomSheet`에 바로 선언합니다.
PopupBase shell / design props
title | icon | description | children | footer | className | panelClassName | bodyClassName | footerClassName | contentAlign | hasCloseButton | closeButtonLabel | shouldCloseOnBackdrop | shouldCloseOnEscape | dialogLabel | onClickClose- BottomSheet은 `PopupBase` shell을 감싼 wrapper이므로, custom popup 컴포넌트 안에서 `title`, `footer`, `contentAlign`, `panelClassName` 같은 shell props를 직접 설정할 수 있습니다. `size`는 LayerPopup 전용입니다.
- 반대로 `id`, `open`, `onRequestClose`, `onExited`는 디자인 props가 아니라 `PopupHost`가 runtime에 주입하는 인스턴스 제어용 props입니다.
- 그래서 보통 custom popup 컴포넌트에서는 `...runtimeProps`를 펼친 뒤, 필요한 shell props만 추가 선언하는 패턴을 사용합니다.
function ExamplePopup(runtimeProps: BottomSheetComponentProps) {
return (
<BottomSheet
{...runtimeProps}
title="팝업 제목"
description="PopupBase shell props를 직접 제어하는 예시"
contentAlign="left"
panelClassName="customPanel"
bodyClassName="customBody"
footerClassName="customFooter"
hasCloseButton
closeButtonLabel="닫기"
shouldCloseOnBackdrop={false}
shouldCloseOnEscape={true}
dialogLabel="상세 설정 팝업"
onClickClose={() => {
console.log("close button clicked");
}}
footer={<button onClick={runtimeProps.onRequestClose}>닫기</button>}
>
<div>custom contents</div>
</BottomSheet>
);
}- Header / content: `title`, `icon`, `description`, `children`, `footer`
- Layout / style: `contentAlign`, `className`, `panelClassName`, `bodyClassName`, `footerClassName`
- Close / accessibility: `hasCloseButton`, `closeButtonLabel`, `shouldCloseOnBackdrop`, `shouldCloseOnEscape`, `dialogLabel`, `onClickClose`
- Runtime from host: `id`, `open`, `onRequestClose`, `onExited`
component | id
React.ComponentType<BottomSheetComponentProps> | string | undefined- BottomSheet도 LayerPopup과 동일하게 `component` 자체를 등록하는 구조입니다.
- hook 호출부에서는 어떤 시트를 띄울지만 결정하고, 시트 안의 제목, 설명, 리스트, 버튼은 해당 popup 컴포넌트가 직접 가집니다.
bottomSheet.open({
id: "delivery-slot-bottom-sheet",
component: DeliverySlotBottomSheet,
});useBottomSheet()
{ open: (options) => string; close: (id?: string) => void; closeAll: () => void; bottomSheets: Array<{ id: string; type: "bottomSheet"; status: "open" | "closing" }>; }- `useBottomSheet()`은 등록형 BottomSheet를 전역 store로 열고 닫는 훅입니다.
- `close(id?)`는 특정 시트 또는 가장 마지막 시트를 닫고, `closeAll()`은 현재 열린 BottomSheet 타입만 한 번에 닫습니다.
- 여러 개를 연 상태에서는 마지막 시트부터 정리되므로 모바일 흐름을 단계적으로 되돌릴 때도 같은 메서드를 그대로 사용할 수 있습니다.
usePopupStack()
Array<{ id: string; type: "alert" | "confirm" | "layerPopup" | "bottomSheet" | "fullPopup"; status: "open" | "closing" }>전역 popup stack을 그대로 조회할 수 있어서 BottomSheet가 다른 popup과 섞여 떠 있는 상태도 한 번에 확인할 수 있습니다.
열린 팝업이 없습니다.
BottomSheet props 한눈에 보기
BottomSheet shell에서 직접 제어하는 디자인 props와 PopupHost가 주입하는 runtime props를 함께 정리했습니다.
| Prop | Type | Default | Required | Description |
|---|---|---|---|---|
title | description | children | footer | React.ReactNode | undefined | Optional | 하단 시트 흐름에서 필요한 헤더, 본문, 하단 액션 영역을 조합합니다. |
icon | React.ReactNode | null | undefined | Optional | description 위에 아이콘 영역을 추가합니다. null이면 아이콘 슬롯을 비웁니다. |
contentAlign | "left" | "center" | "left" | Optional | 본문 텍스트와 footer 정렬 기준을 제어합니다. |
hasCloseButton | closeButtonLabel | boolean | string | true | "팝업 닫기" | Optional | 상단 닫기 버튼 노출 여부와 접근성 라벨을 제어합니다. |
shouldCloseOnBackdrop | shouldCloseOnEscape | boolean | true | true | Optional | backdrop 클릭과 Escape 키로 닫힐지 제어합니다. topmost popup에만 Escape가 반응합니다. |
dialogLabel | string | "바텀시트 팝업" | Optional | title이 없을 때 dialog aria-label fallback으로 사용합니다. |
className | panelClassName | bodyClassName | footerClassName | string | undefined | Optional | 루트, 패널, body, footer wrapper 각각에 커스텀 클래스를 추가합니다. |
onClickClose | () => void | undefined | Optional | 닫기 버튼 클릭 시 onRequestClose 직전에 부가 동작을 실행합니다. |
id | open | onRequestClose | onExited | isTopmost | runtime props from PopupHost | injected | Optional | 커스텀 bottom sheet 컴포넌트에서는 보통 `...runtimeProps`로 받고, PopupHost가 lifecycle을 주입합니다. |
BottomSheet은 PopupBase의 bottomSheet variant wrapper입니다. 모바일/빠른 선택 흐름을 전제로 하므로 size는 외부에서 받지 않습니다.useBottomSheet API 한눈에 보기
BottomSheet 등록과 stack 제어에 사용하는 hook API를 표로 정리했습니다.
| Prop | Type | Default | Required | Description |
|---|---|---|---|---|
open | (options: BottomSheetOptions) => string | - | Required | 새 BottomSheet 인스턴스를 stack에 추가하고 생성된 id를 반환합니다. |
open.options.component | React.ComponentType<BottomSheetComponentProps> | - | Required | PopupHost가 렌더링할 custom BottomSheet 컴포넌트입니다. runtime props를 받아야 합니다. |
open.options.id | string | auto generated id | Optional | 특정 인스턴스를 직접 추적하거나 close(id) 대상으로 삼고 싶을 때 사용합니다. |
close | (id?: string) => void | - | Required | id를 주면 해당 BottomSheet를 닫고, 생략하면 현재 타입 stack의 마지막 popup을 닫습니다. |
closeAll | () => void | - | Required | 현재 열린 BottomSheet 타입 인스턴스만 모두 closing 상태로 전환합니다. |
bottomSheets | Array<{ id: string; type: "bottomSheet"; status: "open" | "closing" }> | - | Required | 전역 popup stack 중 BottomSheet 항목만 필터링한 snapshot 배열입니다. |
useBottomSheet()도 store action을 감싼 얇은 wrapper입니다. 실제 shell props와 콘텐츠는 등록한 component 안에서 선언합니다.