Absolute positioning
Handy for a megamenu.
Live demo
A closable PanelSet opens and closes as a whole. Position it and it becomes a megamenu: the tab buttons switch panels while the whole thing floats over the content below, instead of pushing it down. With closeOnTab, clicking the active tab closes it; the Close / Open / Toggle buttons drive it from anywhere.
Markup
<div class="megamenu-wrapper">
<div class="demo-controls">
<button aria-controls="megamenu-panel-1">Panel 1</button>
<button aria-controls="megamenu-panel-2">Panel 2</button>
<button aria-controls="megamenu-panel-3">Panel 3</button>
<button data-panelset-close="#megamenu">Close</button>
<button data-panelset-open="#megamenu">Open</button>
<button data-panelset-toggle="#megamenu">Toggle</button>
</div>
<hr class="no-margin">
<div id="megamenu" data-panelset data-closable data-close-on-tab data-panelset-align="end">
<!-- Panels here-->
</div>
</div>
Positioning and styling
The closable PanelSet is absolutely positioned. Becuase the 'top' is not defined, it just follows the hr in the DOM structure. The megamenu overlays the page instead of pushing the layout down when it opens. Similar to the Panel dropdown, scaled up to a tabbed megamenu.
.megamenu-wrapper {
position: relative;
width: max-content;
}
#megamenu {
position: absolute;
right: 0; /* right edges aligned with the controls */
z-index: 10;
width: 320px;
border-radius: 8px;
background: var(--demo-btn-bg);
box-shadow: 0 8px 20px var(--special-shadow-dark);
}
Closable mechanics
This set is data-closable with data-close-on-tab. Together they make the tab buttons double as open/close toggles: a tab opens the set when it is closed (silently switching to that panel first if needed), and clicking the active tab while open closes it.
Panel switching
The switching handler is the same as any other PanelSet. Passing the event to show() is optional, but lets you know what triggered the switch (via event.target or the ps:activationstart event).
document.addEventListener('click', event => {
const button = event.target.closest('button[aria-controls]');
if (!button) return;
const panelId = button.getAttribute('aria-controls');
const container = document.getElementById(panelId)?.closest('[data-panelset]');
container?.panelSet?.show(panelId, { event });
});
Open / close / toggle buttons
Buttons carrying data-panelset-open, data-panelset-close or data-panelset-toggle (with a selector value) drive the set programmatically:
document.addEventListener('click', event => {
const actions = ['close', 'open', 'toggle'];
for (const action of actions) {
const btn = event.target.closest(`[data-panelset-${action}]`);
if (btn) {
const selector = btn.getAttribute(`data-panelset-${action}`);
const container = document.querySelector(selector);
if (container?.panelSet) {
const withTransition = !btn.hasAttribute('data-no-transition');
container.panelSet[action]({ event, transition: withTransition });
}
return;
}
}
});