Morphos
Overlays

Popover

A floating panel anchored to a trigger element, used to display rich non-modal content.

Interactive example

Installation

npm install @morphos/overlays
pnpm add @morphos/overlays
yarn add @morphos/overlays
bun add @morphos/overlays

Import

import { Popover, PopoverTrigger, PopoverContent } from '@morphos/overlays'

Usage

@Component()
class MyComponent extends StatefulComponent {
  @State() popover = new Popover()

  render() {
    return (
      <>
        <PopoverTrigger popover={this.popover}>
          Open popover
        </PopoverTrigger>
        <PopoverContent popover={this.popover} aria-label="Settings">
          <p>Popover content goes here.</p>
        </PopoverContent>
      </>
    )
  }
}

Compound components

ComponentDescription
PopoverRoot state manager. Owns open state, computed anchor position, and outside-click/escape behavior.
PopoverTrigger<button> that toggles the popover on click. Sets aria-haspopup="true", aria-expanded, aria-controls, and data-open.
PopoverContentRenders into a Portal, positioned with position: fixed. Sets role="dialog" and data-open. Closes on outside click and Escape.

Props — Popover

PropTypeDefaultDescription
openbooleanControlled open state. When set, the consumer owns the state.
defaultOpenbooleanfalseInitial open state in uncontrolled mode.
onOpenChange(open: boolean) => voidCalled when the open state changes.
closeOnEscapebooleantrueWhether pressing Escape closes the popover.
closeOnOutsideClickbooleantrueWhether clicking outside the content (and outside the trigger) closes the popover.
side"top" | "bottom" | "left" | "right""bottom"Which edge of the trigger the popover is placed against.
align"start" | "center" | "end""start"Alignment of the popover along the trigger's perpendicular axis.
sideOffsetnumber4Gap in pixels between the trigger and the popover.
childrenChildrenContent — typically PopoverTrigger and PopoverContent.

Methods

MethodDescription
toggle()Toggles the open state (recomputing position when opening). Emits onOpenChange.
closePopover()Closes the popover. Emits onOpenChange(false).

Props — PopoverTrigger

PropTypeDefaultDescription
popoverPopoverThe Popover instance this trigger controls.
childrenChildrenThe trigger element content.
classstringCSS class.
idstringHTML id.

Props — PopoverContent

PropTypeDefaultDescription
popoverPopoverThe Popover instance this content belongs to.
childrenChildrenPopover body content.
classstringCSS class.
idstringHTML id. Falls back to an auto-generated id.
aria-labelstringAccessible label.
aria-labelledbystringID of the element that labels the popover.

Keyboard navigation

KeyAction
EscapeCloses the popover (if closeOnEscape is true)

data-* attributes

AttributeElementWhen present
data-openPopoverTriggerPopover is open
data-openPopoverContent rootPopover is open

PopoverContent renders with role="dialog" inside a Portal. Provide an aria-label or aria-labelledby prop to satisfy accessibility requirements. Its position is computed with computeAnchorPosition() from @morphos/core, using PopoverTrigger's bounding rect and the side/align/sideOffset props on Popover. Popover does not trap focus or lock scroll — it is non-modal; use Dialog for modal content instead.

Styling example

.morphos-popover-content {
  z-index: 100;
  min-width: 12rem;
  max-width: 24rem;
  padding: var(--morphos-space-4);
  background: var(--morphos-color-bg);
  border: 1px solid var(--morphos-color-border);
  border-radius: var(--morphos-radius-lg);
}

On this page