# Popover URL: /react/components/popover Source: https://github.com/daangn/seed-design/blob/dev/docs/content/react/components/popover.mdx 트리거 요소에 앵커링되어 화면 위에 떠 있는 컨테이너입니다. Header/Body/Footer 구조로 부가 정보나 액션을 제공할 때 사용됩니다. 사용 가능 버전: @seed-design/react@3.0.0, @seed-design/css@3.0.0 ## Preview ```tsx import { HStack } from "@seed-design/react"; import { ActionButton } from "seed-design/ui/action-button"; import { PopoverAction, PopoverBody, PopoverContent, PopoverFooter, PopoverRoot, PopoverTrigger, } from "seed-design/ui/popover"; export default function PopoverPreview() { return ( Open Popover Popover 본문에는 사용자가 확인해야 할 내용이나 추가 액션을 배치할 수 있습니다. 확인 ); } ``` ## Installation - npm: npx @seed-design/cli@latest add ui:popover - pnpm: pnpm dlx @seed-design/cli@latest add ui:popover - yarn: yarn dlx @seed-design/cli@latest add ui:popover - bun: bun x @seed-design/cli@latest add ui:popover ## Props ### `PopoverRoot` ### `PopoverTrigger` ### `PopoverAnchor` ### `PopoverContent` ### `PopoverBody` ### `PopoverFooter` ### `PopoverAction` ## Examples ### Trigger ``는 `aria-haspopup="dialog"` 속성을 설정하고, Popover의 `open` 상태에 따라 `aria-expanded` 속성을 자동으로 설정합니다. 열려 있는 동안에는 ``를 가리키는 `aria-controls` 속성도 함께 설정합니다. 이 속성은 스크린 리더와 같은 보조 기술에 유용합니다. ```tsx import { HStack } from "@seed-design/react"; import { ActionButton } from "seed-design/ui/action-button"; import { PopoverAction, PopoverBody, PopoverContent, PopoverFooter, PopoverRoot, PopoverTrigger, } from "seed-design/ui/popover"; export default function PopoverTriggerExample() { return ( Trigger 트리거를 눌러 Popover를 열 수 있습니다. 확인 ); } ``` ### Controlled Trigger 외의 방식으로 Popover를 열고 닫을 수 있습니다. 이 경우 `open` prop을 사용하여 Popover의 상태를 제어합니다. ```tsx import { HStack, VStack } from "@seed-design/react"; import { useState } from "react"; import { ActionButton } from "seed-design/ui/action-button"; import { PopoverAction, PopoverBody, PopoverContent, PopoverFooter, PopoverRoot, PopoverTrigger, } from "seed-design/ui/popover"; import { Switch } from "seed-design/ui/switch"; export default function PopoverControlled() { const [open, setOpen] = useState(false); return ( Popover open prop으로 Popover의 열림 상태를 직접 제어합니다. 확인 ); } ``` ### Open Change `onOpenChange(open, details)`에서 열림 상태가 바뀐 이유를 확인할 수 있습니다. - `trigger`: 트리거로 열거나 닫음 - `closeButton`: `PopoverAction` 또는 닫기 버튼으로 닫음 - `escapeKeyDown`: Escape 키로 닫음 - `interactOutside`: 외부 영역을 눌러 닫음 - `focusOut`: Tab 등으로 포커스가 밖으로 이동하여 닫음 - `cascadeDismiss`: 상위 레이어가 닫혀 함께 닫음 `cascadeDismiss`는 `details.dismissedParent`를, 나머지는 `details.event`를 제공합니다. `focusOut`의 이벤트는 `FocusEvent`입니다. Popover는 열릴 때 콘텐츠로 포커스를 옮기지만 가두지 않습니다. `closeOnInteractOutside={false}`가 아니라면 Tab 등으로 포커스가 밖으로 이동할 때 닫히며, 이동한 곳의 포커스를 유지합니다. ### Placement ``에 `placement` prop을 설정하여 트리거 기준 위치를 지정합니다. 뷰포트 경계를 벗어나면 자동으로 뒤집히거나(flip) 이동합니다(shift). ```tsx import { HStack } from "@seed-design/react"; import { ActionButton } from "seed-design/ui/action-button"; import { PopoverAction, PopoverBody, PopoverContent, PopoverFooter, PopoverRoot, PopoverTrigger, } from "seed-design/ui/popover"; export default function PopoverPlacement() { return ( right-start placement prop으로 트리거 기준 위치를 지정합니다. 뷰포트를 벗어나면 자동으로 뒤집히거나 이동합니다. 확인 ); } ``` ### Anchor ``를 사용하면 트리거와 분리된 요소를 기준으로 Popover의 위치를 잡을 수 있습니다. 이 경우 열림 상태는 `open` prop으로 직접 제어합니다. ```tsx import { HStack } from "@seed-design/react"; import { useState } from "react"; import { ActionButton } from "seed-design/ui/action-button"; import { Avatar } from "seed-design/ui/avatar"; import { IdentityPlaceholder } from "seed-design/ui/identity-placeholder"; import { PopoverAction, PopoverAnchor, PopoverBody, PopoverContent, PopoverFooter, PopoverRoot, } from "seed-design/ui/popover"; export default function PopoverAnchorExample() { const [open, setOpen] = useState(false); return ( setOpen(true)}> Popover 열기 } /> 트리거와 분리된 요소를 기준으로 Popover의 위치를 잡을 수 있습니다. 확인 ); } ``` ### Scroll ``의 `max-height`(600px)를 넘는 긴 콘텐츠는 ``가 스크롤됩니다. 콘텐츠가 실제로 넘칠 때에만 하단에 scroll fog가 표시되고, 위에 Header가 있는 Body를 아래로 스크롤하면 상단에 divider가 나타납니다. 뷰포트가 작으면 `max-height`는 가용 높이에 맞춰 줄어듭니다. ```tsx import { HStack } from "@seed-design/react"; import { ActionButton } from "seed-design/ui/action-button"; import { PopoverAction, PopoverBody, PopoverContent, PopoverFooter, PopoverRoot, PopoverTrigger, } from "seed-design/ui/popover"; export default function PopoverScroll() { return ( 긴 콘텐츠 Popover {Array.from({ length: 20 }, (_, index) => (

