Side Panel
A panel that slides in from the right edge, beside the page rather than in front of it. The page stays live while it is open.
When to Use
Variants
Heading, subtitle and a body
One shape. The head carries the title, an optional line under it, and the close button; the body scrolls on its own. Open it from the button below: any element with data-ws-side-panel-open toggles the panel it names.
<?= ws_side_panel($bodyHtml, [
'id' => 'wsComments',
'title' => 'Leave a comment',
'subtitle' => 'Everyone working on this workshop reads what you post here.',
]) ?>
<?= ws_button('Comments', ['icon' => 'mode_comment', 'attrs' => [
'data-ws-side-panel-open' => 'wsComments',
'aria-controls' => 'wsComments',
'aria-expanded' => 'false',
]]) ?>Branded
'variant' => 'branded' puts the head on the red band the branded Modal wears: white title, the subtitle and close stepped back, and an optional icon in a pill. The comments panel wears it.
<?= ws_side_panel($bodyHtml, [
'id' => 'wsComments',
'title' => 'Leave a comment',
'variant' => 'branded',
'icon' => 'mode_comment',
]) ?>Real-World Usage
Each phase's comments (app/includes/comments-panel.php): the Comments button sits beside the save on Strategize, Plan, Facilitate and Synthesize's red bars, and the panel it opens holds the Leave a comment form and the workshop's thread. The panel loads its thread when it opens, from the ws-side-panel-open event.
Options
| Option | Type | Purpose |
|---|---|---|
$body | string | Panel body HTML, already escaped by the caller |
id | string | Required. Triggers point at it, and the heading and subtitle take {id}-title and {id}-subtitle |
title | string | The heading, in Fraunces |
subtitle | string | One line under the heading; a script can reword it through #{id}-subtitle |
variant | string | default or branded, the red header band |
icon | string | A Material Symbols name, in a pill beside the heading |
class | string | Additional classes |
attrs | array | Additional attributes |
Scripting: wsSidePanelOpen(id, trigger), wsSidePanelClose(id) and wsSidePanelToggle(id, trigger). The panel fires ws-side-panel-open and ws-side-panel-close on itself.
Accessibility
- A non-modal dialog:
role="dialog"witharia-modal="false", named by its heading. Nothing behind it goes inert and focus is not trapped. - Opening moves focus to the panel; closing hands it back to the control that opened it, but only if focus was still in the panel.
- Escape closes it while focus is in the panel or on its toggle. A modal open on top keeps Escape for itself.
- Every toggle's
aria-expandedfollows the panel. On the App Bar an open panel's button turns white with a red icon, and the panel starts under the bar, so that button stays in reach to close it. If the bar scrolls with its page, the panel's top follows it up to--ws-side-panel-top. - Once it has slid out it takes
[hidden], so it leaves the tab order and the accessibility tree. Under reduced motion the slide is instant.
Tokens
| Token | Use |
|---|---|
--ws-side-panel-top / --ws-side-panel-bottom | Where it starts and stops (default 0). The app shell keeps its 60px header and its footer clear. Below 600px the panel takes the whole screen |
--ws-side-panel-width | 360px by default, never wider than the viewport |
--duration-enter + --ease-spring | Sliding in |
--duration-exit + --ease-in | Sliding out |
--z-overlay minus 100 | One step under overlays, so a modal, a toast, a header menu or the launcher opened while it is out lands on top of it |
--shadow-lg, --bg-surface, --gray-200 | Lift, surface and the left edge |
CSS Classes
| Class | Purpose |
|---|---|
.ws-side-panel | The panel; .is-open while it is in view |
.ws-side-panel__head | Heading block and close button |
.ws-side-panel__title / __subtitle | The heading and the line under it |
.ws-side-panel__close | The close button |
.ws-side-panel__body | The scrolling body |
Files
| File | Purpose |
|---|---|
includes/components/helpers.php | ws_side_panel() helper function |
includes/components/side-panel.php | Template |
includes/components/components.css | Styles (.ws-side-panel rules) |
includes/components/components.js | wsSidePanelOpen/Close/Toggle(), the delegated toggles and Escape |