Component
Popover
PC에서는 trigger 옆 Popover, 모바일에서는 BottomSheet로 보조 컨트롤과 정보를 표시합니다.
Playground
옵션을 조절하며 화면과 사용 코드를 함께 확인하세요.
PC 1280px
Controls
본문 여백 · PC와 모바일 모두 적용, 목록은 sm
PC 표시 방향
PC 정렬
PC trigger와의 간격
false면 자식이 모바일 본문 스크롤을 소유
Code
import { Popover, PopoverTrigger, Button, PopoverContent, PopoverClose } from '@amineslab/ui'
export default function ExamplePreview() {
return ((<Popover snappable={true} fullScreenOnMobile={false}>
<PopoverTrigger asChild>
<Button variant="outline">옵션</Button>
</PopoverTrigger>
<PopoverContent title={"작업 옵션"} padding={"md"} scrollable={true} align={"center"} side={"bottom"} sideOffset={8}>
<p className="text-body-2">작업을 계속하기 전에 선택을 확인하세요.</p>
<PopoverClose asChild>
<Button>확인</Button>
</PopoverClose>
</PopoverContent>
</Popover>))
}Props
import {
Popover,
PopoverTrigger,
PopoverContent,
PopoverAnchor,
PopoverClose,
PopoverPortal,
PopoverArrow,
} from '@amineslab/ui'Popover
HTML <div> 요소의 표준 속성을 그대로 받습니다.
| Name | Type | Default | Description |
|---|---|---|---|
PopoverTrigger / PopoverContent | ReactNode | - | PopoverTrigger asChild 안에 버튼을, PopoverContent 안에 메뉴·폼을 넣습니다. PopoverClose나 onOpenChange(false)로 닫습니다. |
PopoverContent.title / aria-label | string | '선택' | 모바일 패널 제목입니다. title, aria-label 순서로 사용합니다. |
Popover.open / defaultOpen / onOpenChange | boolean / (open: boolean) => void | - | 제어 상태. 생략하면 내부 상태를 사용합니다. |
PopoverContent.padding | 'none' | 'sm' | 'md' | 'md' | PC 표면과 모바일 본문 여백입니다. md는 PC·모바일 16px, 선택 목록용 sm은 PC 4px·모바일 8px, none은 여백이 없습니다. |
PopoverContent.scrollable | boolean | true | false면 모바일 본문 스크롤 wrapper를 생략해 자식이 스크롤을 소유합니다. 자식에 min-h-0 flex-1 overflow-y-auto를 지정하고 이중 스크롤을 피합니다. |
PopoverContent.confirmFooter | ReactNode | - | 명시적 적용이 필요한 다중 선택의 모바일 고정 footer입니다. 단일 선택에는 넣지 않습니다. PC 작업 버튼은 children에 직접 배치합니다. |
Popover.snappable | boolean | true | 내용 높이로 열고 위로 끌어 전체 높이로 확장합니다. |
Popover.fullScreenOnMobile | boolean | false | 모바일에서 처음부터 전체 높이로 엽니다. |
PopoverContent.align / side / sideOffset | PopoverContentProps | - | PC Popover 위치. 모바일 Drawer에서는 사용하지 않습니다. |
PopoverContent.className / mobileClassName | string | - | className은 PC 표면, mobileClassName은 모바일 시트 표면에 적용합니다. 본문 여백은 padding으로 조절합니다. |
sideOffset | number | 6 | trigger와 내용 사이의 간격입니다. |
Examples
자주 쓰는 조합을 살펴보고, 필요한 예시의 코드를 펼쳐 확인하세요.
모바일 bottomsheet 메뉴
PC에서는 Popover, 모바일에서는 내용 높이의 Drawer로 열립니다. Drawer 안에서는 중첩 Drawer가 됩니다. 목록은 padding="sm" 여백을 사용합니다.
import { useState } from 'react'
import { Popover, PopoverTrigger, Button, PopoverContent } from '@amineslab/ui'
function ResponsiveMenuExample() {
const [open, setOpen] = useState(false);
const [selection, setSelection] = useState('최근 수정순');
return (<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button variant="outline">{selection}</Button>
</PopoverTrigger>
<PopoverContent title="정렬 기준" padding="sm">
<div className="grid gap-1">
{['최근 수정순', '이름순', '생성일순'].map((label) => (<Button key={label} variant="ghost" className="justify-start" onClick={() => {
setSelection(label);
setOpen(false);
}}>
{label}
</Button>))}
</div>
</PopoverContent>
</Popover>);
}
export default function ExamplePreview() {
return (<ResponsiveMenuExample />)
}Small form
import { Popover, PopoverTrigger, Button, PopoverContent, Input } from '@amineslab/ui'
export default function ExamplePreview() {
return ((<Popover>
<PopoverTrigger asChild>
<Button variant="outline">이름 바꾸기</Button>
</PopoverTrigger>
<PopoverContent>
<Input aria-label="새 이름" defaultValue="Amineslab UI"/>
<Button>저장</Button>
</PopoverContent>
</Popover>))
}사용 기준
권장하는 사용
- 맥락을 유지한 채 짧게 끝나는 작업에 사용합니다.
피해야 할 사용
- 겉모양만으로 사용을 결정하지 마세요.
- 의미와 키보드 동작, 모바일에서의 흐름을 함께 확인하세요.
접근성
화면에 맞는 이름을 제공하고, 키보드만으로 작업을 마칠 수 있는지 확인하세요.
Enter 또는 Space: 열기Escape: 닫고 trigger로 포커스 복귀