overlay-trigger

Overview API
triggered-by performance optimization
Use the new triggered-by attribute to declare which types of overlays your implementation will use. This improves performance by avoiding unnecessary DOM operations and preventing race conditions during rendering. For more information, read the Performance optimization section.

When to use overlay-trigger

Section titled When to use overlay-trigger

Use <overlay-trigger> when you need multiple interaction types on a single trigger element. This component excels at:

  • Hover tooltip + click dialog: Show a tooltip on hover and open a dialog on click
  • Multiple related actions: Different overlays for click, hover, and longpress on the same element
  • Simplified API: Slot-based approach with automatic content lifecycle management

Don't use <overlay-trigger> when you need:

  • Virtual positioning: VirtualTrigger for cursor-based positioning (use <sp-overlay> or imperative API)
  • Single interaction only: For one interaction type, <sp-overlay> is simpler
  • Fine-grained control: Advanced features like custom focus behavior (use <sp-overlay>)

See the Getting Started Guide for a complete comparison of entry points.

Overview

Section titled Overview

An <overlay-trigger> element supports the delivery of temporary overlay content based on interaction with a persistent trigger element. An element prepared to receive accessible interactions (e.g. an <sp-button>, or <button>, etc.) is addressed to slot="trigger", and the content to display (either via click or hover/focus interactions) is addressed to slot="click-content" or slot="hover-content", respectively. A trigger element can be linked to the delivery of content, intended for a single interaction, or both. Content addressed to slot="hover-content" is made available when the mouse enters or leaves the target element. Keyboard navigation will make this content available when focus enters or leaves the target element. Be thoughtful with what content you address to slot="hover-content", as the content available via "hover" will be transient and non-interactive.

Usage

Section titled Usage

See it on NPM! How big is this package in your project?

yarn add @spectrum-web-components/overlay

Import the side-effectful registration of <overlay-trigger> via:

import '@spectrum-web-components/overlay/overlay-trigger.js';

The default of <overlay-trigger> will load dependencies in @spectrum-web-components/overlay asynchronously via a dynamic import. In the case that you would like to import those tranverse dependencies statically, import the side effectful registration of <overlay-trigger> as follows:

import '@spectrum-web-components/overlay/sync/overlay-trigger.js';

When looking to leverage the OverlayTrigger base class as a type and/or for extension purposes, do so via:

import { OverlayTrigger } from '@spectrum-web-components/overlay';

Example

Section titled Example

In this example, a default <overlay-trigger> manages content that is triggered by "click" and "hover" interactions.

<overlay-trigger placement="top" type="replace">
    <sp-button slot="trigger">Overlay Trigger</sp-button>
    <sp-popover slot="click-content" open>
        <sp-dialog size="s">
            <h2 slot="heading">Click content</h2>
            An &lt;overlay-trigger&gt; can be used to manage either or both of
            the "click" and "hover" content slots that are made available. Here,
            content is only addressed to
            <code>slot="click-content"</code>
            ...
            <sp-button
                slot="button"
                onclick="javascript: this.dispatchEvent(new Event('close', {bubbles: true, composed: true}));"
            >
                I understand
            </sp-button>
        </sp-dialog>
    </sp-popover>
    <sp-tooltip slot="hover-content">Hover content</sp-tooltip>
</overlay-trigger>

Options

Section titled Options

Placement

Section titled Placement

When using the placement attribute of an <overlay-trigger> ("top" |"top-start" | "top-end" | "bottom" | "bottom-start" | "bottom-end" | "right" | "right-start" | "right-end" | "left" | "left-start" | "left-end"), you can suggest to the overlay in which direction relative to the trigger that the content should display. When there is adequate room for the content to display in the specified direction, it will do so. When adequate room is not available, the overlaid content will calculate the direction in which it has the most room to be displayed and use that direction.

Type

Section titled Type

The type of an Overlay outlines a number of things about the interaction model within which it works:

Note: The type attribute only affects click-triggered overlays. Hover overlays always use hint type behavior, and longpress overlays always use auto type behavior. For more control over hover and longpress overlay types, use <sp-overlay> directly.

Combining multiple interactions

Section titled Combining multiple interactions

