OGE logoOGE

Modal

oge-modal is the centered dialog primitive: backdrop, focus trap, body scroll lock, Escape/backdrop closing and focus restore. Content renders lazily behind the opened model and joins the shared overlay Escape stack, so popups opened inside the modal close before the modal itself. Declare it near the component root — transformed ancestors break position: fixed.

oge-modal [(opened)] closeGuard *ogeModalFooter

Basics

Open declaratively via the two-way opened model or imperatively with open()/close()/toggle(). The footer slot's let close function closes the modal; Escape, backdrop clicks and the ✕ button work out of the box and focus returns to the opener.

[(opened)] title *ogeModalFooter

Form content & stacked popups

Any content projects into the body — including dropdown editors. Their popups render above the modal, and the shared Escape stack closes the topmost surface first: one Escape for the open select popup, a second for the modal.

width oge-select-box Escape stack

Full screen, placement & sizing

showMaximizeButton puts a maximize/restore toggle in the title bar, driving the two-way fullScreen model (size inputs are ignored while full screen). placement="top" pins the dialog near the top edge — command-palette style — and [shading]="false" keeps the backdrop transparent while staying fully modal. Sizing accepts width/height plus min/max variants, as numbers (px) or CSS strings.

[(fullScreen)] placement shading min/max size

Window mode & modal service

dragEnabled makes the title bar a drag handle (viewport-clamped unless dragOutsideBoundary), resizeEnabled adds a corner handle with resizeStarted/resized events, and restorePosition resets both on reopen. For imperative flows — or transformed ancestors — OgeModalService.open(component, config) renders a body-appended modal; the content injects OGE_MODAL_DATA and closes itself via OgeModalRef, whose closed promise carries the typed result. inertBackground additionally marks the page behind the modal inert.

dragEnabled resizeEnabled OgeModalService inert
service result: —

Async close guard

closeGuard runs before every close — Escape, backdrop, ✕ and close() alike — and may return a Promise<boolean>: the modal stays open until it resolves, single-flight guarded. No other library covers the async unsaved-changes veto without hand-rolled plumbing. A direct opened model write bypasses the guard (the app already decided).

closeGuard closePending async veto

Busy state

While busy is true the modal shows a spinner veil, sets aria-busy and blocks user-initiated closes — programmatic close() still works, so finish your async work and close. Pairs naturally with the button family's async action.

busy aria-busy spinner veil

Typed result

close(result) — from code or the footer slot — carries a typed value into closed, alongside the close reason. Declarative confirm/prompt flows no longer need side-channel component state.

close(result) OgeModalClosedEvent reason
outcome: —

Notes

  • autoFocus picks the initial focus target: 'first-tabbable' (default), 'panel', or any CSS selector; an [autofocus] element always wins.
  • Headerless modals (showCloseButton=false, no title) should set ariaLabel; [padding]="false" makes the body flush for grids and custom layouts.
  • The ✕ button's aria label localizes via provideOgeOverlayConfig({ messages: { modalClose: '…' } }) or the per-instance messages input.
  • Body scroll locks while open (scrollbar-width compensated, ref-counted across stacked modals) — disable with [scrollLock]="false".