본문으로 건너뛰기

BottomSheet

화면 하단에서 위로 슬라이드하며 나타나는 모달 인터페이스입니다. 제스처로 드래그하여 닫을 수 있으며, 키보드가 나타나면 자동으로 위치를 조정합니다.

실제 앱에서 확인하세요

웹에서는 시트 열기·닫기와 기본 레이아웃을 확인할 수 있습니다. 네이티브 드래그 감도, 소프트 키보드 회피, SafeArea, Android 하드웨어 뒤로가기와 dismissable 우선순위는 실제 iOS·Android 앱에서 확인하세요.

앱 예제 Playgroundv1.0.2
Interactive exampleBottomSheet 로컬 웹 예제

예제를 선택하면 현재 저장소 소스로 만든 Expo Web 화면을 불러옵니다.

웹 미지원 또는 플랫폼 종속 기능은 실제 iOS·Android 앱에서 확인하세요.

BottomSheetOverlay 렌더러

BottomSheetOverlayOverlayProvider 내부에서 시트 상태, 드래그 제스처, 배경 터치, Android back 처리를 연결하는 렌더러입니다. 앱에서 직접 마운트하면 Provider가 관리하는 닫힘 콜백과 우선순위를 우회하게 되므로 showBottomSheet()로 여세요.

기본 사용법

import { useOverlay } from '@0610studio/zs-ui';

function MyComponent() {
const { showBottomSheet } = useOverlay();

const handleOpenBottomSheet = () => {
showBottomSheet({
component: <MyBottomSheetContent />,
options: {
height: 300,
padding: 20,
},
});
};

return <Button title="BottomSheet 열기" onPress={handleOpenBottomSheet} />;
}

API 참조

showBottomSheet 함수

showBottomSheet(props: ShowBottomSheetProps): void

ShowBottomSheetProps 인터페이스

PropTypeDefaultDescription
componentReact.ReactNodeRequiredBottom Sheet 내부에 표시할 컴포넌트
headerComponentReact.ReactNodeundefined상단에 표시할 헤더 컴포넌트
optionsBottomSheetOptions{}Bottom Sheet 옵션

BottomSheetOptions 인터페이스

PropTypeDefaultDescription
dismissablebooleantrue배경 터치·아래로 끌기 제스처로 닫을 수 있는지 여부. false여도 hideOverlay('bottomSheet') 호출로는 닫힙니다
onClose() => voidundefined시트가 어떤 경로(버튼·배경 터치·드래그·뒤로가기)로 닫히든 정확히 1회 호출되는 콜백
isBackgroundTouchClosebooleantrueDeprecateddismissable을 사용하세요. dismissable 미지정 시에만 참조되며, 이제 배경 터치뿐 아니라 제스처 닫힘까지 함께 제어합니다
marginHorizontalnumber10시트의 좌우 여백
marginBottomnumber10시트의 하단 여백
heightnumber | 'auto'300시트의 높이 ('auto' 지정 시 컨텐츠 크기에 맞춤)
maxHeightnumber화면 높이시트의 최대 높이 제한
paddingnumber14시트 내부 패딩
foldableSingleScreenbooleanfalse폴더블 디바이스에서 단일 화면 모드 사용 여부
type'floating' | 'fixed''floating'시트 타입 (floating: 떠있는 형태, fixed: 화면 하단에 고정)

특징

  • 제스처 지원: 드래그하여 닫을 수 있습니다
  • 키보드 대응: 키보드가 나타나면 자동으로 위치를 조정합니다
  • 애니메이션: 부드러운 스프링 애니메이션이 적용됩니다
  • 폴더블 디바이스 지원: 폴더블 디바이스에서도 올바르게 동작합니다

예제

기본 사용

import { useOverlay, ZSText, ZSPressable } from '@0610studio/zs-ui';
import { View } from 'react-native';

function MyBottomSheetContent() {
const { hideOverlay } = useOverlay();

return (
<View>
<ZSText typo="heading.2">제목</ZSText>
<ZSText typo="body.2">내용</ZSText>
<ZSPressable onPress={() => hideOverlay('bottomSheet')}>
<ZSText typo="body.2">닫기</ZSText>
</ZSPressable>
</View>
);
}

function MyComponent() {
const { showBottomSheet } = useOverlay();

const handleOpenBottomSheet = () => {
showBottomSheet({
component: <MyBottomSheetContent />,
options: {
height: 300,
},
});
};

return <Button title="BottomSheet 열기" onPress={handleOpenBottomSheet} />;
}

헤더 컴포넌트 사용

import { useOverlay, ZSText } from '@0610studio/zs-ui';
import { View } from 'react-native';

function MyComponent() {
const { showBottomSheet } = useOverlay();

const handleOpenBottomSheet = () => {
showBottomSheet({
headerComponent: (
<View style={{ padding: 20 }}>
<ZSText typo="heading.2">헤더</ZSText>
</View>
),
component: <MyBottomSheetContent />,
options: {
height: 400,
},
});
};

return <Button title="BottomSheet 열기" onPress={handleOpenBottomSheet} />;
}

Fixed 타입 (화면 하단 고정)

import { useOverlay } from '@0610studio/zs-ui';

function MyComponent() {
const { showBottomSheet } = useOverlay();

const handleOpenBottomSheet = () => {
showBottomSheet({
component: <MyBottomSheetContent />,
options: {
height: 500,
type: 'fixed',
padding: 20,
},
});
};

return <Button title="BottomSheet 열기" onPress={handleOpenBottomSheet} />;
}

커스텀 여백

import { useOverlay } from '@0610studio/zs-ui';

function MyComponent() {
const { showBottomSheet } = useOverlay();

const handleOpenBottomSheet = () => {
showBottomSheet({
component: <MyBottomSheetContent />,
options: {
height: 400,
marginHorizontal: 20,
marginBottom: 30,
padding: 30,
},
});
};

return <Button title="BottomSheet 열기" onPress={handleOpenBottomSheet} />;
}

배경 터치·제스처로 닫기 비활성화

dismissable: false를 지정하면 배경 터치와 아래로 끌기 제스처 모두 무시됩니다. 사용자가 반드시 시트 내부 동작(버튼 등)으로만 닫아야 할 때 사용하세요.

import { useOverlay } from '@0610studio/zs-ui';

function MyComponent() {
const { showBottomSheet } = useOverlay();

const handleOpenBottomSheet = () => {
showBottomSheet({
component: <MyBottomSheetContent />,
options: {
height: 300,
dismissable: false,
},
});
};

return <Button title="BottomSheet 열기" onPress={handleOpenBottomSheet} />;
}

BottomSheet 닫기

import { useOverlay, ZSPressable, ZSText } from '@0610studio/zs-ui';
import { View } from 'react-native';

function MyBottomSheetContent() {
const { hideOverlay } = useOverlay();

return (
<View>
<ZSPressable onPress={() => hideOverlay('bottomSheet')}>
<ZSText typo="body.2">닫기</ZSText>
</ZSPressable>
</View>
);
}