One of the key benefits of <overlay-trigger> is supporting multiple interaction types on a single trigger:

<!-- Tooltip on hover, dialog on click -->
<overlay-trigger placement="top">
    <sp-button slot="trigger">Help</sp-button>

    <!-- Shows on hover - always non-interactive (hint type) -->
    <sp-tooltip slot="hover-content">Click for more information</sp-tooltip>

    <!-- Shows on click - interactive (uses type attribute) -->
    <sp-popover slot="click-content">
        <sp-dialog size="s">
            <h2 slot="heading">Help</h2>
            <p>Detailed help content goes here...</p>
            <sp-button
                slot="button"
                onclick="this.dispatchEvent(new Event('close', {bubbles: true}))"
            >
                Got it
            </sp-button>
        </sp-dialog>
    </sp-popover>
</overlay-trigger>

Important: Hover content limitations

Section titled Important: Hover content limitations

Content in slot="hover-content" is always non-interactive because it uses hint type behavior:

  • Cannot contain focusable elements
  • Closes when the user interacts with the page
  • Best for tooltips and brief informational content

If you need interactive content on hover, use <sp-overlay> with trigger="id@hover" and type="auto" instead.

Interaction type combinations

Section titled Interaction type combinations

Common patterns:

Tooltip + Action:

<overlay-trigger>
    <sp-button slot="trigger">Delete</sp-button>
    <sp-tooltip slot="hover-content">Delete item</sp-tooltip>
    <sp-popover slot="click-content">
        <sp-dialog>
            <h2 slot="heading">Confirm deletion</h2>
            <p>Are you sure?</p>
        </sp-dialog>
    </sp-popover>
</overlay-trigger>

Longpress + Hover:

<overlay-trigger>
    <sp-action-button slot="trigger" hold-affordance>
        <sp-icon-settings slot="icon"></sp-icon-settings>
    </sp-action-button>
    <sp-tooltip slot="hover-content">Hold for more options</sp-tooltip>
    <sp-popover slot="longpress-content">
        <sp-menu>
            <sp-menu-item>Option 1</sp-menu-item>
            <sp-menu-item>Option 2</sp-menu-item>
        </sp-menu>
    </sp-popover>
</overlay-trigger>

All three interactions:

<overlay-trigger>
    <sp-button slot="trigger">Actions</sp-button>
    <sp-tooltip slot="hover-content">Quick action menu</sp-tooltip>
    <sp-popover slot="click-content">
        <sp-menu>
            <sp-menu-item>Copy</sp-menu-item>
            <sp-menu-item>Paste</sp-menu-item>
        </sp-menu>
    </sp-popover>
    <sp-popover slot="longpress-content">
        <sp-menu>
            <sp-menu-item>Advanced option 1</sp-menu-item>
            <sp-menu-item>Advanced option 2</sp-menu-item>
        </sp-menu>
    </sp-popover>
</overlay-trigger>
Modal

'modal' Overlays create a modal context that traps focus within the content and prevents interaction with the rest of the page. The overlay manages focus trapping and accessibility features like aria-modal="true" to ensure proper screen reader behavior.

They should be used when you need to ensure that the user has interacted with the content of the Overlay before continuing with their work. This is commonly used for dialogs that require a user to confirm or cancel an action before continuing.

<overlay-trigger type="modal" triggered-by="click">
    <sp-button slot="trigger">Open modal</sp-button>
    <sp-dialog-wrapper
        slot="click-content"
        headline="Signin form"
        dismissable
        underlay
    >
        <p>I am a modal type overlay.</p>
        <sp-field-label>Enter your email</sp-field-label>
        <sp-textfield placeholder="test@gmail.com"></sp-textfield>
        <sp-action-button
            onClick="
                this.dispatchEvent(
                    new Event('close', {
                        bubbles: true,
                        composed: true,
                    })
                );
            "
        >
            Sign in
        </sp-action-button>
    </sp-dialog-wrapper>
</overlay-trigger>
Page

'page' Overlays behave similarly to 'modal' Overlays by creating a modal context and trapping focus, but they will not be allowed to close via the "light dismiss" algorithm (e.g. the Escape key).

A page overlay could be used for a full-screen menu on a mobile website. When the user clicks on the menu button, the entire screen is covered with the menu options.

