Getting started

<ps-panel> is a custom element that wraps Panel. Everything works the same: events, async content, grouped accordions, persist, all of it. The only differences are how you register it and how you write attributes.

IIFE (no build step)

Include the bundled script. register() is called automatically with the default ps prefix. No extra setup needed.

HTML
<script src="panelset.js"></script>

<!-- <ps-panel> is ready immediately after the script loads-->
<ps-panel id="my-panel" panel-axis="vertical">
	<div class="panel-wrapper">...</div>
</ps-panel>

Module: import and done

Just import this path and all three elements are registered. Nothing to call.

JS
import 'panelset/register';
// <ps-panel>, <ps-panelset>, <ps-panelcontrol> are now registered

Module: explicit call

Call register() yourself when you need control over timing or the prefix.

JS
import { register } from 'panelset';
register(); // registers <ps-panel>, <ps-panelset>, <ps-panelcontrol>

Basic example

A show-more panel using <ps-panel> with plain attributes. The attribute names match the data attributes but without the data- prefix: data-panel-axis becomes panel-axis.

Additional content that was hidden. The panel animates to its natural height, exactly as with data-panel.

HTML
<button aria-controls="wc-panel-demo" aria-expanded="false">Show more</button>

<ps-panel id="wc-panel-demo">
	<div class="panel-wrapper">
		<p>Hidden content.</p>
	</div>
</ps-panel>

Panel connects the trigger via aria-controls automatically, so no click handler is needed.

It can even be simplified further: the aria-expanded attribute is optional, because Panel will add it on its own. The same goes for the panel-wrapper. Panel adds it. And if we add data-panel-trigger to the button, we can skip the id too (when a trigger and its panel sit next to each other in the markup, see implicit wiring). This is all optional, but it’s nice that the web component can handle it for you.

Additional content that was hidden. The panel animates to its natural height, exactly as with data-panel.

HTML
<button data-panel-trigger>Show more</button>

<ps-panel>
	<p>Hidden content.</p>
</ps-panel>

Trigger wiring

Panel auto-binds all [aria-controls ] triggers on init. If you need to reach the Panel instance from your own JavaScript, use closest('ps-panel') instead of closest('[data-panel]').

JS
// Accessing the Panel instance from custom JS:
document.addEventListener('click', event => {
	const el = event.target.closest('ps-panel');
	if (!el?.panel) return;
	el.panel.toggle(event);
});

Custom prefix

Pass a string to register() to use a custom element name prefix. The default is ps.

JS
import { register } from 'panelset';

register();         // <ps-panel>, <ps-panelset>, <ps-panelcontrol>
register('solar'); // <solar-panel>, <solar-panelset>, <solar-panelcontrol>

It is safe to call register() multiple times. It skips any name that is already defined.