A Popover displays a content overlay when its anchor element is activated.

Preview

Usage

A Popover contains a dialog that will appear above other content when activated. It will always appear in a location relative to the anchor. If you are looking for a dialog that does not display relative to the anchor, see Modal. Some common examples of popover usage: dropdown list, emoji picker dialog, add comment dialog. A popover can be modal or non-modal. Below are some guidelines on when to use a modal vs non-modal popover.

Migration note: DtOldPopover is deprecated. Replace all uses with DtPopover (this component). DtOldPopover will be removed in a future major version. See the whats-new posts for migration details.

Your popover should be modal when:

  • It contains scrollable content.
  • It contains components that hold user input state (input, checkbox).

Your popover should be non-modal when:

  • It is not scrollable.
  • It contains only components that do not hold state (link, button).

The content slot will be rendered lazily when the popover is open. By default, the popover content will be opened when the anchor is clicked, and closed when clicking outside the content or on ESC key press. You may override this behaviour by using .sync on the open prop (or v-model:open in Vue 3) in which you can open or close the content using whichever condition you wish.

Do

  • Smaller sized dialogs that trigger on user activation of an anchor element.
  • Dialogs that should be positioned relative to the anchor.
  • Dialogs that contain interactive components.

Don’t

  • Content that is displayed on hover. Instead, use a Tooltip.
  • Dialogs that should be positioned in the center of the screen.
  • Dialogs that are very large.
  • Alerts.

Best Practices

  • Popovers should be fairly small. If you are looking for more of a full size dialog solution see Modal
  • Trigger using an anchor element, such as a button.
  • Render the dialog at the body element.
  • Focus the first interactive element within the dialog after it is opened.
  • Close the dialog when ESC is pressed.
  • Close non-modal dialogs if they are scrolled out of visibility.
  • Set the z-index of the dialog to var(--zi-modal-element) if modal, var(--zi-popover) if not.

Variants and Examples

Popover - Modal

Popover - Non Modal

With Header - Modal

Fallback Placements

The popover uses headless-tippy and popper, if the popover opens in a placement where it will be clipped, it will move to a new position. It will do this automatically by default, but if you want to manually specify which position it will move to in what order you can do so via the fallbackPlacements prop.

Padding

Padding options for the popover content are provided via size classes "small", "medium" or "large" in order to standardize the look of the popover content between usages. To remove the padding from the content, you can pass "none". Setting none will also allow you to set custom padding via utility classes (Ex: you only want padding on the left.).

Force Close All Opened Instances

When the popover is open, it will attach an event listener into the window object, so you can close the instances dispatching the dt-popover-close event in the window object:

const e = new Event('dt-popover-close');
window.dispatchEvent(e);

Content Mode

Popover content renders outside the DOM tree. Use the contentMode prop to apply color mode (invert, light, dark) to the positioned content. See Positioned Components for details.

Vue API

import { DtPopover } from '@dialpad/dialtone-vue';

Slots

Name
Type
anchor

Anchor element that activates the popover. Usually a button.

content

Slot for the content that is displayed in the popover when it is open.

footerContent

Slot for the footer content.

headerContent

Slot for popover header content

Props

Name
Default
Type
anchorClass
''
string|array|object

Additional class name for the anchor wrapper element.

appendTo
'body'
"'body'" | "'parent'" | "'root'" | "HTMLElement"

Sets the element to which the popover is going to append to. 'body' will append to the nearest ancestor

