Popover

Popover

팝오버(Popover)는 요소 위에 뜨는 작은 팝업창으로, 버튼이나 링크를 클릭했을 때 상세 정보를 보여줄 때 사용해요. @chakra-ui/react에서 Popover 컴포넌트를 가져와 사용할 수 있어요.

출처: 문서

본문

사용법 (Usage)

import { Popover } from "@chakra-ui/react"
<Popover.Root>
  <Popover.Trigger />
  <Popover.Positioner>
    <Popover.Content>
      <Popover.CloseTrigger />
      <Popover.Arrow>
        <Popover.ArrowTip />
      </Popover.Arrow>
      <Popover.Body>
        <Popover.Title />
      </Popover.Body>
    </Popover.Content>
  </Popover.Positioner>
</Popover.Root>

단축 속성 (Shortcuts)

Popover는 자주 쓰는 사용 사례를 위한 단축 속성을 제공해요.

Arrow

Popover.Arrow는 기본적으로 내부에 Popover.ArrowTip 컴포넌트를 자동으로 렌더링해요.

이렇게 써도 동작해요:

<Popover.Arrow>
  <Popover.ArrowTip />
</Popover.Arrow>

화살표 끝을 커스터마이즈할 필요가 없다면 이렇게 더 간결하게 쓸 수 있어요.

<Popover.Arrow />

예시 (Examples)

Controlled

open과 onOpenChange props를 사용해 팝오버의 표시 여부를 제어할 수 있어요.

여러 트리거 (Multiple Triggers)

버튼마다 팝오버를 하나씩 만들지 마세요. 하나의 Root 아래 각 Trigger에 value를 넣어주세요. 다른 트리거를 클릭하면 같은 팝오버가 그 위치로 이동해요.

Root의 triggerValue와 onTriggerValueChange로 활성 트리거를 추적할 수 있어요. 대상이 버튼이 아닌 경우에는 positioning.getAnchorRect를 사용하세요.

크기 (Sizes)

size prop을 사용해 팝오버 컴포넌트의 크기를 바꿀 수 있어요.

Lazy Mount

lazyMounted와 unmountOnExit prop을 사용해 팝오버 콘텐츠가 열릴 때까지 마운트를 지연할 수 있어요.

위치 (Placement)

positioning.placement prop을 사용해 내부의 floating-ui 위치 계산 로직을 설정할 수 있어요.

오프셋 (Offset)

positioning.offset prop을 사용해 팝오버 콘텐츠의 위치를 조정할 수 있어요.

같은 너비 (Same Width)

positioning.sameWidth prop을 사용해 팝오버 콘텐츠가 트리거와 같은 너비가 되도록 할 수 있어요.

중첩 팝오버 (Nested Popover)

팝오버 안에 팝오버, 셀렉트, 메뉴 같은 플로팅 요소를 중첩할 때는, 이들을 문서의 body로 포털링(portalling)하지 않는 것이 좋아요.

-<Portal>
  <Popover.Positioner>
    <Popover.Content>
      {/* ... */}
    </Popover.Content>
  </Popover.Positioner>
-</Portal>

초기 포커스 (Initial Focus)

initialFocusEl prop을 사용해 팝오버 콘텐츠의 초기 포커스 위치를 설정할 수 있어요.

폼 (Form)

팝오버 안에 폼이 있는 예시는 다음과 같아요.

커스텀 배경 (Custom Background)

--popover-bg CSS 변수를 사용해 팝오버 콘텐츠와 화살표의 배경색을 바꿀 수 있어요.

다이얼로그에서 열기 (Open From Dialog)

Dialog 안에서 Popover를 사용하려면, Popover.Positioner를 문서의 body로 포털링하지 않아야 해요.

-<Portal>
  <Popover.Positioner>
    <Popover.Content>
      {/* ... */}
    </Popover.Content>
  </Popover.Positioner>
-</Portal>

Dialog에 scrollBehavior="inside"를 설정했다면 다음을 처리해야 해요:

  • 팝오버가 다이얼로그에 잘리지 않도록 팝오버 위치를 fixed로 설정해요.
  • 트리거가 화면 밖으로 스크롤되면 팝오버를 숨기도록 hideWhenDetached를 true로 설정해요.
<Popover.Root positioning={{ strategy: "fixed", hideWhenDetached: true }}>
  {/* ... */}
</Popover.Root>

가이드 (Guide)

팝오버 컨텍스트 접근 (Accessing popover context)

usePopoverContext를 사용하면 팝오버 안의 어떤 컴포넌트에서든 팝오버의 상태와 메서드에 접근할 수 있어요.

import { usePopoverContext } from "@chakra-ui/react"

const PopoverStatus = () => {
  const popover = usePopoverContext()

  return <div>Popover is {popover.open ? "open" : "closed"}</div>
}

const MyPopover = () => (
  <Popover.Root>
    <Popover.Trigger>Open</Popover.Trigger>
    <Popover.Positioner>
      <Popover.Content>
        <PopoverStatus />
      </Popover.Content>
    </Popover.Positioner>
  </Popover.Root>
)

프로그래밍 방식으로 닫기 (Closing programmatically)

컨텍스트의 setOpen(false)를 사용해 팝오버를 프로그래밍 방식으로 닫을 수 있어요.

import { usePopoverContext } from "@chakra-ui/react"

const CloseButton = () => {
  const popover = usePopoverContext()

  return <Button onClick={() => popover.setOpen(false)}>Close Popover</Button>
}

const MyPopover = () => (
  <Popover.Root>
    <Popover.Trigger>Open</Popover.Trigger>
    <Popover.Positioner>
      <Popover.Content>
        <CloseButton />
      </Popover.Content>
    </Popover.Positioner>
  </Popover.Root>
)

ref 기반 위치 지정 (Positioning based on ref)

positioning.getAnchorRect()를 사용해 커스텀 요소의 ref를 기준으로 팝오버를 위치시킬 수 있어요.

import { useRef } from "react"

const MyPopover = () => {
  const anchorRef = useRef<HTMLDivElement>(null)

  return (
    <>
      <div ref={anchorRef}>Anchor Element</div>

      <Popover.Root
        positioning={{
          getAnchorRect() {
            return anchorRef.current?.getBoundingClientRect()
          },
        }}
      >
        <Popover.Trigger>Open</Popover.Trigger>
        <Popover.Positioner>
          <Popover.Content>
            <Popover.Body>
              This popover is anchored to the div above
            </Popover.Body>
          </Popover.Content>
        </Popover.Positioner>
      </Popover.Root>
    </>
  )
}

Props

Popover의 여러 파트(Root, Trigger 등)별로 사용 가능한 props는 공식 문서에서 확인할 수 있어요.

더 알아보기 (Learn more)