Navigation

Sidebar

App navigation that collapses to icons on wide screens and opens as a Sheet on phones.

Class nameTypeDescription
sidebarplf:sidebarComponentThe navigation beside the page
drawerplf:drawerComponentThe layout root
sidebar-headerplf:sidebar-headerPartTop area that stays in place
sidebar-contentplf:sidebar-contentPartMiddle area that scrolls
sidebar-footerplf:sidebar-footerPartBottom area that stays in place
sidebar-groupplf:sidebar-groupPartA group of links
sidebar-group-labelplf:sidebar-group-labelPartA group's muted heading
sidebar-group-contentplf:sidebar-group-contentPartA collapsible group's content
sidebar-menuplf:sidebar-menuPartA list of links
sidebar-linkplf:sidebar-linkPartA link or button row
sidebar-iconplf:sidebar-iconPartA link's SVG icon; an icon class there doesn't need it
sidebar-labelplf:sidebar-labelPartA link's text; hidden in icon mode
sidebar-badgeplf:sidebar-badgePartA trailing count; hidden in icon mode
sidebar-chevronplf:sidebar-chevronPartA trailing icon, hidden in icon mode; in a collapsible group, your own in place of the drawn chevron
sidebar-submenuplf:sidebar-submenuPartA nested list with a start border
sidebar-sub-linkplf:sidebar-sub-linkPartA lighter link in a submenu
sidebar-controlplf:sidebar-controlPartHolds a dropdown in the header or footer
sidebar-identityplf:sidebar-identityPartA taller brand, workspace or account row
sidebar-identity-iconplf:sidebar-identity-iconPartThe identity's logo or avatar
sidebar-nameplf:sidebar-namePartThe identity's name
sidebar-descriptionplf:sidebar-descriptionPartA muted line under the name
sidebar-indicatorplf:sidebar-indicatorPartThe current-link line the script adds
sidebar-dialogplf:sidebar-dialogPartThe Sheet for phones
sidebar-mobile-contentplf:sidebar-mobile-contentPartThe Sheet's body, which takes the sidebar on phones
drawer-bodyplf:drawer-bodyPartThe row holding the sidebar and the page
drawer-contentplf:drawer-contentPartThe page beside the sidebar
drawer-endplf:drawer-endPlacementSidebar on the end side
drawer-stickyplf:drawer-stickyModifierThe page scrolls; the sidebar stays in view

Default

The dialog, named with aria-label, and every toggle need a name, all in the same root, or the script does not start. Leave the Sheet’s body empty: on phones the script moves the sidebar’s content into it, beside the close button. Each page marks its own link with aria-current="page", which this preview moves on click.

Workspace switcher

For an account with several workspaces, a Dropdown Menu in the header switches between them.

Compact

Icon mode hides the labels only visually, and each link then shows its label as a tooltip on hover and keyboard focus. The script opens the sidebar in the mode this browser saved.

Offcanvas

data-plf-collapsible="offcanvas" hides the sidebar on wide screens instead of narrowing it to icons; this one starts hidden, and its toggle shows it.

Scrollable

The menu scrolls when it is taller than the layout, which needs a height, or than the screen in a sticky layout.

Sticky

drawer-sticky lets the page scroll: the sidebar stays in view, one screen tall at most, and a sticky header in drawer-content stays at the top of the screen. The layout is at least one screen tall, so it takes no height. Page builders’ scroll effects work as on any page; the application shell uses it.

A bar fixed above the page, such as WordPress’s admin bar, sets --plf-sidebar-top to its height: the sidebar and a header whose top reads it stay below the bar.

HTML
<div class="drawer drawer-sticky" data-plf-sidebar>
  <div class="drawer-body">
    <aside class="sidebar" aria-label="Workspace sidebar"><!-- The sidebar --></aside>
    <div class="drawer-content">
      <header class="sticky border-b border-base-300 bg-base-100" style="top: var(--plf-sidebar-top, 0px)"><!-- The header --></header>
      <main><!-- The page --></main>
    </div>
  </div>