<overlay-trigger type="page" triggered-by="click">
    <sp-button slot="trigger">Open page</sp-button>
    <sp-dialog-wrapper
        slot="click-content"
        headline="Full screen menu"
        mode="fullscreenTakeover"
        cancel-label="Close"
    >
        <p>I am a page type overlay.</p>
    </sp-dialog-wrapper>
</overlay-trigger>
Hint

'hint' Overlays are much like tooltips so they are not just ephemeral, but they are delivered primarily as a visual helper and exist outside of the tab order. In this way, be sure not to place interactive content within this type of Overlay.

This overlay type does not accept focus and does not interfere with the user's interaction with the rest of the page.

<overlay-trigger type="hint" triggered-by="hover">
    <sp-button slot="trigger">Open hint</sp-button>
    <sp-tooltip slot="click-content">
        I am a hint type overlay. I am not interactive and will close when the
        user interacts with the page.
    </sp-tooltip>
</overlay-trigger>
Auto

'auto' Overlays provide a place for content that is ephemeral and interactive. These Overlays can accept focus and remain open while interacting with their content. They will close when focus moves outside the overlay or when clicking elsewhere on the page.

<overlay-trigger type="auto" triggered-by="click" placement="bottom">
    <sp-button slot="trigger">Open overlay</sp-button>
    <sp-popover slot="click-content" dialog>
        <p>
            My slider in overlay element:
            <sp-slider label="Slider Label - Editable" editable></sp-slider>
        </p>
    </sp-popover>
</overlay-trigger>
Manual

'manual' Overlays act much like 'auto' Overlays, but do not close when losing focus or interacting with other parts of the page.

Note: When a 'manual' Overlay is at the top of the "overlay stack", it will still respond to the Escape key and close.

<style>
    .chat-container {
        position: fixed;
        bottom: 1em;
        left: 1em;
    }
</style>
<overlay-trigger type="manual" triggered-by="click">
    <sp-button slot="trigger">Open manual</sp-button>
    <sp-popover slot="click-content" class="chat-container">
        <sp-dialog dismissable>
            <span slot="heading">Chat Window</span>
            <sp-textfield placeholder="Enter your message"></sp-textfield>
            <sp-action-button>Send</sp-action-button>
        </sp-dialog>
    </sp-popover>
</overlay-trigger>

Performance optimization

Section titled Performance optimization

The triggered-by attribute (triggeredBy property) allows you to explicitly declare which types of overlays your implementation will use. This can help optimize performance by avoiding unnecessary DOM operations and preventing race conditions during rendering.

<!-- Only using click and hover overlays -->
<overlay-trigger triggered-by="click hover">
    <sp-button slot="trigger">Click and hover trigger</sp-button>
    <sp-popover slot="click-content" direction="bottom" tip>
        Click content
    </sp-popover>
    <sp-tooltip slot="hover-content">Hover content</sp-tooltip>
</overlay-trigger>

<!-- Only using longpress overlay -->
<overlay-trigger triggered-by="longpress">
    <sp-button slot="trigger">Longpress trigger</sp-button>
    <sp-popover slot="longpress-content" direction="bottom" tip>
        Longpress content
    </sp-popover>
    <div slot="longpress-describedby-descriptor">
        Press and hold to reveal more options
    </div>
</overlay-trigger>

The triggered-by attribute accepts a space-separated string of overlay types:

  • click - For click-triggered content
  • hover - For hover/focus-triggered content
  • longpress - For longpress-triggered content

When not specified, the component will automatically detect which content types are present, but this may result in additional rendering cycles. For optimal performance, especially in applications with many overlay triggers, explicitly declaring the content types you plan to use is recommended.

Accessibility best practices

Section titled Accessibility best practices

When using <overlay-trigger>, follow these accessibility guidelines:

Interactive trigger elements

Section titled Interactive trigger elements

The content in slot="trigger" must be "interactive" - able to receive focus and respond to keyboard events. Use:

  • <sp-button> or native <button>
  • <sp-action-button>
  • <a href="#"> (links)
  • Other focusable, keyboard-accessible elements

Don't use:

  • <div> or <span> without proper ARIA roles and keyboard handlers
  • Elements that can't receive focus

