ComponentsP3 본문

BottomSheet

화면 하단에서 올라오는 모바일 선택 표면 — 포커스 트랩 · Escape/배경 닫기 · 핸들 드래그 다운 닫기 · 스크롤 잠금을 내장한 제어 컴포넌트입니다. Select/DatePicker의 mobile 모드가 이 컴포넌트를 합성합니다 (DK 사양 승격).

마지막 업데이트 2026-06-11

한눈에#

화면 하단에서 올라오는 모바일 선택 표면입니다 — 포커스 트랩·Escape/배경 닫기·핸들 드래그 다운 닫기·스크롤 잠금을 내장한 제어 컴포넌트입니다.

정렬 기준최신순 · 인기순 · 이름순 중에서 고르세요.
  • 하단 슬라이드 업
  • 핸들 드래그 다운 닫기
  • auto·half·full 높이
  • Select·DatePicker mobile 합성
열린 상태 재현 — 하단에서 시트가 올라오고 상단 컨텍스트가 일부 노출됩니다(실제 동작은 아래에서)

트리거를 눌러 핸들 드래그 다운·Escape·배경 닫기를 직접 확인하세요:

사용 시점#

모바일·터치 환경에서 하단에서 올라오는 선택·작업 표면이면 BottomSheet — 측면·적응·중앙 결정은 다른 컴포넌트입니다.

쓴다

엄지로 닿는 하단 영역에 옵션을 펼치고 핸들 드래그로 가볍게 닫는 모바일 선택 표면

대신 SideSheet

넓은 화면에선 측면 패널로 적응시킬 때

대신 Drawer

뷰포트와 무관하게 항상 측면 고정 패널일 때

대신 Modal

데스크톱 중앙 결정 다이얼로그일 때

플레이그라운드#

컨트롤로 props를 조작하면 미리보기와 코드가 실시간 갱신됩니다.

import { BottomSheet, Button } from '@wds/ui-web';

<BottomSheet
  open={open}
  onClose={() => setOpen(false)}
  title="공유"
>
  링크 복사 · 멤버 초대 · 내보내기
</BottomSheet>

변형#

footer 슬롯이 변형 축입니다 — 취소/확인 같은 액션이 필요한 흐름은 footer를 채우고(버튼은 균등 폭으로 늘어나는 모바일 관례), 단순 정보·즉시 확정 흐름(Select mobile처럼 항목 클릭이 곧 확정)은 footer 없이 본문만 씁니다.

footer 슬롯 — 있음(취소/확인) · 없음(본문만)

DK 프로젝트의 모바일 재활용 표준 표면입니다 — 선택형 오버레이 컴포넌트가 mobile prop을 받으면 팝업 대신 이 시트로 선택 UI를 렌더합니다. SelectDatePicker## 모바일 섹션을 참고하세요.

크기#

height — auto(내용 높이, 기본) · half(50dvh) · full(85dvh)

auto도 상한 85dvh를 넘지 않아 상단 컨텍스트가 항상 일부 노출됩니다. 본문이 넘치면 body 영역만 내부 스크롤되고, footer는 safe-area-inset-bottom을 반영해 홈 인디케이터를 피합니다.

표시 방식 (ADR-012 B-P2)#

variant가 표면의 성격을 가릅니다 — 기본 'modal'은 스크림으로 배경을 가리고 포커스를 가두며 배경 스크롤을 잠그는 차단형입니다(기존 동작). 'standard'는 스크림·포커스 트랩·스크롤 잠금이 없어 본문과 공존하며, 배경을 그대로 클릭할 수 있습니다(M3 standard sheet). standard는 배경 클릭으로 닫히지 않으므로 닫기 버튼이나 핸들 드래그로 닫습니다.

expandable을 켜면 핸들을 위로 끌어 halffull 디텐트를 토글합니다 — half 상태에서 아래로 끌면 닫힙니다. 높이 전환은 디텐트 단위로 스냅하며, height는 디텐트 초기값으로만 쓰입니다.

상태#

제어 컴포넌트입니다 — 열림/닫힘은 소비자의 open prop이 결정하고, 닫힘 요청(Escape·배경·닫기 버튼·핸들 드래그)은 전부 onClose 콜백으로 전달됩니다. 핸들을 80px 이상 끌어내리면 닫힘 요청이 발생하고, 그 미만은 스냅백합니다. 열림 동안 배경 body 스크롤이 잠깁니다.

Props#

Prop타입기본값설명
openboolean표시 여부 — 제어 prop
onClose() => voidEscape·배경·닫기 버튼·핸들 드래그 다운의 닫힘 요청 콜백
titleReactNode제목 — aria-labelledby 대상이라 필수
footerReactNode하단 액션 영역 — 자식이 균등 폭으로 늘어남
height'auto' | 'half' | 'full''auto'auto: 내용 높이(상한 85dvh) · half: 50dvh · full: 85dvh. expandable이면 디텐트 초기값
variant'standard' | 'modal''modal'modal: 스크림+포커스 트랩+스크롤 잠금 · standard: 본문과 공존(스크림·트랩 없음)
expandablebooleanfalse핸들을 위로 끌어 half↔full 디텐트 토글 (half에서 아래로 끌면 닫힘)
closeLabelstring'닫기'닫기 버튼 aria-label

접근성#

계약구현
역할role="dialog" + aria-modal="true"
이름titlearia-labelledby로 연결
포커스 진입열리면 패널로 이동
포커스 트랩Tab/Shift+Tab이 시트 안에서 순환
포커스 복원닫히면 이전 포커스 요소로 복귀
키보드 닫기Escape — 포커스 위치 무관(document 캡처)
드래그 핸들포인터 전용 보조 경로(aria-hidden) — 키보드는 Escape·닫기 버튼
스크롤열림 동안 배경 body 스크롤 잠금
모션슬라이드 업은 transform/opacity만 + prefers-reduced-motion 존중

토큰#

component 토큰 없이 semantic을 직접 소비합니다(신설 기준 §4 미충족 — Modal과 같은 오버레이 어휘).

속성토큰
오버레이color.overlay · z.modal
패널color.surface-raised · radius.xl(상단 모서리) · shadow.xl
핸들color.border-strong · radius.full
푸터 구분선color.border
닫기 버튼hover color.surface-hover · pressed color.surface-pressed
등장 모션duration.fast/normal · 패널 ease.emphasized-decelerate · 스크림 ease.out