Floating
Popover
트리거 요소를 기준으로 열리는 팝오버. 클릭으로 토글하고 외부 클릭이나 ESC로 닫습니다.
설치
npm install @woon-ui/popoverimport { Popover } from '@woon-ui/popover'
import '@woon-ui/popover/css'개요
import { Popover } from '@woon-ui/popover'Popover는 플러그인 등록 없이 바로 사용할 수 있는 컴파운드 컴포넌트입니다.
@floating-ui/react 기반으로 위치를 자동 계산하며, 충돌 감지와 자동 뒤집기를 지원합니다.
기본 사용법
import { Popover } from '@woon-ui/popover'
<Popover.Root>
<Popover.Trigger>
<button>열기</button>
</Popover.Trigger>
<Popover.Content>
<div>팝오버 콘텐츠</div>
</Popover.Content>
</Popover.Root>Preview
컴파운드 컴포넌트
Popover.Root
| Prop | Type | Default |
|---|---|---|
| open | boolean | — |
| 제어 모드: 열림 상태 | ||
| defaultOpen | boolean | false |
| 비제어 모드: 초기 열림 여부 | ||
| onOpenChange | (open: boolean) => void | — |
| 열림 상태 변경 콜백 | ||
Popover.Trigger
asChild를 사용하면 Trigger의 기능을 자식 요소에 위임합니다. 기본적으로 자체 button을 렌더합니다.
Popover.Content
| Prop | Type | Default |
|---|---|---|
| side | 'top'|'right'|'bottom'|'left' | 'bottom' |
| 팝오버가 표시되는 방향 | ||
| align | 'start'|'center'|'end' | 'center' |
| 트리거를 기준으로 한 정렬 | ||
| sideOffset | number | 6 |
| 트리거와의 간격 (px) | ||
| alignOffset | number | 0 |
| 정렬 방향 오프셋 (px) | ||
| avoidCollisions | boolean | true |
| 화면 밖으로 넘어갈 때 자동으로 반대쪽으로 뒤집습니다 | ||
| collisionPadding | number | 8 |
| 화면 가장자리 여백 (px) | ||
| trapFocus | boolean | false |
| 활성화 시 Tab 포커스가 팝오버 내부에서만 순환합니다. 비활성화(기본) 시 Tab으로 팝오버 밖으로 나가면 자동으로 닫힙니다. | ||
Popover.Close
asChild를 사용하면 Close의 기능을 자식 요소에 위임합니다.
위치 설정
side와 align을 조합해 12가지 방향을 지정할 수 있습니다.
<Popover.Content side="top" align="start" />
<Popover.Content side="right" align="center" />
<Popover.Content side="bottom" align="end" />avoidCollisions가 true일 때 화면 밖으로 넘어가면 자동으로 반대쪽으로 뒤집힙니다.
Preview
제어 모드
open과 onOpenChange를 전달하면 외부에서 상태를 제어할 수 있습니다.
const [open, setOpen] = useState(false)
<Popover.Root open={open} onOpenChange={setOpen}>
<Popover.Trigger>열기</Popover.Trigger>
<Popover.Content>
<button onClick={() => setOpen(false)}>닫기</button>
</Popover.Content>
</Popover.Root>비제어 모드에서는 defaultOpen으로 초기 상태만 설정합니다.
스타일
@woon-ui/popover/css로 기본 스타일이 적용됩니다. 특정 값만 바꾸려면 선택자로 override하세요.
[data-woon-popover-content] {
background: #1a1a1a;
color: #fff;
}완전히 교체하려면 @woon-ui/react/css import를 제거하고 아래 CSS를 복사해서 수정하세요.
[data-woon-popover-floating] { z-index: 500; }
[data-woon-popover-content],
[data-woon-popover-content] *,
[data-woon-popover-content] *::before,
[data-woon-popover-content] *::after {
box-sizing: border-box;
}
[data-woon-popover-content] {
width: max-content;
max-width: calc(100vw - 1rem);
padding: 0.75rem 1rem;
background: #fff;
border-radius: 8px;
box-shadow:
0 0 0 1px rgba(0, 0, 0, 0.06),
0 4px 16px rgba(0, 0, 0, 0.12);
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
font-size: 0.875rem;
line-height: 1.5;
outline: none;
}
[data-woon-popover-content][data-state='open'] {
animation: woon-popover-in 160ms cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes woon-popover-in {
from { opacity: 0; scale: 0.97; }
to { opacity: 1; scale: 1; }
}
@media (prefers-reduced-motion) {
[data-woon-popover-content] { animation: none !important; }
}접근성
- Trigger에
aria-expanded,aria-controls,aria-haspopup="dialog"자동 적용 - Content에
role="dialog"적용 - 외부 클릭 시 닫기
- ESC 키로 닫기 (Dialog와 escape-stack 공유)
trapFocus활성화 시 Tab 키가 팝오버 내부에서만 순환- 기본(
trapFocus=false)에서는 Tab으로 밖으로 나가면 자동 닫힘 - 닫힐 때 Trigger로 포커스 복귀
data 속성
| 속성 | 대상 | 값 |
|---|---|---|
data-woon-popover-content | Content | — |
data-state | Content | "open" |
data-side | Content | "top" "right" "bottom" "left" |
data-align | Content | "start" "center" "end" |
[data-woon-popover-content] {
background: white;
border: 1px solid #e5e5e5;
border-radius: 8px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
}