Overlay
@ailuracode/alpine-overlay
Centralized portal root, z-index slot allocation, and open-stack registry for Alpine.js applications.
Headless. No Tailwind, no CSS framework. No DOM mutation outside the portal root itself.
Install
pnpm add @ailuracode/alpine-overlay @ailuracode/alpine-core @ailuracode/alpine-ui alpinejsQuick start
import Alpine from "alpinejs";import { overlayPlugin } from "@ailuracode/alpine-overlay";
Alpine.plugin(overlayPlugin({ baseZIndex: 1000, step: 10 }));
Alpine.start();Template:
<template x-teleport="#overlay-root"> <div class="dialog" :style="{ zIndex: $store.overlay.zIndexOf('dialog', 'confirm') }"> <!-- ... --> </div></template>Avoiding name collisions
If your application already owns a $store.overlay — or another toolkit plugin registers on that name — rename the integration surface without touching the controller:
Alpine.plugin(overlayPlugin({ storeKey: "stack" })); // → $store.stackThe exposed constant DEFAULT_OVERLAY_STORE_KEY keeps the rename discoverable from TypeScript.
API
$store.overlay
| Member | Type | Description |
|---|---|---|
stack |
readonly OverlayStackEntry[] |
Open overlays sorted by z-index (top last) |
count |
number |
stack.length |
root |
HTMLElement | null |
Portal container (lazily created) |
baseZIndex |
number |
Initial slot (default 1000) |
step |
number |
Slot gap (default 10) |
configure(opts) |
void |
Idempotent setup. root, baseZIndex, step. |
register(plugin, id) |
number |
Allocate slot, returns zIndex |
unregister(plugin, id) |
void |
Release slot (silent if unknown) |
zIndexOf(plugin, id) |
number |
Lookup allocated zIndex (0 after destroy) |
isOpen(plugin, id) |
boolean |
Whether (plugin, id) is on the stack |
on('change', cb) |
Unsubscribe |
Subscribe to stack transitions |
$overlay magic
Shorthand for $store.overlay. Same shape.
License
MIT © ailuracode
