ComponentsP3 본문

Popover

트리거 기준으로 뜨는 논모달 패널 — 외부 클릭/Escape 닫기는 closing exit로 부드럽게 정리하고, 하단 공간 부족 시 상단 플립. 지원 브라우저에서는 native Popover top layer로 승격하며, 포커스 트랩 없이 Tab이 자연 진행합니다. 비제어(defaultOpen).

마지막 업데이트 2026-07-01

한눈에#

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

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

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

사용 시점#

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

권장 — 이렇게 쓰세요

지양 — 이러지 마세요

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

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

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

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

플레이그라운드#

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

Popover를 직접 조작해 보세요

속성·테마·토큰을 바꾸고 React·Flutter 코드를 확인하는 풀스크린 빌더로 엽니다.

빌더 열기

플레이그라운드는 넓은 작업 영역이 필요해 웹·태블릿에서 편집할 수 있어요.

변형#

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

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

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

크기#

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

상태#

  • 열림 — 트리거 aria-expanded="true" + 패널 렌더
  • 닫힘 전환 — 외부 클릭·Escape·트리거 닫힘은 패널을 즉시 제거하지 않고 closing 상태로 유지한 뒤, anchor-origin fade/scale-out이 끝나면 unmount
  • Hover — 트리거 배경 color.surface-hover
  • Focus — 트리거 :focus-visible에 2px primary 아웃라인

논모달입니다 — 포커스 트랩이 없고, 열린 채로 Tab을 누르면 문서 흐름대로 이동하며, 닫혀도 포커스를 강제로 옮기지 않습니다. 닫힘 중 패널은 pointer-events: none으로 후속 입력을 받지 않습니다. 행동을 요구하는 흐름이면 Modal/Drawer를 쓰세요.

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

Native Popover API#

지원 브라우저에서는 열린 앵커 패널에 popover="manual"을 부여하고 showPopover({ source: trigger })로 top layer에 올립니다. 열림 상태와 외부 클릭·Escape 닫기는 React 로직이 계속 제어하며, 닫힐 때는 closing exit를 유지한 뒤 hidePopover()로 native 표면을 정리합니다.

top layer에서는 overflow 조상에 잘리지 않도록 viewport 기준 fixed 좌표를 씁니다. CSS Anchor Positioning을 지원하면 trigger와 panel에 고유 anchor name을 연결해 브라우저 배치 힌트를 함께 제공하고, 미지원·실패 환경에서는 기존 anchored absolute 표면으로 폴백합니다. 현재는 JS geometry가 정본이며, CSS Anchor Positioning 단독 full migration은 별도 검증 뒤 진행합니다.

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

adaptToSheetOnCompact를 켜면 compact 뷰포트(< 600px)에서 작은 앵커 패널 대신 BottomSheet로 강등됩니다 — 좁은 폭의 터치 환경에 맞춘 WDS popover↔sheet 적응입니다. 기본은 trigger가 시트 제목이지만, 맥락 명령처럼 본문 첫 줄에 대상 이름이 이미 있으면 sheetTitle + sheetTitleVisuallyHidden으로 접근성 이름만 남길 수 있습니다. 드래그·배경 클릭·Escape 닫기가 충분한 표면은 sheetShowCloseButton={false}로 시각 닫기 버튼을 생략할 수 있습니다. opt-in이 없으면(기본) 뷰포트와 무관하게 앵커 패널을 유지하므로 기존 사용처는 영향이 없습니다. BottomSheet로 강등된 본문은 별도 팝업 카드처럼 다시 가두지 않고 시트 본문 폭을 사용합니다. 입력 컨트롤만 자체 테두리를 유지합니다.

Props#

Prop타입기본값설명
triggerReactNode트리거 콘텐츠 — 내부에서 button으로 감싼다(자체 button 전달 금지)
openboolean제어 열림 상태 — 제공하면 제어 모드(내부 상태 무시, 모든 전환이 onOpenChange로 통지)
onOpenChange(open: boolean) => void열림/닫힘 전환 통지 — 제어/비제어 모두에서 호출
defaultOpenbooleanfalse초기 열림 여부 — 이후 상태는 내부 소유(비제어, open 미제공 시)
adaptToSheetOnCompactbooleanfalsetrue면 compact 뷰포트에서 앵커 패널 대신 BottomSheet로 강등 (ADR-012 B-P2 — 본문은 nested popup chrome 없이 시트 폭 사용)
sheetTitleReactNodecompact BottomSheet로 강등할 때 사용할 제목. 미지정 시 trigger를 사용한다.
sheetTitleVisuallyHiddenbooleanfalsecompact BottomSheet 제목을 접근성 이름으로만 남기고 화면에서는 숨긴다.
sheetShowCloseButtonbooleantruecompact BottomSheet 닫기 버튼 표시 여부.
classNamestring루트(div)에 적용 — 레이아웃 조정용
childrenReactNode패널 콘텐츠
refRef<HTMLButtonElement>트리거 <button> 요소로 전달되는 ref (React 19 ref-as-prop). adaptToSheetOnCompact로 BottomSheet 강등 시에도 트리거는 항시 마운트 — ref는 양 모드에서 동일하게 트리거를 가리킨다(패널 ref 아님 — COMPONENT_API §2 분류).

접근성#

  • 트리거 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
모션등장 spring.effect.fast + ease.emphasized-decelerate, 닫힘 spring.effect.fast + ease.emphasized-accelerate