ComponentsP3 본문

Popover

트리거 기준으로 뜨는 논모달 패널 — 외부 클릭/Escape 닫기, 하단 공간 부족 시 상단 플립. 포커스 트랩 없이 Tab이 자연 진행합니다. 비제어(defaultOpen).

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

한눈에#

트리거 곁에 뜨는 논모달 패널입니다 — 링크·버튼이 섞인 가벼운 콘텐츠를 담고, 외부 클릭·Escape로 닫히며 포커스를 가두지 않습니다(Tab 자연 진행).

발행 정보
마지막 발행 2026-06-10 — 토큰 SSOT 기준 빌드입니다.
  • 논모달 패널
  • 외부 클릭·Escape 닫기
  • 포커스 트랩 없음
  • 하단 공간 부족 시 상단 플립
열린 상태 재현 — 트리거 하단에 패널이 앵커됩니다(실제 동작은 아래에서)

트리거를 눌러 외부 클릭·Escape 닫기를 직접 확인하세요:

사용 시점#

링크·버튼이 섞인 가벼운 비차단 패널이면 Popover — 순수 설명·액션 메뉴·차단 흐름은 다른 컴포넌트입니다.

쓴다

상세 설명·링크가 섞인 가벼운 보조 패널(외부 클릭·Escape로 가볍게 닫힘, 포커스 비가둠)

대신 Tooltip

상호작용 없는 순수 보조 설명일 때

대신 DropdownMenu

실행 가능한 메뉴 항목 목록일 때

대신 Modal

행동을 강제하는 차단형 흐름일 때

플레이그라운드#

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

테마 미리보기
import { Popover } from '@wds/ui-web';

<Popover trigger="도움말 보기">이 값은 최근 7일 평균입니다.</Popover>

변형#

패널 안에 텍스트·링크 등 임의 콘텐츠를 둘 수 있습니다.

defaultOpen — 초기 열림(이후 상태는 내부 소유)

패널은 트리거 하단에 정렬되고, 뷰포트 하단 공간이 부족하면 상단으로 플립됩니다(data-placement 속성으로 노출).

크기#

단일 크기입니다 — 트리거 높이 control.height-md(44px), 패널 폭 14rem~20rem(콘텐츠에 따라 가변).

상태#

  • 열림 — 트리거 aria-expanded="true" + 패널 렌더
  • Hover — 트리거 배경 color.surface-hover
  • Focus — 트리거 :focus-visible에 2px primary 아웃라인

논모달입니다 — 포커스 트랩이 없고, 열린 채로 Tab을 누르면 문서 흐름대로 이동하며, 닫혀도 포커스를 강제로 옮기지 않습니다. 행동을 요구하는 흐름이면 Modal/Drawer를 쓰세요.

제어/비제어 — 기본은 비제어(defaultOpen)이며 내부에서 상태를 소유합니다. open을 주면 제어 모드가 되어 부모가 상태를 소유하고, 트리거 클릭·Escape·외부 클릭 등 모든 열림/닫힘 전환은 onOpenChange(open)로 통지됩니다(렌더는 부모 open을 따름).

적응형 (ADR-012 B-P2)#

adaptToSheetOnCompact를 켜면 compact 뷰포트(< 600px)에서 작은 앵커 패널 대신 BottomSheet로 강등됩니다 — 좁은 폭의 터치 환경에 맞춘 Apple popover↔sheet 적응입니다. 이때 trigger가 시트 제목이 되고, 닫기/배경/Escape는 BottomSheet 계약을 따릅니다. opt-in이 없으면(기본) 뷰포트와 무관하게 앵커 패널을 유지하므로 기존 사용처는 영향이 없습니다.

Props#

Prop타입기본값설명
triggerReactNode트리거 콘텐츠 — 내부에서 button으로 감쌈(자체 button 전달 금지)
openboolean제어 열림 상태 — 제공하면 제어 모드(내부 상태 무시, 모든 전환이 onOpenChange로 통지)
onOpenChange(open: boolean) => void열림/닫힘 전환 통지 — 제어/비제어 모두에서 호출
defaultOpenbooleanfalse초기 열림 여부 — 이후 상태는 내부 소유(비제어, open 미제공 시)
adaptToSheetOnCompactbooleanfalsecompact 뷰포트에서 앵커 패널 대신 BottomSheet로 강등 (trigger가 시트 제목)
childrenReactNode패널 콘텐츠
classNamestring루트(div)에 적용 — 레이아웃 조정용

접근성#

  • 트리거 button에 aria-expanded + aria-controls(패널 id) 연결
  • Escape로 닫기 — 포커스 위치 무관(document 레벨)
  • 외부 클릭(mousedown)으로 닫기
  • 논모달이므로 포커스를 가두지 않습니다 — 패널 진입은 Tab 자연 진행
  • 등장 모션은 prefers-reduced-motion 존중

토큰#

component 토큰 없이 semantic을 직접 소비합니다(신설 기준 §4 미충족).

속성토큰
트리거color.surface + color.border (hover surface-hover/border-strong · pressed surface-pressed)
트리거 높이/라운드control.height-md · radius.control
패널color.surface-raised · radius.md · shadow.lg · z.dropdown
패널 텍스트font.size-body-2 · color.text
간격트리거-패널 space.2 · 패딩 space.4
모션duration.fast + ease.emphasized-decelerate