Popover
A popover floats content above the page, positioned relative to the trigger element that anchors it.
Usage
forge-popover floats its content above the page, anchored to a trigger element by anchor (the trigger’s id), through placement, triggerType, preset, and arrow. Use it for content that needs more than a couple of words — a form, a set of options, or a preview — triggered by clicking, hovering, or focusing another element. For a one- or two-word label, use a tooltip instead; forge-popover is also the foundation other components build on, like menu, select, and date picker.
Rules
Basic usage
Set anchor to the id of the trigger element; the popover positions itself relative to it automatically.
A popover anchored to a button, structured with a scaffold.
<forge-button id="popover-trigger" variant="raised">
Show Popover
</forge-button>
<forge-popover anchor="popover-trigger" placement="bottom" position-strategy="fixed" hide="anchor-hidden">
<forge-scaffold>
<forge-toolbar no-border slot="header">
<h2 class="forge-typography--heading4" slot="start">
Popover Title
</h2>
</forge-toolbar>
<div slot="body" style="width: 300px; padding: var(--forge-spacing-medium);">
Popover content
</div>
<forge-toolbar no-border slot="footer">
<forge-button slot="end" variant="filled">
Close
</forge-button>
</forge-toolbar>
</forge-scaffold>
</forge-popover>Popover vs. dialog
Popovers are transient and non-modal — anchored to a trigger, they don’t block interaction with the rest of the page. Dialogs are typically modal and reserved for content that demands the user’s immediate attention, like a confirmation or a form that must be completed before moving on. The line can blur in practice; when it’s genuinely ambiguous which one fits, weigh the UX and accessibility implications of blocking (or not blocking) the rest of the page rather than defaulting to one or the other.
Non-modal
forge-popover has no semantic meaning by default — it’s up to you to add ARIA attributes appropriate to its content. Set role="dialog" and aria-modal="false" for a popover that doesn’t trap focus or block interaction with the rest of the page — useful for a lightweight, persistent form.
A non-modal popover that doesn't block interaction with the rest of the page.
<forge-button id="popover-trigger-nonmodal" variant="raised">
Show Non-modal Popover
</forge-button>
<forge-popover anchor="popover-trigger-nonmodal" placement="bottom-start" arrow aria-labelledby="nonmodal-title">
<forge-scaffold>
<forge-toolbar no-border slot="header">
<h2 class="forge-typography--heading4" slot="start" id="nonmodal-title">
Enter Your Name
</h2>
</forge-toolbar>
<div slot="body" id="nonmodal-description" style="width: 300px; padding: var(--forge-spacing-medium);">
<form autocomplete="off">
<forge-text-field>
<input autofocus type="text" name="your-name" value required aria-label="Enter your name">
</forge-text-field>
</form>
</div>
<forge-toolbar no-border slot="footer">
<forge-button slot="end" style="margin-right: var(--forge-spacing-medium);">
Cancel
</forge-button>
<forge-button slot="end" variant="filled" disabled>
Save
</forge-button>
</forge-toolbar>
</forge-scaffold>
</forge-popover>
<script type="module">
import { ToastComponent } from "@tylertech/forge/toast";
const popover = document.querySelector("forge-popover");
const input = popover?.querySelector('input[name="your-name"]');
const [cancelButton, saveButton] = popover ? Array.from(popover.querySelectorAll('forge-toolbar[slot="footer"] forge-button')) : [];
function handleInput() {
if (saveButton) {
saveButton.disabled = !input?.value;
}
}
function close() {
if (input) {
input.value = "";
}
if (saveButton) {
saveButton.disabled = true;
}
if (popover) {
popover.open = false;
}
}
function save() {
if (input?.value) {
ToastComponent.present({ message: `Hello, ${input.value}!` });
}
close();
}
input?.addEventListener("input", handleInput);
cancelButton?.addEventListener("click", close);
saveButton?.addEventListener("click", save);
popover?.addEventListener("forge-popover-beforetoggle", (event) => {
const { detail } = event;
if (detail.newState === "closed" && input?.value) {
event.preventDefault();
ToastComponent.present({ message: "You have unsaved changes." });
}
});
</script>Distinct
Give related popovers the same distinct value to guarantee only one of them is ever open at a time.
Two popovers sharing a distinct value, so opening one closes the other.
<forge-drawer open direction="left">
<forge-list navlist>
<forge-list-item id="li-1">
<button type="button">
List Item One
</button>
</forge-list-item>
<forge-popover arrow placement="right" trigger-type="hover" distinct="list-item-nav-popovers">
<div class="w-[300px] p-medium">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
</div>
</forge-popover>
<forge-list-item id="li-2">
<button type="button">
List Item Two
</button>
</forge-list-item>
<forge-popover arrow placement="right" trigger-type="hover" distinct="list-item-nav-popovers">
<div class="w-[300px] p-medium">
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</div>
</forge-popover>
<forge-list-item id="li-3">
<button type="button">
List Item Three
</button>
</forge-list-item>
<forge-popover arrow placement="right" trigger-type="hover" distinct="list-item-nav-popovers">
<div class="w-[300px] p-medium">
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo
inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.
</div>
</forge-popover>
</forge-list>
</forge-drawer>Popovers are used to show content in an element that is rendered above all other content on the page. Use popovers to display additional information or actions related to a specific element. Popovers are typically triggered by user interaction, such as clicking a button or hovering over an element.
import "@tylertech/forge/popover";| Property | Attribute | Type | Default | Description |
|---|---|---|---|---|
arrow | arrow | string | false | Whether or not the popover should render an arrow. |
animationType | animation-type | string | "zoom" | The animation type to use for the popover. Valid values are `'none'`, `'fade'`, `'slide'`, and `'zoom'` (default). |
triggerType | trigger-type | string | "click" | The trigger type(s) to use for the popover. Valid values are `'click'` (default), `'hover'`, `'focus'`, and `'longpress'`. Multiple can be specified. |
longpressDelay | longpress-delay | string | 500 | The delay in milliseconds before a longpress event is detected. |
persistentHover | persistent-hover | string | false | Whether or not the popover should remain open when the user hovers outside the popover. |
hoverDelay | hover-delay | number | 0 | The delay in milliseconds before the popover is shown. |
hoverDismissDelay | hover-dismiss-delay | string | 500 | The delay in milliseconds before the popover is dismissed when the user hovers outside of the popover. |
preset | preset | string | "popover" | The preset to use for the popover. |
distinct | distinct | string | null | null | Enforces that this popover should be the only one open with the same unique value. |
anchorAccessibility | anchor-accessibility | string | "auto" | Controls whether the popover manages accessibility attributes on the anchor element. |
overlay | — | IOverlayComponent | — | A readonly reference to the internal `<forge-overlay>` element instance. |
anchorElement | — | HTMLElement | VirtualElement | null | — | The anchor element to position the overlay relative to. |
anchor | anchor | string | null | — | The IDREF of the anchor element to position the overlay relative to. |
noAnchor | no-anchor | boolean | false | Whether the overlay should not be anchored to an element. This allows for custom positioning. |
open | open | boolean | false | Whether the overlay is open. |
inline | inline | boolean | false | Whether the overlay is inline. |
placement | placement | OverlayPlacement | "bottom" | The placement of the overlay. |
positionStrategy | position-strategy | OverlayPositionStrategy | "fixed" | The position strategy of the overlay. |
offset | offset | IOverlayOffset | {} | The offset of the overlay. |
shift | shift | OverlayShiftState | "auto" | Whether the overlay should shift to fit within the viewport. |
hide | hide | OverlayHideState | "anchor-hidden" | The hide state of the overlay. |
persistent | persistent | boolean | false | Whether the overlay should persist when the anchor is removed. |
flip | flip | OverlayFlipState | "auto" | Whether the overlay should flip placements to another side fit within the viewport. |
boundary | boundary | string | null | — | An IDREF to boundary element to constrain the overlay within. |
boundaryElement | — | HTMLElement | null | — | The boundary element instance to constrain the overlay within. |
fallbackPlacements | — | PositionPlacement[] | null | — | The fallback placements of the overlay. |
| Name | Type | Description |
|---|---|---|
forge-popover-beforetoggle | CustomEvent<IPopoverToggleEventData> | Dispatches before the popover is toggled, and is cancelable. |
forge-popover-toggle | CustomEvent<IPopoverToggleEventData> | Dispatches after the popover is toggled. |
| Name | Description |
|---|---|
(default) | The content to render inside the popover. |
| Name | Description |
|---|---|
::part(overlay) | The overlay root element. |
::part(surface) | The surface container element for the slotted content. |
| Name | Description |
|---|---|
--forge-popover-background | The background color of the popover surface. |
--forge-popover-border-radius | The border radius of the popover surface. |
--forge-popover-box-shadow | The box shadow of the popover surface. |
--forge-popover-border-width | The border width of the popover surface. |
--forge-popover-border-style | The border style of the popover surface. |
--forge-popover-border-color | The border color of the popover surface. |
--forge-popover-width | The width of the popover surface. Defaults to `auto`. |
--forge-popover-height | The height of the popover surface. Defaults to `auto`. |
--forge-popover-min-width | The minimum width of the popover surface. Defaults to `none`. |
--forge-popover-max-width | The maximum width of the popover surface. Defaults to `none`. |
--forge-popover-min-height | The minimum height of the popover surface. Defaults to `none`. |
--forge-popover-max-height | The maximum height of the popover surface. Defaults to `none`. |
--forge-popover-arrow-size | The size of the arrow. |
--forge-popover-arrow-height | The height of the arrow. |
--forge-popover-arrow-width | The width of the arrow. |
--forge-popover-arrow-background-color | The background color of the arrow. Defaults to the background color of the popover surface. |
--forge-popover-arrow-top-rotation | The rotation of the arrow when the popover is placed on the top. |
--forge-popover-arrow-right-rotation | The rotation of the arrow when the popover is placed on the right. |
--forge-popover-arrow-bottom-rotation | The rotation of the arrow when the popover is placed on the bottom. |
--forge-popover-arrow-left-rotation | The rotation of the arrow when the popover is placed on the left. |
--forge-popover-arrow-border-width | The border width of the popover surface and arrow when an arrow is applied. |
--forge-popover-arrow-clip-path | The clip path to use for the arrow element. |
--forge-popover-animation-timing | The animation timing function to use for the popover animation. |
--forge-popover-zoom-duration | The duration of the zoom animation. |
--forge-popover-zoom-timing | The timing function to use for the zoom animation. |
--forge-popover-slide-duration | The duration of the slide animation. |
--forge-popover-slide-timing | The timing function to use for the slide animation. |
--forge-popover-slide-offset | The start offset to use for the slide animation. |
--forge-popover-fade-duration | The duration of the fade animation. |
--forge-popover-fade-timing | The timing function to use for the fade animation. |
--forge-popover-position-block-start | The `block-start` position of the popover. |
--forge-popover-position-block-end | The `block-end` position of the popover. |
--forge-popover-position-inline-start | The `inline-start` position of the popover. |
--forge-popover-position-inline-end | The `inline-end` position of the popover. |
--forge-popover-preset-dropdown-max-height | The maximum height of the popover when using `preset="dropdown"`. Defaults to `256px`. |
--forge-popover-preset-dropdown-overflow | The overflow behavior of the popover when using `preset="dropdown"`. Defaults to `auto visible` (vertical scrolling only). |
| Name | Returns | Description |
|---|---|---|
hideAsync() | Promise<void> | Hides the popover, and returns a `Promise` that resolves when the hide animation is complete. |
position() | void | Forces the overlay to reposition itself. |
No default semantics
A popover has no semantic meaning by default. Add the appropriate ARIA attributes to the popover itself, or to the content inside it, based on what that content actually needs.
Popover vs. dialog
Popovers are transient and non-modal — they don’t block interaction with the rest of the page. Dialogs are typically modal and demand the user’s immediate attention. When a design calls for something in between, weigh the UX and accessibility implications of each rather than defaulting to one.
To make a popover behave like a non-modal dialog, add role="dialog" and aria-modal="false" — this tells screen readers it’s a dialog that doesn’t block the rest of the page, which is useful for gracefully handling in-progress form entry without risking accidental data loss on dismiss.