Popover

An overlay that displays additional information or options when triggered.

Anatomy

To set up the popover correctly, you’ll need to understand its anatomy and how we name its parts.

Each part includes a data-part attribute to help identify them in the DOM.

Examples

Learn how to use the Popover component in your project. Let’s take a look at the most basic example:

import { Popover } from '@ark-ui/react'

const Basic = () => (
  <Popover.Root>
    <Popover.Trigger>
      Click Me <Popover.Indicator>{'>'}</Popover.Indicator>
    </Popover.Trigger>
    <Popover.Positioner>
      <Popover.Content>
        <Popover.Title>Title</Popover.Title>
        <Popover.Description>Description</Popover.Description>
      </Popover.Content>
    </Popover.Positioner>
  </Popover.Root>
)

Using a Portal

By default, the popover is rendered in the same DOM hierarchy as the trigger. To render the popover within a portal, set the portalled prop to true.

Note: This requires that you render the component within a Portal based on the framework you use.

import { Popover, Portal } from '@ark-ui/react'

const Portalled = () => (
  <Popover.Root portalled>
    <Popover.Trigger>
      Click Me <Popover.Indicator>{'>'}</Popover.Indicator>
    </Popover.Trigger>
    <Portal>
      <Popover.Positioner>
        <Popover.Content>
          <Popover.Title>Title</Popover.Title>
          <Popover.Description>Description</Popover.Description>
        </Popover.Content>
      </Popover.Positioner>
    </Portal>
  </Popover.Root>
)

Adding an arrow

To render an arrow within the popover, render the component Popover.Arrow and Popover.ArrowTip as children of Popover.Positioner.

import { Popover } from '@ark-ui/react'

const Arrow = () => (
  <Popover.Root>
    <Popover.Trigger>Click Me</Popover.Trigger>
    <Popover.Positioner>
      <Popover.Content>
        <Popover.Arrow>
          <Popover.ArrowTip />
        </Popover.Arrow>
        <Popover.Title>Title</Popover.Title>
        <Popover.Description>Description</Popover.Description>
        <Popover.CloseTrigger>Close</Popover.CloseTrigger>
      </Popover.Content>
    </Popover.Positioner>
  </Popover.Root>
)

Listening for open and close events

When the popover is opened or closed, we invoke the onOpenChange callback.

import { Popover } from '@ark-ui/react'

const OnOpenChange = () => {
  return (
    <Popover.Root onOpenChange={(open) => alert(open ? 'opened' : 'closed')}>
      <Popover.Trigger>
        Click Me <Popover.Indicator>{'>'}</Popover.Indicator>
      </Popover.Trigger>
      <Popover.Positioner>
        <Popover.Content>
          <Popover.Title>Title</Popover.Title>
          <Popover.Description>Description</Popover.Description>
        </Popover.Content>
      </Popover.Positioner>
    </Popover.Root>
  )
}

Control the open state

Use the isOpen prop to control the open state of the popover.

import { Popover } from '@ark-ui/react'
import { useState } from 'react'

const Controlled = () => {
  const [isOpen, setIsOpen] = useState(false)
  return (
    <>
      <button onClick={() => setIsOpen(!isOpen)}>Toggle</button>
      <Popover.Root open={isOpen}>
        <Popover.Anchor>Anchor</Popover.Anchor>
        <Popover.Positioner>
          <Popover.Content>
            <Popover.Title>Title</Popover.Title>
            <Popover.Description>Description</Popover.Description>
            <Popover.CloseTrigger>Close</Popover.CloseTrigger>
          </Popover.Content>
        </Popover.Positioner>
      </Popover.Root>
    </>
  )
}

Modifying the close behavior

The popover is designed to close on blur and when the esc key is pressed.

To prevent it from closing on blur (clicking or focusing outside), pass the closeOnInteractOutside prop and set it to false.

To prevent it from closing when the esc key is pressed, pass the closeOnEsc prop and set it to false.

import { Popover } from '@ark-ui/react'

const CloseBehavior = () => (
  <Popover.Root closeOnEsc={false} closeOnInteractOutside={false}>
    <Popover.Trigger>Click Me</Popover.Trigger>
    <Popover.Positioner>
      <Popover.Content>
        <Popover.Title>Title</Popover.Title>
        <Popover.Description>Description</Popover.Description>
        <Popover.CloseTrigger>Close</Popover.CloseTrigger>
      </Popover.Content>
    </Popover.Positioner>
  </Popover.Root>
)

Changing the placement

To change the placement of the popover, set the positioning prop.

import { Popover } from '@ark-ui/react'

const Positioning = () => (
  <Popover.Root
    positioning={{ placement: 'left-start', gutter: 16, offset: { mainAxis: 12, crossAxis: 12 } }}
  >
    <Popover.Trigger>Click Me</Popover.Trigger>
    <Popover.Positioner>
      <Popover.Content>
        <Popover.Title>Title</Popover.Title>
        <Popover.Description>Description</Popover.Description>
        <Popover.CloseTrigger>Close</Popover.CloseTrigger>
      </Popover.Content>
    </Popover.Positioner>
  </Popover.Root>
)

Changing the modality

In some cases, you might want the popover to be modal. This means that it’ll:

  • trap focus within its content
  • block scrolling on the body
  • disable pointer interactions outside the popover
  • hide content behind the popover from screen readers

To make the popover modal, set the modal prop to true. When modal={true}, we set the portalled attribute to true as well.

import { Popover } from '@ark-ui/react'

const Modal = () => (
  <Popover.Root modal>
    <Popover.Trigger>Click Me</Popover.Trigger>
    <Popover.Positioner>
      <Popover.Content>
        <Popover.Title>Title</Popover.Title>
        <Popover.Description>Description</Popover.Description>
        <Popover.CloseTrigger>Close</Popover.CloseTrigger>
      </Popover.Content>
    </Popover.Positioner>
  </Popover.Root>
)

API Reference

Root

PropTypeDefault
autoFocus
boolean
closeOnEsc
boolean
closeOnInteractOutside
boolean
defaultOpen
boolean
dir
'ltr' | 'rtl'"ltr"
getRootNode
() => Node | ShadowRoot | Document
id
string
ids
Partial<{ anchor: string trigger: string content: string title: string description: string closeTrigger: string positioner: string arrow: string }>
initialFocusEl
HTMLElement | (() => MaybeElement)
lazyMount
booleanfalse
modal
booleanfalse
onEscapeKeyDown
(event: KeyboardEvent) => void
onExitComplete
() => void
onFocusOutside
(event: FocusOutsideEvent) => void
onInteractOutside
(event: InteractOutsideEvent) => void
onOpenChange
(details: OpenChangeDetails) => void
onPointerDownOutside
(event: PointerDownOutsideEvent) => void
open
boolean
portalled
booleantrue
positioning
PositioningOptions
present
boolean
unmountOnExit
booleanfalse

Arrow

PropTypeDefault
asChild
boolean

Title

PropTypeDefault
asChild
boolean

Anchor

PropTypeDefault
asChild
boolean

Content

PropTypeDefault
asChild
boolean

Trigger

PropTypeDefault
asChild
boolean

ArrowTip

PropTypeDefault
asChild
boolean

Indicator

PropTypeDefault
asChild
boolean

Positioner

PropTypeDefault
asChild
boolean

Description

PropTypeDefault
asChild
boolean

CloseTrigger

PropTypeDefault
asChild
boolean