Components
Popover

Popover

An overlay that displays additional information or options when triggered.

You can explore the popover component in the following curated examples.

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/solid/popover'

export 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 } from '@ark-ui/solid/popover'
import { Portal } from 'solid-js/web'

export 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/solid/popover'

export 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/solid/popover'

export 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/solid/popover'
import { createSignal } from 'solid-js'

export const Controlled = () => {
  const [isOpen, setIsOpen] = createSignal(false)
  return (
    <>
      <button type="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/solid/popover'
import { Portal } from 'solid-js/web'

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

Changing the placement

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

import { Popover } from '@ark-ui/solid/popover'

export const Positioning = () => (
  <Popover.Root
    positioning={{
      placement: 'left-start',
      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/solid/popover'

export 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>
)

Using the Root Provider

The RootProvider component provides a context for the popover. It accepts the value of the usePopover hook. You can leverage it to access the component state and methods from outside the popover.

import { Popover, usePopover } from '@ark-ui/solid/popover'

export const RootProvider = () => {
  const popover = usePopover()

  return (
    <>
      <button onClick={() => popover().setOpen(true)}>
        Popover is {popover().open ? 'open' : 'closed'}
      </button>

      <Popover.RootProvider value={popover}>
        <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.RootProvider>
    </>
  )
}

If you're using the RootProvider component, you don't need to use the Root component.

API Reference

Root

PropDefaultType
autoFocustrue
boolean

Whether to automatically set focus on the first focusable content within the popover when opened.

closeOnEscapetrue
boolean

Whether to close the popover when the escape key is pressed.

closeOnInteractOutsidetrue
boolean

Whether to close the popover when the user clicks outside of the popover.

defaultOpen
boolean

The initial open state of the popover when it is first rendered. Use when you do not need to control its open state.

id
string

The unique identifier of the machine.

ids
Partial<{ anchor: string trigger: string content: string title: string description: string closeTrigger: string positioner: string arrow: string }>

The ids of the elements in the popover. Useful for composition.

immediate
boolean

Whether to synchronize the present change immediately or defer it to the next frame

initialFocusEl
() => HTMLElement | null

The element to focus on when the popover is opened.

lazyMountfalse
boolean

Whether to enable lazy mounting

modalfalse
boolean

Whether the popover should be modal. When set to `true`: - interaction with outside elements will be disabled - only popover content will be visible to screen readers - scrolling is blocked - focus is trapped within the popover

onEscapeKeyDown
(event: KeyboardEvent) => void

Function called when the escape key is pressed

onExitComplete
() => void

Function called when the animation ends in the closed state

onFocusOutside
(event: FocusOutsideEvent) => void

Function called when the focus is moved outside the component

onInteractOutside
(event: InteractOutsideEvent) => void

Function called when an interaction happens outside the component

onOpenChange
(details: OpenChangeDetails) => void

Function invoked when the popover opens or closes

onPointerDownOutside
(event: PointerDownOutsideEvent) => void

Function called when the pointer is pressed down outside the component

open
boolean

Whether the popover is open

persistentElements
(() => Element | null)[]

Returns the persistent elements that: - should not have pointer-events disabled - should not trigger the dismiss event

portalledtrue
boolean

Whether the popover is portalled. This will proxy the tabbing behavior regardless of the DOM position of the popover content.

positioning
PositioningOptions

The user provided options used to position the popover content

present
boolean

Whether the node is present (controlled by the user)

unmountOnExitfalse
boolean

Whether to unmount on exit.

Anchor

PropDefaultType
asChild
(props: ParentProps<'div'>) => Element

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.

Arrow

PropDefaultType
asChild
(props: ParentProps<'div'>) => Element

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.

ArrowTip

PropDefaultType
asChild
(props: ParentProps<'div'>) => Element

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.

CloseTrigger

PropDefaultType
asChild
(props: ParentProps<'button'>) => Element

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.

Content

PropDefaultType
asChild
(props: ParentProps<'div'>) => Element

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
Data AttributeValue
[data-scope]popover
[data-part]content
[data-state]"open" | "closed"
[data-expanded]Present when expanded
[data-placement]The placement of the content

Description

PropDefaultType
asChild
(props: ParentProps<'div'>) => Element

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.

Indicator

PropDefaultType
asChild
(props: ParentProps<'div'>) => Element

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
Data AttributeValue
[data-scope]popover
[data-part]indicator
[data-state]"open" | "closed"

Positioner

PropDefaultType
asChild
(props: ParentProps<'div'>) => Element

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.

RootProvider

PropDefaultType
value
UsePopoverReturn

immediate
boolean

Whether to synchronize the present change immediately or defer it to the next frame

lazyMountfalse
boolean

Whether to enable lazy mounting

onExitComplete
() => void

Function called when the animation ends in the closed state

present
boolean

Whether the node is present (controlled by the user)

unmountOnExitfalse
boolean

Whether to unmount on exit.

Title

PropDefaultType
asChild
(props: ParentProps<'div'>) => Element

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.

Trigger

PropDefaultType
asChild
(props: ParentProps<'button'>) => Element

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
Data AttributeValue
[data-scope]popover
[data-part]trigger
[data-placement]The placement of the trigger
[data-state]"open" | "closed"

Accessibility

Keyboard Support

KeyDescription
Space
Opens/closes the popover.
Enter
Opens/closes the popover.
Tab
Moves focus to the next focusable element within the content.
Note: If there are no focusable elements, focus is moved to the next focusable element after the trigger.
Shift + Tab
Moves focus to the previous focusable element within the content
Note: If there are no focusable elements, focus is moved to the trigger.
Esc
Closes the popover and moves focus to the trigger.