Skip to content

Import#

import { Popover } from '@dnb/eufemia'

Description#

Popover renders its own floating surface anchored to a trigger element.

It is used in the Tooltip and DatePicker component, but can also be used directly when you need a more flexible trigger or richer content.

Relevant links#

Accessibility#

  • Focus moves into the popover body once it opens (similar to TermDefinition). When restoreFocus is enabled, closing returns focus to the trigger, including when a controlled open prop changes to false. If the trigger cannot receive focus, Popover falls back to the element focused when it opened. A click or tap outside closes the popover without moving focus back to the trigger.
  • Use restoreFocusTo to choose a different focus destination after closing. It accepts an element, ref, or function returning an element. Set restoreFocus={false} when your application manages focus itself.
  • The Popover does by default change its alignment initially, but not reposition itself during user scroll when opened, as this could be disorienting and confusing for users.
  • When you render a trigger via the provided render props, it receives ARIA attributes such as aria-controls, aria-expanded, and aria-describedby alongside keyboard handlers.
  • Set hideCloseButton if you want to remove the built-in close button and handle dismissal yourself (use the provided close helper when rendering custom content).
  • The popover can be dismissed with Escape, by clicking outside, or by using the close button.
  • Custom triggers receive the necessary ARIA attributes (aria-controls, aria-expanded, aria-describedby) and keyboard handlers so long as you spread the provided props.

Root Element (React Portal)#

The Popover component uses PortalRoot internally to render its content. See the PortalRoot documentation for information on how to control where the portal content appears in the DOM, and for the BrowserTranslate helper when browser translation tools such as Google Translate should not modify content rendered through PortalRoot.

Related components#

Popover is part of the Feedback category. Other components for similar needs:

  • AriaLive — to announce page changes to screen reader users.
  • Badge — to highlight new, unread, or important information.
  • Dialog — when people need to make a choice or read an important message before continuing.
  • Drawer — to show extra content in a panel that slides in from the side.
  • FormStatus — to show validation errors, warnings, or messages near a form.
  • GlobalError — to show a clear 404 or 500 error page.

See all in Feedback →

Demos#

Basic usage#

<Popover
  trigger={({ active, ...triggerProps }) => (
    <Button icon="question" {...triggerProps} selected={active} />
  )}
  title="Need help?"
>
  Popover content that appears when the custom trigger button is toggled.
</Popover>

Without close button#

<Popover
  hideCloseButton
  trigger={(triggerProps) => (
    <Button text="More info" variant="secondary" {...triggerProps} />
  )}
  title="More information"
  content={({ close }) => (
    <Flex.Stack>
      <P>
        This popover hides the default close button. You can still close it
        programmatically by calling the provided helpers.
      </P>
      <Button text="Dismiss" variant="secondary" onClick={close} />
    </Flex.Stack>
  )}
/>

Controlled state#

An external trigger can control open. Focus returns to the trigger after closing, including when the content updates the state directly.

const Example = () => {
  const [open, setOpen] = useState(false)
  const anchorRef = useRef<HTMLDivElement>(null)
  return (
    <Flex.Stack>
      <div ref={anchorRef}>
        <Button
          text="Open controlled popover"
          aria-expanded={open}
          aria-controls="controlled-popover-content"
          onClick={() => setOpen(!open)}
        />
      </div>
      <Popover
        id="controlled-popover-content"
        open={open}
        onOpenChange={setOpen}
        targetElement={anchorRef}
        title="Controlled state"
      >
        <Flex.Stack>
          <P>
            Closing also returns focus to the opener when the positioning
            target is a wrapper.
          </P>
          <Button text="Done" onClick={() => setOpen(false)} />
        </Flex.Stack>
      </Popover>
      <Button text="Another action" variant="secondary" />
    </Flex.Stack>
  )
}
render(<Example />)
Suggest an edit