Popover
자신을 연 컨트롤 옆에 열리는 시트입니다. Tooltip과 달리 그대로 떠 있고 포인터와 키보드로 닿을 수 있어서, 안의 내용을 누르고 입력할 수 있습니다.
import { Button, Popover } from 'neba';
<Popover trigger={<Button variant="outline">Share</Button>} title="Share this page">
<TextField size="sm" label="Link" defaultValue="https://…" readOnly />
</Popover>;Props
| Prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
| locale | string | — | BCP 47 태그. ×의 접근성 이름을 이 언어로 씁니다. 지원하지 않는 태그는 영어로 |
| trigger | ReactElement | — | popup이 매달리고 또 popup을 여는 요소. ref를 받고 props를 펼치는 요소 하나여야 합니다. 모든 Neba 컴포넌트가 그렇습니다 |
| size공통 | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'md' | 타입 스케일과 여백, 그리고 popup이 넓어질 수 있는 한계까지 함께 정합니다 |
| color공통 | 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info' | 'primary' | 의미론적 색 역할. 시트는 물들지 않으므로 가장자리와 포커스 링에만 나타납니다 |
| density공통 | 'default' | 'compact' | 'default' | 여백만 바꿉니다 |
| title | ReactNode | — | 제목. popup의 이름이 되는 요소로 렌더링됩니다 |
| description | ReactNode | — | 제목 아래 한 줄이자 popup의 접근성 설명 |
| children | ReactNode | — | 본문 |
| side | 'top' | 'right' | 'bottom' | 'left' | 'bottom' | 트리거의 어느 쪽에 뜨는지. 자리가 없으면 반대쪽으로 넘어갑니다 |
| align | 'start' | 'center' | 'end' | 'center' | 그 변을 따라 놓이는 위치 |
| sideOffset | number | 6 | 트리거와의 거리(px) |
| alignOffset | number | 0 | 그 변을 따라 밀어내는 거리(px) |
| arrow | boolean | false | 트리거를 가리키는 작은 쐐기. Tooltip과 달리 기본이 꺼짐입니다. 이 표면은 반투명이고, popup의 상자 밖으로 튀어나온 쐐기는 그 backdrop을 함께 가져갈 수 없습니다 |
| open | boolean | — | 열림 여부. onOpenChange와 함께 |
| defaultOpen | boolean | false | 비제어 popover의 초기 상태 |
| onOpenChange | (open: boolean) => void | — | 열리거나 닫힐 때 호출 |
| modal | boolean | 'trap-focus' | false | 뒤 페이지를 가져갈지. 기본이 꺼짐인 것이 popover와 Dialog를 가릅니다. popover는 페이지 대신이 아니라 페이지 옆의 한 부분입니다 |
| dismissible | boolean | true | Escape나 바깥 클릭으로 닫히는지. 꺼도 PopoverClose는 통과하므로 갇히지 않습니다 |
| showClose | boolean | false | 모서리의 × |
| closeLabel | string | — | × 버튼의 접근성 이름 |
| width | number | string | — | size가 정한 최대 너비를 대신할 값. 숫자는 픽셀입니다 |
<div>의 native 속성은 popup으로 전달됩니다. color · title · children만 위 표와 이름이 겹쳐 제외됩니다.
PopoverClose는 Base UI의 Popover.Close를 그대로 내보낸 것입니다. render prop을 주면 어떤 요소든 자기가 속한 popup을 닫습니다: <PopoverClose render={<Button>Apply</Button>} />.
공통 축은 prop 규칙에서 설명합니다.
예시
side와 align
side는 trigger의 어느 변에 popup이 놓일지, align은 그 변을 따라 어디에 놓일지입니다. 창에 자리가 없으면 반대쪽으로 자동으로 넘어갑니다. sideOffset으로 간격을, alignOffset으로 변을 따라 미는 거리를 조절합니다.
popup 안의 form
popup은 focus를 받을 수 있는 내용을 담으므로, 필터 패널이나 작은 form, 색 선택기는 Dialog가 아니라 여기에 들어갑니다. form을 채우는 동안 뒤 페이지가 계속 읽힙니다. 내용이 너비를 정해야 할 때는 width로 상한을 둡니다.
제어 컴포넌트
open과 onOpenChange를 함께 넘기면 state의 주인은 caller가 되므로, 페이지의 다른 무엇이든 이 popup을 열고 닫을 수 있습니다. 넘기지 않으면 popover가 스스로 관리하고 defaultOpen이 초기 상태를 정합니다.
arrow
arrow는 trigger를 가리키는 쐐기를 그립니다. 기본은 꺼짐입니다. 이 표면은 흐린 backdrop 위의 반투명이고, popup의 상자 밖으로 튀어나온 쐐기는 그 backdrop을 함께 가져갈 수 없기 때문입니다. trigger가 멀어서 popup이 무엇에 속하는지 말해야 할 때 켜세요.
<Popover arrow trigger={<Button>Details</Button>}>
Anchored to the button it came from.
</Popover>접근성
- popup에
role="dialog"가 붙습니다.title이 이름이 되고description이 설명이 되며aria-labelledby와aria-describedby로 연결됩니다. 둘 다 없는 popover에는aria-label을 따로 주세요. - 열리면 focus가 popup 안으로 들어가고, 닫히면 trigger로 돌아갑니다.
- Esc로 닫히고 바깥 클릭으로도 닫힙니다.
dismissible={false}는 둘 다 취소하지만PopoverClose는 통과하므로 갇히지 않습니다. modal은 기본이false이므로 뒤 페이지는 계속 스크롤되고 쓸 수 있습니다. 다른 것을 건드리기 전에 반드시 답해야 하는 popup에는'trap-focus'를 쓰세요.- ×의 접근성 이름은
locale이 정합니다.closeLabel로 직접 쓸 수도 있습니다.