Slide-in Panel
A trigger opens the panel from the chosen edge. Change the side, then add a backdrop with Modal or block dismissal with Static. Panel content is yours: header, body, and footer are all optional.
Sheets
A full-width surface that slides from the top or bottom edge. It fits its content up to --panel-height, and a tall sheet is capped so it never covers the sticky header.
<button class="nds-btn nds-primary nds-lg" data-panel-toggle="details-sheet">
<span class="nds-label">Open Sheet</span>
</button>
<aside id="details-sheet" class="nds-panel" data-panel-side="bottom"
aria-label="Details sheet" hidden>
<div class="nds-panel-header">
<span class="nds-featured-icon nds-circle">
<i class="hgi hgi-stroke hgi-stars"></i>
</span>
<div class="nds-panel-text">
<span class="nds-panel-title">Details</span>
<p class="nds-panel-description">A closer look at the selected item.</p>
</div>
<button class="nds-btn nds-subtle nds-icon-only" type="button" data-panel-close aria-label="Close sheet">
<i class="nds-icon nds-hgi-cancel-01" aria-hidden="true"></i>
</button>
</div>
<div class="nds-panel-body">
<p>A bottom sheet is a good fit for mobile actions or a compact form.</p>
</div>
</aside>
Built-in Features
Activates when a .nds-panel is on the page. Toggle and close buttons wire up from data attributes with no init call.
Slides in from the inline start or end, the physical left or right, or as a full-width top or bottom sheet.
Add data-panel-modal for a dimming backdrop and scroll lock; leave it off and the page behind stays fully interactive.
Focus moves into the panel on open and returns to the trigger on close. Escape and outside clicks dismiss it unless data-panel-static is set.
Opening a panel closes any other first and waits for it to finish sliding out, so two panels never overlap.
Side panels sit below the sticky header and track it as the topbar scrolls in and out; tall sheets cap their height to match.
Logical start and end sides flip with text direction in RTL and LTR; physical left and right stay on the same edge.
Open, close, toggle, and query any panel through the JS API, and react to the opened and closed events it dispatches.
Usage Guidelines
Best Practices
- Use a panel for secondary content the user reveals on demand: settings, filters, a details view, or a form that supports the main task without replacing it
- Keep the default non-modal (no
data-panel-modal) when users benefit from seeing the panel affect live content, such as filter or accessibility controls - Add
data-panel-modalwhen the panel demands a decision and the page behind it should be inert, for example a checkout step or a destructive confirmation with detail - Do not use a panel for a short blocking confirmation with no extra content. Use a Modal instead
- Do not use a panel for primary site navigation. Use the Drawer or Sidemenu
- Prefer logical
startandendsides so the panel follows reading direction. Reserveleftandrightfor cases that must anchor to a physical edge regardless of language - Choose a
bottomsheet for mobile-first actions and a side panel for desktop-oriented settings or filters - Add
data-panel-staticto a panel holding an unsaved form so a stray Escape or outside click cannot discard the user's work - Header, body, and footer are all optional. Drop content straight into
.nds-panel-body, or swap it for an Scroll More wrapper for long scrolling content with fade edges - Keep the header's title inside
.nds-panel-text, the same title-plus-description pairing Cards use. Add a.nds-panel-descriptionbeside the title when the panel needs a subtitle, and drop the wrapper only for a bare title: it still fills the row on its own, so a leading icon and the close button stay where they are - Set
--panel-content-width: 100%on a sheet whose content should span the full width (a media row, a wide table) instead of capping to the page max-width - Ship the panel with the
hiddenattribute so it never flashes before the script loads
Data Attributes
| Attribute | Description |
|---|---|
data-panel-side | Set on .nds-panel to pick the edge. Values: end (default) or start (logical, flip with direction); left or right (physical); top or bottom (full-width sheet) |
data-panel-toggle | Set on any button, anywhere on the page, with the target panel's id as its value. Clicking it opens or closes that panel |
data-panel-close | Set on any element inside the panel to make it a close control |
data-panel-modal | Present on .nds-panel to add a dimming backdrop, a scroll lock, and a focus trap. Omit for a non-blocking disclosure |
data-panel-static | Present on .nds-panel to disable both Escape and outside-click dismissal. A close button and a swap to another panel still work |
CSS Custom Properties
| Property | Default | Description |
|---|---|---|
--panel-width | min(420px, 100vw) | Width of an inline side panel (start, end, left, right) |
--panel-height | 60svh | Maximum height of a top or bottom sheet. The sheet fits its content up to this, and is capped so it never covers the header |
--panel-content-width | --nds-content-MaxWidth | Max width of a top or bottom sheet's content, centered within the full-bleed sheet and aligned to the page gutter on narrower screens. Set to 100% for full-width content |
--panel-top | sticky header bottom | Block-start offset. Set it to override the automatic header tracking with a fixed value |
--panel-padding | --spacing-lg | Padding of the header, body, and footer |
--panel-gap | 0 | Gap between the panel's header, body and footer |
--panel-radius | 0, --radius-lg for sheets | Corner radius of the panel surface. Top and bottom sheets round the two corners facing the page at the modal radius |
--panel-z | 999 | Stacking order of the panel |
JavaScript API
The NDS.Panel API opens, closes, and toggles panels programmatically. Every method accepts a panel element or its id string. Toggle and close buttons work from markup alone, so most pages never touch this API.