PanelControl
An external controller for a PanelSet.
What it does
A PanelSet switches panels, but it does not automatically listen to the clicks on your tabs. On the PanelSet example pages that is all done with JavaScript, an extra script on each page. If you just read the docs of PanelSet, you might think you have to write that code yourself.
PanelControl to the rescue: assign it to the element that holds your triggers and it activates the right panel on click, adds keyboard navigation, and reflects state back onto the controls.
It finds its PanelSet through the panels the triggers point at, so the control can live anywhere in the DOM. It does not need to sit next to the PanelSet. One PanelControl drives one PanelSet.
Setup
PanelControl ships inside the panelset package, so there is nothing extra to install.
Installing PanelControl
npm install panelset
Using PanelControl
Installing PanelControl
Download the ZIP from the releases page, unzip, and place the files somewhere your HTML can reach.
Using PanelControl
Installing PanelControl
No download needed. Files are served directly from jsDelivr.
https://cdn.jsdelivr.net/npm/panelset@latest/dist/
Using PanelControl
With the script-tag build, window.PanelControl is available and the custom elements are already registered. See the Web Component page to learn more.
Markup
Put data-panelcontrol on the element holding your triggers. Each trigger points at a panel with aria-controls. Add role="tablist" (with role="tab" on the buttons) to switch on keyboard (arrow) navigation.
Key Features
- This is our most important feature ever!
Pricing Plans
- Starter Plan: Whenever you don’t want to pay a lot.
- Professional Plan: Ideal for managers who like to spend money!
Support Options
- If you send us an email, we will probably ignore it.
- We don’t even have a community forum.
- Opening an issue on GitHub is your next best option. Or even better: PR’s! You do the work!
<div class="tabs" role="tablist" data-panelcontrol>
<button role="tab" aria-controls="markup-panel-1" aria-selected="true">Features</button>
<button role="tab" aria-controls="markup-panel-2">Pricing</button>
<button role="tab" aria-controls="markup-panel-3">Support</button>
</div>
<div class="tab-content" data-panelset>
<div class="panel-wrapper">
<div class="active" id="markup-panel-1" role="tabpanel">…</div>
<div id="markup-panel-2" role="tabpanel" hidden>…</div>
<div id="markup-panel-3" role="tabpanel" hidden>…</div>
</div>
</div>
Initializing
Initialise PanelSet and PanelControl. Order does not matter (PanelControl resolves its PanelSet lazily).
import { PanelSet, PanelControl } from 'panelset';
PanelSet.init();
PanelControl.init(); // every [data-panelcontrol]
PanelControl.init('#my-tabs'); // or a specific control
PanelSet is required. PanelControl drives a PanelSet. It does not replace it, and it holds no panel-switching logic of its own. With no PanelSet initialised, clicks do nothing (in debug mode PanelControl logs why). For plain tabs with no animation, keep PanelSet and turn transitions off: PanelSet.init({ transitions: false }).
Layout patterns
The control’s role decides its keyboard model (and how much ARIA you take on).
- Horizontal tablist
role="tablist"withrole="tab"children. Left / Right arrows,Home/End, roving tabindex. The default, best-supported pattern.- Vertical tablist
- The same, plus
aria-orientation="vertical": arrows become Up / Down; everything else is identical. CSS lays it out as a sidebar. Covers most "sidebar that switches panels" needs, with no extra ARIA.
See Activation, Closable, and Vertical display for worked examples.
Scope
PanelControl manages controls and reflects state: activation, keyboard nav, roving tabindex, selected state (aria-selected on tabs, aria-current otherwise) / disabled. It also exposes setTabState(id, 'disabled' | 'enabled') so external code can lock or unlock a tab; PanelControl just applies it.
Validation, Previous / Next flow, step locking, and persistence are not part of PanelControl. Those are up to your own code, which calls setTabState when a step should lock. The direction is one way: your code calls PanelControl, which calls PanelSet, never the reverse.
Next: every option in Configuration, and the method list in the API reference.