element when inside one (keeping the popover in the browser's top layer), or to the nearest body otherwise. To always append to body regardless of dialog context, pass document.body as an HTMLElement. 'root' will try append to the iFrame's parent body if it is contained in an iFrame and has permissions to access it, else, it'd default to 'parent'.

ariaLabel
null
string

Descriptive label for the popover content. You should provide this or ariaLabelledby, but not both.

ariaLabelledby
null
string

ID of the element that serves as the label for the popover content. Defaults to the "anchor" element; this exists to provide a different ID of the label element if, for example, the anchor slot contains other items that do not serve as a label. You should provide this or ariaLabel, but not both.

closeOnClick
true
"true" | "false"

Closes the popover when clicking the anchor or outside the content box.

contentAppear
null
boolean

Whether to apply transition on initial render in the content lazy show component.

contentClass
''
string|array|object

Additional class name for the content wrapper element.

contentMode
"light" | "dark" | "invert"

Applies a color mode to the positioned content element. light and dark are explicit overrides. invert computes the opposite of the nearest ancestor's mode and stays reactive.

contentTabindex
-1
Number || null

Tabindex value for the content. Passing null, no tabindex attribute will be set.

contentWidth
''
"null" | "anchor"

Width configuration for the popover content. When its value is 'anchor', the popover content will have the same width as the anchor.

dialogClass
''
string|array|object

Additional class name for the dialog element.

elementType
'div'
string

Element type (tag name) of the root element of the component.

externalAnchorElement
null
HTML_ELEMENT_TYPE

External anchor element reference. Use this instead of externalAnchor when the anchor may be inside a Shadow DOM, as querySelector cannot pierce shadow boundaries.

fallbackPlacements
['auto']
array

If the popover does not fit in the direction described by "placement", it will attempt to change its direction to the "fallbackPlacements". Popper.js docs

footerClass
''
string|array|object

Additional class name for the footer content wrapper element.

footerWrapperClass
''
string|array|object

Additional class name for the footer element (d-popover__footer).

headerClass
''
string|array|object

Additional class name for the header content wrapper element.

headerWrapperClass
''
string|array|object

Additional class name for the header element (d-popover__header).

id
generated unique ID
string

The id of the tooltip

initialFocusElement
'first'
"none" | "dialog" | "first"

The element that is focused when the popover is opened. This can be an HTMLElement within the popover, a string starting with '#' which will find the element by ID. 'first' which will automatically focus the first element, or 'dialog' which will focus the dialog window itself. If the dialog is modal this prop cannot be 'none'.

maxHeight
''
string

Determines maximum height for the popover before overflow. Possible units rem|px|em

maxWidth
''
string

Determines maximum width for the popover before overflow. Possible units rem|px|%|em

modal
true
"true" | "false"

Determines modal state. If enabled popover has a modal overlay preventing interaction with elements below it, but it is invisible.

offset
[0, 4]
array

Displaces the content box from its anchor element by the specified number of pixels. Tippy.js docs

open
null
"null" | "true" | "false"

Controls whether the popover is shown. When null (default), the popover toggles on click. When set to true or false, the default trigger is disabled and the parent controls visibility via v-model:open.

openOnContext
false
"true" | "false"

Opens the popover on right click (context menu). If you set this value to true, the default trigger behavior will be disabled.

openWithArrowKeys
false
"true" | "false"

If the popover should open pressing up or down arrow key on the anchor element. This can be set when not passing open prop.

padding
'large'
"none" | "small" | "medium" | "large"

Padding size class for the popover content.

placement
'bottom-end'
"top" | "top-start" | "top-end" | "right" | "right-start" | "right-end" | "left" | "left-start" | "left-end" | "bottom" | "bottom-start" | "bottom-end" | "auto" | "auto-start" | "auto-end"

The direction the popover displays relative to the anchor. Tippy.js docs

role
'dialog'
string

ARIA role for the content of the popover. Defaults to "dialog". aria-haspopup

showCloseButton
false
"true" | "false"

Determines visibility for close button

sticky
false
"true" | "false" | "reference" | "popper"

If the popover sticks to the anchor. This is usually not needed, but can be needed if the reference element's position is animating, or to automatically update the popover position in those cases the DOM layout changes the reference element's position. true enables it, reference only checks the "reference" rect for changes and popper only checks the "popper" rect for changes. Tippy.js docs

tether
true
"true" | "false"

If set to false the dialog will display over top of the anchor when there is insufficient space. If set to true it will never move from its position relative to the anchor and will clip instead. Popper.js docs

transition
'fade'
string

Named transition when the content display is toggled.

externalAnchor Deprecated
''
string

External anchor id to use in those cases the anchor can't be provided via the slot. For instance, using the combobox's input as the anchor for the popover.

Use externalAnchorElement instead for Shadow DOM compatibility.

Events

Name
Type
keydown
KeyboardEvent

Native keydown event

mouseenter-popover

Emitted when the mouse enters the popover

mouseenter-popover-anchor

Emitted when the mouse enters the popover anchor

mouseleave-popover

Emitted when the mouse leaves the popover

mouseleave-popover-anchor

Emitted when the mouse leaves the popover anchor

opened
Boolean | Array

Emitted when popover is shown or hidden

update:open
undefined

Event fired to sync the open prop with the parent component

Classes

Popover must contain an anchor and content element. d-modal--transparent can be used as a sibling before the popover container if you wish to make the popover modal.

Class
Applies to
Description

Accessibility

If your popover is modal, please see the accessibility section of this page regarding "focus trapping": Modal Accessibility. The same rules will apply here if your popover is modal.

Popovers, in their current implementation, are accessible when used as interactive components. Content will be read to screen reader users, and the popover markup by is appended to the <body>.

There are a few important considerations to ensure popover controls are accessible:

  • The popover content will have a generic role of "dialog" ( "menu" and "listbox" are also possible roles as well).
  • On open, focus will be transferred to the first focusable element within the popover, after close the triggering element will be focused.
  • A screen reader visible only close button is added by default when setting the showCloseButton prop to false.
Item
Applies to
Description

Anchor

The anchor element that activates the popover should be fully accessible by keyboard. The easiest way to do this is by using an element like an DtButton that is already accessible. The user should also be able to close the popover content using the ESC key for most ARIA roles.

There are some required ARIA attributes for the anchor element (such as aria-expanded set based on open and aria-haspopup that matches the role). To make this as straightforward as possible, these ARIA attributes are passed with the correct values as the attrs slot-scope to the anchor slot. Applying them is as simple as using v-bind:

<template #anchor="{ attrs }">
  <dt-button v-bind="attrs">I'm accessible now!</dt-button>
</template>

By default, the dialog content will be labeled by the entire anchor element. To change this, you can do one of 2 things:

  • Pass aria-label, which is the text label that will be applied to the dialog content.
  • Pass aria-labelledby, which is an ID of the element that should be used as the descriptive label.

Keyboard Support

The below keyboard functionality is automatically implemented when using the popover component:

  • The user can dismiss the popover pressing the ESC key, after that the focus will be returned to the element that launched it.
  • The user can traverse focusable elements using the TAB key. If the popover has a defined header, the focus will be moved to the header buttons after the last focusable element inside content's container.

Additionally you must use the "initialFocusElement" prop to set which element is initially focused when the popover opens. You can set this to "first" to focus the first focusable element, "dialog" to focus the dialog itself, a string starting with '#' to focus an element by id within the dialog or you may pass in an HTMLElement directly. If set to "none" the focus will remain on the anchor, however this is invalid behavior if the popover is modal.

References

Popover documentation last updated Thursday, June 18, 2026