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.
<dt-popover><template#anchor="{ attrs }"><dt-buttonv-bind="attrs">
View Popover
</dt-button></template><template#content="{ close }"><div><pclass="d-mb4">
This is content rendered within the popover.
</p><dt-button@click="close">
Button
</dt-button></div></template></dt-popover>
<divclass="d-popover"><divid="DtPopover__anchor1"><buttontype="button"class="base-button__button d-btn d-btn--primary"aria-expanded="false"><spanclass="d-btn__label base-button__label"> View Popover </span></button></div></div><divclass="tippy-box d-ps-absolute"id="tippy-1"style="z-index: 650;position: absolute;inset: 0px 0px auto auto;margin: 0px;transform:translate3d(-593px, 197px, 0px);"data-popper-placement="bottom-end"><divid="dt0"role="dialog"aria-hidden="false"aria-labelledby="DtPopover__anchor1"aria-modal="false"tabindex="-1"class="d-popover__dialog d-popover__dialog--modal"style=""><divclass="d-popover__content d-p16"><div><pclass="d-mb4">This is content rendered within the popover.</p><buttontype="button"class="base-button__button d-btn d-btn--primary"><spanclass="d-btn__label base-button__label"> Button </span></button></div></div></div></div>
<dt-popover:modal="false"><template#anchor="{ attrs }"><dt-buttonv-bind="attrs">
View Popover
</dt-button></template><template#content="{ close }"><div><pclass="d-mb4">
This is content rendered within the popover.
</p><dt-button@click="close">
Button
</dt-button></div></template></dt-popover>
<divclass="d-popover"><divid="DtPopover__anchor1"><buttontype="button"class="base-button__button d-btn d-btn--primary"aria-expanded="false"><spanclass="d-btn__label base-button__label"> View Popover </span></button></div></div><divclass="tippy-box d-ps-absolute"data-tippy-root=""id="tippy-1"data-popper-placement="bottom-end"style="z-index: 300;position: absolute;inset: 0px 0px auto auto;margin: 0px;transform:translate3d(-593px, 197px, 0px);"><divid="dt0"role="dialog"aria-hidden="false"aria-labelledby="DtPopover__anchor1"aria-modal="true"tabindex="-1"class="d-popover__dialog"style=""><divclass="d-popover__content d-p16"><div><pclass="d-mb4">This is content rendered within the popover.</p><buttontype="button"class="base-button__button d-btn d-btn--primary"><spanclass="d-btn__label base-button__label"> Button </span></button></div></div></div></div>
<dt-popover><template#anchor="{ attrs }"><dt-buttonv-bind="attrs">
View Popover
</dt-button></template><template#headerContent><divclass="d-w100p">
This is the header
</div></template><template#content="{ close }"><div><divclass="d-mb8">
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>
<divclass="d-popover"><divid="DtPopover__anchor1"><buttontype="button"class="base-button__button d-btn d-btn--primary"aria-expanded="false"><spanclass="d-btn__label base-button__label"> View Popover </span></button></div></div><divclass="tippy-box d-ps-absolute"data-tippy-root=""id="tippy-1"data-popper-placement="bottom-end"style="z-index: 650;position: absolute;inset: 0px 0px auto auto;margin: 0px;transform:translate3d(5px, 197px, 0px);"><divid="dt0"role="dialog"aria-hidden="false"aria-labelledby="DtPopover__anchor1"aria-modal="false"tabindex="-1"class="d-popover__dialog d-popover__dialog--modal"style="max-height:calc(100vh - var(--dt-space-300));"><divclass="d-popover__header d-pl16"><divclass="d-popover__header__content"><divclass="d-w100p">This is the header</div></div></div><divclass="d-popover__content d-p16"><div><divclass="d-mb8">
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><buttontype="button"class="base-button__button d-btn d-btn--primary"><spanclass="d-btn__label base-button__label"> Button </span></button></div></div></div></div>
<dt-popover><template#anchor="{ attrs }"><dt-buttonv-bind="attrs">
View Popover
</dt-button></template><template#content="{ close }"><div><divclass="d-mb8">
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><divclass="d-w100p">
This is the footer
</div></template></dt-popover>
<divclass="d-popover"><divid="DtPopover__anchor1"><buttontype="button"class="base-button__button d-btn d-btn--primary"aria-expanded="false"><spanclass="d-btn__label base-button__label"> View Popover </span></button></div></div><divclass="tippy-box d-ps-absolute"data-tippy-root=""id="tippy-5"style="z-index: 650;position: absolute;inset: 0px 0px auto auto;margin: 0px;transform:translate3d(5px, 197px, 0px);"data-popper-placement="bottom-end"><divid="dt0"role="dialog"aria-hidden="false"aria-labelledby="DtPopover__anchor1"aria-modal="false"tabindex="-1"class="d-popover__dialog d-popover__dialog--modal"style="max-height:calc(100vh - var(--dt-space-300));"><divclass="d-popover__content d-p16"><div><divclass="d-mb8">
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><buttontype="button"class="base-button__button d-btn d-btn--primary"><spanclass="d-btn__label base-button__label"> Button </span></button></div></div><divclass="d-popover__footer d-pl16"><divclass="d-popover__footer__content"><divclass="d-w100p">This is the footer</div></div></div></div></div>
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:fallback-placements="[`top`]"><template#anchor="{ attrs }"><dt-buttonv-bind="attrs">
fallback placement: top
</dt-button></template><template#content="{ close }"><div><pclass="d-mb4">
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-popoverpadding="small"><template#anchor="{ attrs }"><dt-buttonv-bind="attrs">
View Popover
</dt-button></template><template#content="{ close }"><div><pclass="d-mb4">
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 =newEvent('dt-popover-close');window.dispatchEvent(e);
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
Description
Default
appendTo
Sets the element to which the popover is going to append to.
'body' will append to the nearest body (supports shadow DOM).
'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'.
Type:HTML_ELEMENT_TYPE|string
Values:'body''parent''root'HTMLElement
'body'
ariaLabel
Descriptive label for the popover content. You should provide this
or ariaLabelledby, but not both.
Type:string
null
ariaLabelledby
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.
Type:string
null
contentAppear
Whether to apply transition on initial render in the content lazy show component.
Type:boolean
null
contentClass
Additional class name for the content wrapper element.
Type:string|array|object
''
contentTabindex
Tabindex value for the content. Passing null, no tabindex attribute will be set.
Type:Number || null
-1
contentWidth
Width configuration for the popover content. When its value is 'anchor',
the popover content will have the same width as the anchor.
Type:string
Values:nullanchor
''
dialogClass
Additional class name for the dialog element.
Type:string|array|object
''
elementType
Element type (tag name) of the root element of the component.
Type:string
'div'
externalAnchor
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.
Type:string
''
externalAnchorElement
External anchor element reference. Use this instead of externalAnchor when
the anchor may be inside a Shadow DOM, as querySelector cannot pierce shadow boundaries.
Type:HTML_ELEMENT_TYPE
null
fallbackPlacements
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
Type:array
['auto']
footerClass
Additional class name for the footer content wrapper element.
Type:string|array|object
''
headerClass
Additional class name for the header content wrapper element.
Type:string|array|object
''
hideOnClick
Determines if the popover hides upon clicking the
anchor or outside the content box.
Type:boolean
Values:truefalse
true
id
The id of the tooltip
Type:string
function() { return getUniqueString(); }
initialFocusElement
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'.
Type:string|HTML_ELEMENT_TYPE
Values:nonedialogfirst
'first'
maxHeight
Determines maximum height for the popover before overflow.
Possible units rem|px|em
Type:string
''
maxWidth
Determines maximum width for the popover before overflow.
Possible units rem|px|%|em
Type:string
''
modal
Determines modal state. If enabled popover has a modal overlay
preventing interaction with elements below it, but it is invisible.
Type:boolean
Values:truefalse
true
offset
Displaces the content box from its anchor element
by the specified number of pixels.
Tippy.js docs
Type:array
[0, 4]
open
Controls whether the popover is shown. Leaving this null will have the popover trigger on click by default.
If you set this value, the default trigger behavior will be disabled, and you can control it as you need.
Supports v-model
Type:boolean
Values:nulltruefalse
null
openOnContext
Opens the popover on right click (context menu). If you set this value to true,
the default trigger behavior will be disabled.
Type:boolean
Values:truefalse
false
openWithArrowKeys
If the popover should open pressing up or down arrow key on the anchor element.
This can be set when not passing open prop.
Type:boolean
Values:truefalse
false
padding
Padding size class for the popover content.
Type:string
Values:nonesmallmediumlarge
'large'
placement
The direction the popover displays relative to the anchor.
Tippy.js docs
ARIA role for the content of the popover. Defaults to "dialog".
aria-haspopup
Type:string
'dialog'
showCloseButton
Determines visibility for close button
Type:boolean
Values:truefalse
false
sticky
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
Type:boolean|string
Values:truefalsereferencepopper
false
tether
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
Type:boolean
Values:truefalse
true
transition
Named transition when the content display is toggled.
Type:string
'fade'
Events
Name
Description
keydown
Native keydown event
Type:KeyboardEvent
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
Emitted when popover is shown or hidden
Type:Boolean | Array
update:open
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.
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.
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:
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.