ARIA attributes

Section titled ARIA attributes

Add appropriate ARIA attributes to trigger elements:

<overlay-trigger type="modal">
    <sp-button slot="trigger" aria-haspopup="dialog" aria-expanded="false">
        Open Dialog
    </sp-button>
    <sp-popover slot="click-content">
        <sp-dialog aria-labelledby="dialog-title">
            <h2 id="dialog-title" slot="heading">Dialog Title</h2>
            <p>Dialog content...</p>
        </sp-dialog>
    </sp-popover>
</overlay-trigger>

Recommended attributes:

  • aria-haspopup: Indicates the type of overlay ("dialog", "menu", "true")
  • aria-expanded: Reflects overlay open/closed state (managed automatically by overlay system)
  • aria-labelledby / aria-label: Labels for overlay content

Keyboard navigation

Section titled Keyboard navigation

The overlay system handles most keyboard interactions:

  • ESC: Closes overlay and returns focus to trigger
  • TAB: Navigates within interactive overlays
  • Enter/Space: Activates trigger button

For hover tooltips, ensure keyboard users can access the same information:

<!-- Good: Tooltip accessible via focus -->
<overlay-trigger>
    <sp-button slot="trigger">Help</sp-button>
    <sp-tooltip slot="hover-content">
        This tooltip shows on both hover and keyboard focus
    </sp-tooltip>
</overlay-trigger>

Screen reader support

Section titled Screen reader support

Follow these guidelines:

  • Use proper heading structure in overlay content
  • Provide descriptive labels for all interactive elements
  • Ensure error messages in overlays are announced

For more details, see the Accessibility Guide.

Learn more about accessible keyboard interactions at W3C WCAG 2.1 Understanding keyboard.

API

Attributes and Properties

Section titled Attributes and Properties
Property Attribute Type Default Description disabled disabled boolean false Whether the overlay trigger is disabled. When `true`, overlays cannot be opened offset offset number 6 The distance (in pixels) between the overlay and the trigger. Default: `6` open open OverlayContentTypes | undefined placement placement "top" | "top-start" | "top-end" | "right" | "right-start" | "right-end" | "bottom" | "bottom-start" | "bottom-end" | "left" | "left-start" | "left-end" The placement of the overlay relative to the trigger. Same options as ``: `"top"`, `"bottom"`, `"left"`, `"right"`, with `-start` and `-end` variants receivesFocus receives-focus 'true' | 'false' | 'auto' 'auto' How focus should be handled when overlay opens. Options: `"true"` (always focus), `"false"` (never focus), `"auto"` (based on overlay type). Only affects `click-content` triggeredBy triggered-by string Performance optimization that explicitly declares which interaction types are used.

Benefits of declaring triggered-by:

  1. Prevents extra renders - Avoids unnecessary slot reparenting
  2. Eliminates race conditions - Prevents infinite render loops during content detection
  3. Reduces DOM nodes - Only creates overlays for declared content types
  4. Improves initial load - Skips detection cycles for unused interaction types

When to use:

  • Applications with many <overlay-trigger> elements (10+)
  • Performance-critical pages
  • Mobile applications

Format: Space-separated list of interaction types

type type OverlayTypes | undefined Configures behavior of `click-content` overlay. Options: `"auto"`, `"modal"`, `"manual"`, `"page"`. **Note:** Hover uses `hint`, longpress uses `auto`

Slots

Section titled Slots
Name Description click-content Content displayed on click. Interactive (uses `type` attribute). Best for menus, dialogs, and interactive popovers. hover-content Content displayed on hover/focus. **Always non-interactive** (uses `hint` type). Best for tooltips and brief informational content. longpress-content Content displayed on longpress gesture (300ms hold) or Space/Alt+Down keys. Interactive (uses `auto` type). Best for contextual actions. longpress-describedby-descriptor Automatically managed description text for longpress affordance (e.g., "Double tap and long press for additional options") trigger The interactive element that triggers the overlays (e.g., ``, ``). Must be keyboard accessible.

Events

Section titled Events
Name Type Description sp-closed Event Announces that an overlay has completed any exit animations and is fully closed sp-opened Event Announces that an overlay has completed any entry animations and is fully visible