A wider screen, please

This page features interactive demos and side-by-side code samples that need at least 340 pixels of horizontal space. Please widen your browser window, or rotate your device, to continue.

Morpheus v0.1.0
v0.1.0

Boundary#

Component <neo-boundary> is a logical scoping region for overlays. An overlay inside it (Popover, Menu, Select, Combobox, or Text input suggestions) treats the boundary as its local document and viewport. Its scope attribute is a space-separated token list that defaults to "dismiss positioning": outside clicks and focus no longer dismiss the overlay, and its panel clamps to the region instead of the viewport. Setting scope replaces that default, so add a token to opt into a scope or drop one to turn it off. The scroll token lets independent scrollers outside the region move without closing the overlay; stacking layers the region's overlays inside it rather than the document root. Both are off by default. The element is layout-neutral (display: contents) until stacking gives it a box, and never clips a panel. Escape and trigger toggles always close an overlay.

Reference#

Attributes #

NameTypeDefaultDescription
scope"dismiss" | "positioning" | "scroll" | "stacking" (space-separated)"dismiss positioning"Space-separated list of the scopes this region applies. Setting it replaces the default (dismiss positioning) entirely, so list every scope you want; omit a token to fall back to the document / viewport default for it, and scope="" scopes nothing. Tokens: dismiss: a pointer or focus event outside the boundary does not close an overlay inside it (only events inside the boundary but outside the overlay do). positioning: overlay panels clamp and flip against this region's box (the union of the boundary's laid-out descendant rects) instead of the viewport. scroll: a genuinely independent scroll container outside this region can move without closing an embedded overlay; a scroll inside the region, or on an ancestor scroller that carries the region, still dismisses. stacking: the region establishes a local stacking context (isolation: isolate) so its overlays layer inside it, not the document root; this is the one scope that drops display: contents for a box.

Slots #

NameDescription
defaultThe content the boundary scopes. Each overlay inside reads its nearest <neo-boundary> ancestor (via closest("neo-boundary")) and obeys that boundary's scopes only. Rules are not inherited: a closer boundary that turns a scope off falls back to the document or viewport default for that scope, not to an outer boundary. Scoping is purely logical (composed-path containment) and non-visual, so a fixed or top-layer panel still counts as inside through its host even though it paints outside the boundary's box.

Examples#

Scoped dismiss#

Two regions, each a <neo-boundary>. Open an overlay in one, then click or open something in the other: the first stays open, because each boundary scopes dismiss to itself. Without boundaries, the second interaction would close the first.

Project AActions

Actions

Rename, archive, or delete.

To do In progress DoneAlice Larsson Diego Vega Evelyn Kone
Project BActions

Actions

Rename, archive, or delete.

Backlog Active ShippedSamira Khalil Theo Becker Jan O'Sullivan

Positioning containment#

Open the popover. The panel clamps and flips against the dashed region instead of the viewport. The trigger sits at the region's bottom edge, so the panel flips above it to stay inside. Set scope="dismiss" to clamp to the viewport instead.

Filters

Filters

The panel is clamped to the dashed region instead of the viewport, so it flips above the trigger to stay inside. Drop the positioning token from scope to clamp to the viewport instead.

Scroll scope#

The Account menu is an embedded widget inside a scrollable panel; its boundary adds the scroll token (scope="dismiss positioning scroll"). Open the menu, then scroll the panel around it: because that scroller carries the boundary itself, the popover closes instead of floating through the container. Independent scrollers outside the boundary can move without dismissing it.

Diego Vega commented on Onboarding flow.

Evelyn Kone merged Release 2.4.

Account

Account

Signed in as Alice Larsson.

An embedded widget, scoped by its own <neo-boundary>.

Samira Khalil opened Billing audit.

Theo Becker closed Flaky e2e test.

Jan O'Sullivan updated Design tokens.

Alice Larsson archived Q3 planning.

Maya Lindqvist pinned the Roadmap.

Stacking scope#

Stacking scope is opt-in: the right widget adds the stacking token to establish a local stacking context, so its overlays layer inside the region instead of the document root. Both widgets open the same popover (global z-index: 1000) across a host overlay at z-index: 100.

  • Left (default): no stacking context, so the panel outranks the host overlay and paints over it.
  • Right (stacking): the panel is confined to the region's context, so the host overlay paints over it instead.

Open both popovers to compare. Enabling stacking gives the region a box (isolation: isolate), the one scope that drops display: contents.

Host app overlay · z-index 100

Default

Account

Account

Signed in as Alice Larsson.

Plan: Team · 4 seats

No stacking context, so the panel's z-index 1000 paints over the host overlay.

stacking

Account

Account

Signed in as Alice Larsson.

Plan: Team · 4 seats

A local stacking context confines the panel, so the host overlay paints over it.

Nested boundaries#

The closest boundary defines the rules; they are not inherited. The inner boundary uses scope="positioning" (no dismiss), so its popover closes on any outside click (document scope), even though the outer boundary enables dismiss scoping. A closer boundary that turns a scope off falls back to the document or viewport default, never to the outer boundary. Open the popover, then click outside it to see it close.

Outer boundary: default scope.

Menu

The closest boundary defines the rules. Dismiss is off here, so a click anywhere outside this popover closes it, even though the outer boundary enables dismiss scoping. Rules are not inherited.

Inner boundary: scope="positioning" (no dismiss).

Settings

Theme

Default Sunshine Ocean Matrix Rose

Accessibility

Playgrounds

Server Simulator