</div>
React
import { Sidebar, SidebarPage, SidebarPanel } from '@pelatform/react';

export function Example() {
  return (
    <Sidebar sticky>
      <SidebarPanel aria-label="Workspace sidebar">{/* The sidebar */}</SidebarPanel>
      <SidebarPage>
        <header className="sticky border-b border-base-300 bg-base-100" style={{ top: 'var(--plf-sidebar-top, 0px)' }}>{/* The header */}</header>
        <main>{/* The page */}</main>
      </SidebarPage>
    </Sidebar>
  );
}

End placement

Leave sheet-start off the dialog so the Sheet opens from the same side.

JavaScript

Sidebar needs JavaScript. The Full script (pelatform-ui.min.js) starts every component on page load, with no code of your own; with ESM imports, call init() yourself, as in Installation. For markup you add later, see Dynamic content.

<link rel="stylesheet" href="pelatform-ui.min.css">
<link rel="stylesheet" href="icons/icons.min.css">
<script src="pelatform-ui.min.js" defer></script>
<link rel="stylesheet" href="pelatform-ui.prefixed.min.css">
<link rel="stylesheet" href="icons/icons.prefixed.min.css">
<script src="pelatform-ui.min.js" defer></script>
Attribute Purpose
data-plf-sidebar Marks the drawer container, which holds the <aside> for wide screens inside its drawer-body and the mobile Sheet: a closed, named <dialog> that the script makes a Modal, which a tap outside closes. On narrow screens the Sheet’s empty element takes the aside’s content, and a close button before it sits beside the sidebar’s header; a body with content of its own keeps it
data-plf-sidebar-toggle One or more named button toggles, written with hidden; the script shows them and sets aria-controls and aria-expanded
data-plf-collapsed On the container: starts collapsed on wide screens; the script adds or removes it, and setCollapsed() changes it later
data-plf-collapsible On the container: what collapsed means on wide screens, icon (default) for the icons alone or offcanvas for no sidebar
data-plf-reveal-current On the container: scrolls the menu, never the page, so an out-of-view aria-current="page" link sits near the middle, on start and each time the Sheet opens, where that link also takes the focus
data-plf-indicator On the container: a line beside the current link that slides when it changes, also in the phone menu

Without JavaScript, the toggles stay hidden and the full navigation shows, above the content on narrow screens.

Methods

Method Behavior
PLF.Sidebar.getOrCreateInstance(element) Returns the instance, creating it for valid markup
PLF.Sidebar.getInstance(element) Returns the instance or null
instance.getState() Returns { collapsed, mobile, open }
instance.setCollapsed(boolean) Collapses or expands the sidebar for wide screens, also while on a phone; returns false when nothing changes or the event is canceled
instance.toggle() Collapses or expands the sidebar on wide screens, or opens or closes the Sheet on phones
instance.open(trigger), instance.close() Open or close the Sheet on phones; return false on wide screens
instance.destroy() Closes the Sheet and removes the enhancements; the collapsed state stays
Event When
plf:sidebar:before-change, plf:sidebar:change Before and after the sidebar collapses or expands; the first is cancelable

Each event’s detail:

Property Value
instance The Sidebar instance
collapsed true when the sidebar collapses, false when it expands
previousCollapsed Whether the sidebar was collapsed before
reason api or trigger
trigger The toggle button, or null from a method

The Sheet fires the Modal events.

Keyboard

Key Action
Enter, Space On a toggle: collapses or expands the sidebar, or opens the Sheet on phones
Control+B, Command+B With aria-keyshortcuts="Control+B Meta+B" on a toggle: as pressing it, outside text fields
Escape Closes the Sheet and returns focus to the toggle

React