{index + 1}. 본문이 길어지면 Body가 스크롤되고, 스크롤 시 상단 divider와 하단 scroll fog가 나타납니다.

))}
동의
); } ``` ### Show Close Button ``에 `showCloseButton` prop을 전달하여 닫기 버튼 표시 여부를 제어합니다. 기본값은 `true`이며, 표시될 때 Header 우측에 여백이 확보됩니다. ```tsx import { HStack } from "@seed-design/react"; import { ActionButton } from "seed-design/ui/action-button"; import { PopoverAction, PopoverBody, PopoverContent, PopoverFooter, PopoverRoot, PopoverTrigger, } from "seed-design/ui/popover"; export default function PopoverShowCloseButton() { return ( 닫기 버튼 있음 기본적으로 Header 우측에 닫기 버튼이 표시됩니다. 확인 닫기 버튼 없음 닫기 버튼을 숨길 때는 본문이나 푸터에 닫을 수 있는 액션을 제공하세요. 확인 ); } ``` ### Prevent Close `PopoverAction`의 `onClick`에서 `e.preventDefault()`를 호출하면 Popover가 닫히지 않습니다. ```tsx import { HStack } from "@seed-design/react"; import { useState } from "react"; import { ActionButton } from "seed-design/ui/action-button"; import { PopoverAction, PopoverBody, PopoverContent, PopoverFooter, PopoverRoot, PopoverTrigger, } from "seed-design/ui/popover"; import { Switch } from "seed-design/ui/switch"; export default function PopoverPreventClose() { const [preventClose, setPreventClose] = useState(true); return ( 열기 취소 { if (preventClose) e.preventDefault(); }} > 확인 ); } ```