A library for resizable & repositionable panel layouts.
- Zero depedencies, pure TypeScript, tiny.
- Implemented as a Web Component, interoperable with any framework.
- Zero DOM mutation at runtime, implemented entirely by generating using
CSS
gridrules. - Supports arbitrary theming via CSS variables and
::part. - Supports async-aware container rendering for smooth animations even when rendering ovvurs over an event loop boundary.
- Covered in bees.
Demo
Installation
npm install regular-layout
Quick Start
Import the library and add <regular-layout> to your HTML. Children are
matched to layout slots by their name attribute.
<script type="module" src="regular-layout/dist/index.js"></script> <regular-layout> <div name="main">Main content</div> <div name="sidebar">Sidebar content</div> </regular-layout>
For draggable, tabbed panels, use <regular-layout-frame>:
<regular-layout> <regular-layout-frame name="main"> Main content </regular-layout-frame> <regular-layout-frame name="sidebar"> Sidebar content </regular-layout-frame> </regular-layout>
Panels must be added and remove programmatically (e.g they are not auto-registered):
const layout = document.querySelector("regular-layout"); // This adds the panel definition to the layout (and makes it visible via CSS), // but does not mutat the DOM. layout.insertPanel("main"); layout.insertPanel("sidebar"); // This removes the panel from the layout (and hides it via CSS) but does not // mutate the DOM. layout.removePanel("sidebar");
Save/Restore
Layout state serializes to a JSON tree of splits and tabs, which can be persisted and restored:
const state = layout.save(); localStorage.setItem("layout", JSON.stringify(state)); // Later... layout.restore(JSON.parse(localStorage.getItem("layout")));
restore() dispatches a cancelable regular-layout-before-resize event before
applying the new state. Call preventDefault() to suspend the update, then
layout.resumeResize() when ready:
layout.addEventListener("regular-layout-before-resize", (event) => { event.preventDefault(); // ... prepare for resize ... layout.resumeResize(); });
The restore() API can also be used as an alternative to
insertPanel/removePanel for initializing a <regular-layout>.
Theming
Themes are plain CSS files that style the layout and its ::part() selectors,
scoped by a class on <regular-layout>. Apply a theme by adding its stylesheet
and setting the class:
<link rel="stylesheet" href="regular-layout/themes/chicago.css"> <regular-layout class="chicago"> ... </regular-layout>
<regular-layout-frame> exposes these CSS parts:
| Part | Description |
|---|---|
titlebar |
Tab bar container |
tab |
Individual tab |
active-tab |
Currently selected tab |
close |
Close button |
active-close |
Close button on the active tab |
container |
Content area |
regular-layout.mytheme regular-layout-frame::part(titlebar) { background: #333; } regular-layout.mytheme regular-layout-frame::part(active-tab) { background: #fff; color: #000; }
See the example themes/ directory for examples of how to write a
complete theme for <regular-layout> and regular-layout-frame>.
Events
| Event | Detail | Cancelable | Description |
|---|---|---|---|
regular-layout-before-resize |
{ calculatePresizePaths() } |
Yes | Fired before any layout change. Cancel to suspend until resumeResize(). |
regular-layout-update |
Layout |
No | Fired after layout state is updated. |
layout.addEventListener("regular-layout-update", (event) => { console.log("New layout:", event.detail); });