Sidebar from @pelatform/react renders this layout with its drawer-body, its Sheet and its icon-mode tooltip: it keeps its collapsed state, or the application sets it with collapsed, and on a narrow screen the panel’s content opens in a Sheet. Each part is a component of its own; a collapsible group is a Collapsible, and a row that opens a Dropdown Menu is its trigger, each with the sidebar’s classes as its className.

Prop Values Default
collapsed true while the sidebar shows icons only on wide screens, which the application changes in onCollapsedChange; keeping it refuses the change Its own state
defaultCollapsed true starts collapsed when the application does not set collapsed false
onCollapsedChange (collapsed), called when a trigger collapses or expands the sidebar None
collapsible What collapsed means on wide screens: icon for the icons alone, or offcanvas for no sidebar icon
open true while the Sheet is open on a narrow screen, which the application changes in onOpenChange Its own state
onOpenChange (open, reason), called when a trigger opens or closes the Sheet, or it asks to close: trigger, keyboard (Escape) or backdrop; with no reason when a wide screen closes it None
side end puts the sidebar and its Sheet on the end side The start side
sticky true lets the page scroll while the sidebar stays in view false
indicator true adds the line beside the current link false
revealCurrent true scrolls an out-of-view current link to the menu’s middle at start and as the Sheet opens, where it takes the focus false
sheetLabel, closeLabel The Sheet’s name and its close button’s Navigation, Close navigation

The parts:

Part Element
SidebarPanel The aside with sidebar, whose content shows in the Sheet on a narrow screen
SidebarPage A div with drawer-content, the page beside the sidebar
SidebarTrigger A button that collapses or expands the sidebar, or opens the Sheet on a narrow screen, named Toggle navigation unless given another name; aria-keyshortcuts also presses it, and buttonClass() gives it a look
SidebarHeader, SidebarFooter A header with sidebar-header, a footer with sidebar-footer
SidebarContent A nav with sidebar-content, which holds the indicator
SidebarGroup A div with sidebar-group
SidebarGroupLabel A p with sidebar-group-label sidebar-label
SidebarMenu, SidebarSubmenu A ul with sidebar-menu or sidebar-submenu
SidebarLink A link with sidebar-link; aria-current="page" marks the current page
SidebarSubLink, SidebarIdentity A link with sidebar-link and sidebar-sub-link or sidebar-identity
SidebarLabel, SidebarBadge A span with sidebar-label or sidebar-badge, hidden in icon mode
SidebarIdentityIcon, SidebarName, SidebarDescription A span with sidebar-identity-icon, sidebar-name or sidebar-description

The other props are the element’s own, className and ref included. With a router, a link is your router’s own with the sidebar-link class, whose aria-current="page" moves the indicator; as its navigation loads no page, set open to false when the path changes, so the phone’s Sheet closes.

Variable Default
--plf-sidebar-width 16rem, at most the parent’s width
--plf-sidebar-compact-width 3rem
--plf-sidebar-mobile-width 18rem, at most the viewport width minus 16px
--plf-sidebar-bg, --plf-sidebar-color --plf-color-surface-raised and --plf-color-text
--plf-sidebar-border --plf-color-border-subtle
--plf-sidebar-padding --plf-space-2 (8px) around the header, menu and footer
--plf-sidebar-gap --plf-space-1 (4px) between links
--plf-sidebar-hover-bg --plf-color-surface-muted
--plf-sidebar-current-bg, --plf-sidebar-current-color --plf-color-primary-subtle and --plf-color-primary-text for the current link
--plf-sidebar-indicator-color, --plf-sidebar-indicator-width --plf-color-primary-border and 2px, with data-plf-indicator
--plf-sidebar-top 0; in a sticky layout, the height of a bar fixed above the page

Built with Pelatform UIv0.1.0

Components

Getting started

Foundations

Components

Actions

Data display

Navigation

Feedback

Data input

Layout

Advanced

Integrations

Blocks

Application

Authentication

Icons