overlay — shared open/close logic for popovers
Low-level building block. You typically don't include it directly — dropdown, popover, modal-like components depend on it. Pull it in only when you build a custom overlay-style component.
It handles the four things every overlay needs:
- Toggle an
is-openclass on a root element - Close on
Esckeydown - Close on click outside the root (uses
outside-click.jsfrombase) - Lifecycle callbacks (
onOpen,onClose)
No DOM, no styles — just a tiny class.
Install
npx czg-ui add overlay
import { Overlay } from './components/overlay';
Requires base.
API
const overlay = new Overlay(rootEl, opts);
overlay.open();
overlay.close();
overlay.toggle();
overlay.isOpen; // boolean
Options
| Option | Default | Notes |
|---|---|---|
openClass | 'is-open' | CSS class toggled on the root |
closeOnEscape | true | Close on Esc key globally |
closeOnOutsideClick | true | Close on click outside the root |
onOpen | () => {} | Called after open() finishes |
onClose | () => {} | Called after close() finishes |
Usage — building a custom popover
import { Overlay } from './components/overlay';
const root = document.querySelector('[data-popover]');
const popover = new Overlay(root, {
onOpen: () => trigger.setAttribute('aria-expanded', 'true'),
onClose: () => trigger.setAttribute('aria-expanded', 'false'),
});
trigger.addEventListener('click', () => popover.toggle());
.my-popover {
display: none;
&.is-open { display: block; }
}
When NOT to use
- Modal dialogs — you also need a focus trap + scroll lock; reach
for a dedicated modal component
- Inline expanders that don't need outside-click / Esc — use plain
<details>