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:
Your popover should be non-modal when:
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.
<dt-popover :open="onOpen" > <template #anchor> <dt-button> View Popover </dt-button> </template> <template #content="{ close }" > <div> <p class="d-mbe-50"> This is content rendered within the popover. </p> <dt-button @click="close" > Button </dt-button> </div> </template> </dt-popover>
<dt-popover :open="onOpen" :modal="false" > <template #anchor> <dt-button> View Popover </dt-button> </template> <template #content="{ close }" > <div> <p class="d-mbe-50"> This is content rendered within the popover. </p> <dt-button @click="close" > Button </dt-button> </div> </template> </dt-popover>
<dt-popover :open="onOpen" > <template #anchor> <dt-button> View Popover </dt-button> </template> <template #headerContent> <div class="d-w100p"> This is the header </div> </template> <template #content="{ close }" > <div> <div class="d-mbe-100"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequuntur delectus distinctio id iure labore, maiores mollitia reprehenderit sunt tempore veritatis. Aliquam delectus earum ex, expedita ipsam nobis obcaecati quibusdam repudiandae. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequuntur delectus distinctio id iure labore, maiores mollitia reprehenderit sunt tempore veritatis. Aliquam delectus earum ex, expedita ipsam nobis obcaecati quibusdam repudiandae.<br> </div> <dt-button @click="close" > Button </dt-button> </div> </template> </dt-popover>
<dt-popover :open="onOpen" > <template #anchor> <dt-button> View Popover </dt-button> </template> <template #content="{ close }" > <div> <div class="d-mbe-100"> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequuntur delectus distinctio id iure labore, maiores mollitia reprehenderit sunt tempore veritatis. Aliquam delectus earum ex, expedita ipsam nobis obcaecati quibusdam repudiandae. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequuntur delectus distinctio id iure labore, maiores mollitia reprehenderit sunt tempore veritatis. Aliquam delectus earum ex, expedita ipsam nobis obcaecati quibusdam repudiandae.<br> </div> <dt-button @click="close" > Button </dt-button> </div> </template> <template #footerContent> <div class="d-w100p"> This is the footer </div> </template> </dt-popover>
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.
<dt-popover :open="onOpen" :fallback-placements="[`top`]" > <template #anchor> <dt-button> fallback placement: top </dt-button> </template> <template #content="{ close }" > <div> <p class="d-mbe-50"> This is content rendered within the popover. </p> <dt-button @click="close" > Button </dt-button> </div> </template> </dt-popover>
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.).
<dt-popover :open="onOpen" padding="small" > <template #anchor> <dt-button> View Popover </dt-button> </template> <template #content="{ close }" > <div> <p class="d-mbe-50"> This is content rendered within the popover. </p> <dt-button @click="close" > Button </dt-button> </div> </template> </dt-popover>
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);
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.
<dt-popover content-mode="invert">...</dt-popover> <dt-popover content-mode="dark">...</dt-popover> <dt-popover content-mode="light">...</dt-popover>
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:
showCloseButton prop to false.
Item
|
Applies to
|
Description
|
|---|
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:
aria-label, which is the text label that will be applied to the dialog content.aria-labelledby, which is an ID of the element that should be used as the descriptive label.The below keyboard functionality is automatically implemented when using the popover component:
ESC key, after that the focus will be returned to the element that launched it.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.
import { DtPopover } from '@dialpad/dialtone-vue';
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 |
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 |
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. |
boundary | 'clippingParents' |
"clippingParents"
|
"viewport"
|
"document"
|
"HTMLElement"
The element used to determine overflow boundaries for the popover.
Popper.js docs
|
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.
| |
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
|
focustrap | false |
"true"
|
"false"
When true, traps Tab/Shift+Tab focus within the popover dialog.
Use this to enable focus trapping independently of modal state —
e.g. a non-modal popover whose content still requires keyboard containment.
When |
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 |
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"
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.
|
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. |
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 |
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
|
|---|
Popover documentation last updated Friday, September 4, 2026
fix/popover-modal-zindex-scope