Constructor

new Panel(elementOrSelector: HTMLElement | string, options?: PanelConfig)


Builds a Panel on a single element, from a selector or an element reference. Reach for this when you want a handle on one panel. To wire up many at once, Panel.init() (further down) is less typing.

Parameters:

elementOrSelector
A CSS selector string or HTMLElement reference to the [data-panel] element.
options (optional)
A configuration object. See Panel - Configuration for all options.
JavaScript
const panel = new Panel('#my-panel');
const panel = new Panel('#my-panel', { axis: 'horizontal' });
const panel = new Panel(document.getElementById('my-panel'));

Instance methods

panel.open(event?): Promise<void>


OOpen the panel. Nothing happens if it is already open.

Parameters:

event (optional)
The triggering event. When passed, autoFocus only fires on keyboard events. Mouse clicks are ignored, preventing unwanted scroll.

Returns:

A promise that resolves once the opening transition has finished.

panel.close(): void


Close the panel. Nothing happens if it is already closed.

panel.toggle(event?): void


Open the panel if it is closed, close it if it is open. If you catch it mid-close, toggle reverses and opens it again.

Parameters:

event (optional)
The triggering event. Used for keyboard detection.

panel.onBeforeOpen(handler, options?): void


Register a handler that runs just before the panel opens, which is where content loading goes. Return a promise from it and the open waits for that promise to settle. It runs before every open unless you pass once: true.

Parameters:

handler
(el: HTMLElement, signal: AbortSignal) => Promise<void> | void: Return a promise to delay opening.
options (optional)
{ once?: boolean }: If true, the handler is skipped after the first successful load (dataset.loaded === 'true').
JavaScript
panel.onBeforeOpen(async (el, signal) => {
	const html = await fetch('/api/content', { signal }).then(r => r.text());
	el.querySelector('.panel-wrapper').innerHTML = html;
}, { once: true });

You can pass a named function instead of an inline one. It keeps the call site tidy, and it lets you reuse the same loader across several panels.

JavaScript
async function loadContent(el, signal) {
	const html = await fetch('/api/content', { signal }).then(r => r.text());
	el.querySelector('.panel-wrapper').innerHTML = html;
}

panel.onBeforeOpen(loadContent, { once: true });

panel.setStatic(value: boolean): void


Force the panel into (or out of) its static state: plain expanded content instead of a collapsible disclosure. This overrides the static media query, so use it for a breakpoint the library cannot see, such as a container query or your own breakpoint system.

Switching never animates, and going back to collapsible lands the panel closed. See the static option.

panel.destroy(): void


Destroy it. It aborts any animation in progress, removes its event listeners (including the static media query watcher), resets the element to its closed state, and clears the element.panel reference so the element can be initialised again.

Instance properties

panel.isOpen: boolean


Read-only. true while the panel is open, or part-way through opening.

panel.isStatic: boolean


Read-only. true while the panel is plain expanded content rather than a disclosure.

panel.element: HTMLElement


Read-only. The [data-panel] element itself.

panel.config: PanelConfig


Read-only. The merged configuration. Precedence runs least specific to most: defaults first, then constructor options, then data attributes.

Static methods

Panel.init(selectorOrOptions?, options?): Panel[]


Find every panel matching the selector and initialise the lot in one call. It also connects implicit [data-panel-trigger] / [data-panel] pairs that sit next to each other.

Parameters:

selectorOrOptions (optional)
CSS selector string, or a config object (uses '[data-panel'] selector).
options (optional)
Config object, only used when the first argument is a selector string.

Returns:

An array of the Panel instances it created.

JavaScript
Panel.init();
Panel.init({ debug: true });
Panel.init('[data-panel]', { axis: 'vertical' });

Panel.defaults: PanelConfig


Static property. The default config handed to every new instance. Change it here to move the defaults for the whole page at once.

JavaScript
Panel.defaults.axis = 'vertical';
Panel.defaults.debug = true;

TypeScript types

JavaScript
import {
	Panel,
	type PanelConfig,
	type PanelBeforeOpenEventDetail,
	type PanelEventDetail,
	type AsyncOpenHandler,
} from 'panelset';

const panel = new Panel('#my-panel');

panel.element.addEventListener('panel:opened', e => {
	const event = e as CustomEvent<PanelEventDetail>;
	console.log(event.detail.trigger);
});

const config: PanelConfig = {
	axis: 'horizontal',
	transitions: true,
	autoFocus: 'first',
	returnFocus: true,
	persist: true,
};

const panel = new Panel('#my-panel', config);