Components/Sidebar

Sidebar

The largest thing in the kit: sixteen components and 102 variants, from a 32-tall menu row up to five complete navigation shells.

Sidebar / SidebarMenuButton · Type × State × CollapsedLive in the browser · drawn to match the file
Type
State
Collapsed
Menu Item
216 × 32 in the fileradius.md · 8 padding · gap 856 variants
Seven types, one row

Every Type is the same 32-tall row with the same padding and gap; what changes is what sits at the two ends. Collapsible and Dropdown add a trailing glyph, Tree adds a leading chevron and a trailing plus, Badge a number, Checkbox swaps the icon for a box, and Big Icon is the one that changes the height.

Active is weight as well as colour

Hover and Active both fill with base.sidebar-accent, which on its own would make them indistinguishable. Active also moves the label to base.sidebar-accent-foreground and to 500 weight - the weight is what you actually read, and it matches the source's font-medium.

Collapsed is 32 square with a tooltip

At 32 the label is gone entirely rather than clipped, so the row is an icon in a square. The Hover and Active collapsed variants carry a tooltip layer, because a rail with no labels needs somewhere to put the name.

The rest of the kit

Twelve more containers around the row

The button is the piece you place most, but a sidebar is a stack of groups and each group has a label, an action, a sub-list and a disclosure glyph. These are drawn separately so a shell can be assembled without redrawing any of them.

Component
Sidebar / GroupLabelLive in the browser · drawn to match the file
Type
State
Text Size
Group Label
170 × 32 · 12 variants

Two of the containers are compositions rather than parts: SidebarMenuItem pairs a button with an optional sub-list, and SidebarGroup stacks a label over six buttons and has a Collapsed variant that drops to a 48-wide rail. Both are in the file so a shell can be dropped in whole rather than assembled row by row.

The three panels

Switching teams and switching accounts

Three standalone components with no axes: a trigger with its menu attached, that menu on its own, and the account dropdown that hangs off the footer. All three are base.background on a radius.xl corner with one drop shadow, which is what separates them from the sidebar behind.

Panel
NorthwindTeamsNorthwind⌘1Harborline⌘2Kestrel Co.⌘3Add team
316 × 248
The usage frame

Five shells from the same parts

1768 by 1180, holding five 256-wide navigation shells and one 48-wide rail. The same four groups and the same thirty items in each; what changes is whether the group labels fold, whether the items are indented under a rule, and whether there is a search field in the header.

Shell
NorthwindEnterprise
256 × 900, clipped at the frame

All five clip rather than scroll in the file, because a still frame cannot show a scrollbar. Here they scroll, which is what the content is actually doing: four groups and thirty items come to 1,088 tall inside a 900 frame, so the last group is always below the fold.

The whole thing

Sidebar, trigger and inset, wired together

The arrangement the source documents: a provider holding a sidebar beside an inset, with a trigger that folds it. side, variant and collapsible are the three props that decide what happens, and none of them is a variant in the file - they are all layout.

SidebarProvider · Sidebar · SidebarInsetToggle the trigger, or press the same control twice
side
collapsible
variant
Acme IncEnterprise
Platform
Workbench
Agents
Knowledge base
Settings
Workspaces
Design systems
Growth analytics
Field research
More
shadcnm@example.com
PlatformWorkbench
side left · collapsible icon · variant sidebar256cmd+b in the source

Three things the file has no way to record. collapsible=icon leaves the 48 rail the file draws; offcanvas takes the width to zero and the content reflows into it; none pins the sidebar open and greys the trigger out. variant=floating lifts the panel off the edge with a shadow and a corner, and inset does the same to the content instead.

Narrow screens and other directions

On a phone it is a Sheet

Below the mobile breakpoint the sidebar stops being a column beside the content and becomes an off-canvas panel over it, 18rem wide rather than 16. Nothing inside changes - the same header, the same groups, the same rows - only where it lives.

Mobile · the sidebar as an overlayTap the trigger
Workbench
Acme IncEnterprise
Platform
Workbench
Agents
Knowledge base
Settings
Workspaces
Design systems
Growth analytics
Field research
More
shadcnm@example.com
288 wide · SIDEBAR_WIDTH_MOBILE is 18rem against 16rem on desktop

Right to left

The source flips on the dir prop: the panel moves to the other edge, every row reverses, and the disclosure chevrons point the other way. The kit draws none of this, because it is all mirroring - but a designer needs to see what they are asking for, so here it is.

dir=rtlLive in the browser · drawn to match the file
Direction
Acme IncEnterprise
Platform
Workbench
Agents
Knowledge base
Settings
Workbench
panel on the left · rows reversed · chevrons mirrored

Worth saying plainly: mirroring is not a variant and should never become one. Fifty-six menu button variants would become a hundred and twelve for a change no designer makes by hand. Set dir on the container and let the layout do it, which is exactly what the source does.

There is one trap in doing it that way, and this page fell into it first time round. Under dir=rtl a plain flex row already lays its children out from the right, so reversing the row as well cancels the flip and the panel lands back on the left. The fix is to reverse nothing: dir handles order, logical properties like inset-inline-start and text-start handle placement, and the only thing left to flip by hand is the direction a chevron points.

In the file

Sixteen components, 102 variants

Read straight out of the Penpot file. The axes below are the property names you will see in the variant dropdown.

SidebarMenuButtonType × State × CollapsedSimple · Collapsible · Dropdown · Tree · Badge · Checkbox · Big Icon × Default · Hover · Active · Focused × False · True56
SidebarGroupLabelType × State × Text SizeDefault · Collapsible · Action × Default · Hover × xs · sm - 170 × 3212
CollapseIconType × ActiveHorizontal · Vertical · Plus Minus · Up Down × No · Yes - 16 × 168
SidebarMenuSubItemStateDefault · Hover · Active · Focused - 216 × 28, no icon4
SidebarMenuSubTypeDefault · Indent · Border - 237 × 1563
SidebarGroupActionStateDefault · Hover · Focused - 20 × 20 on radius.sm3
Header ButtonStateDefault · Hover · Focused - 28 × 28, the trigger that folds the rail3
PopoverMenuItemStateDefault · Hover · Focused - 196 × 40 with a shortcut3
SidebarMenuItemSubmenuTrue · False - a button with or without a sub-list2
SidebarGroupCollapsedTrue · False - 248 × 248 or a 48-wide rail2
MediaAssetTypeIcon · Avatar - 32 × 32 on radius.md or radius.full2
PopoverTriggerStateDefault · Hover - 141 × 362
InboxItemStateDefault · Hover - 323 × 120, a two-line preview row2
Popover · PopoverMenu · AccountDropdownnone316 × 248, 316 × 212 and 224 × 188 - three standalone panels3

Using the Sidebar

Because Type changes what sits at the ends of the row and Collapsed changes whether there is a row at all. Seven types times four states times two widths is fifty-six, and the alternative - hidden layers for the trailing glyphs - does not work here, because Tree adds a leading chevron and Big Icon changes the height from 32 to 48. Both of those move their neighbours, which only a variant can do.

Both fill with base.sidebar-accent, so the fill alone tells you nothing. Active also moves the label to base.sidebar-accent-foreground and to 500 weight. The weight is the part you actually read at a glance, and it is what the source does too - data-[active=true] carries font-medium, not a different colour.

It is removed, not clipped. A collapsed row is a 32 square with the icon centred, and the Hover and Active collapsed variants carry a tooltip layer instead - a rail with no labels has to put the name somewhere, and that somewhere is beside the icon on hover.

Because there are four conventions and teams disagree about them. Horizontal points right when shut and down when open, Vertical points down then up, Plus Minus swaps the sign, and Up Down is a single chevron pair that never changes. Drawing them as one component with a Type axis means a file can pick one and be consistent everywhere.

The same four groups and thirty items arranged five ways: flat labels, collapsible labels, items indented under a rule, both at once, and an application nav with a footer and a collapsed 48 rail beside it. All five clip at 900 in the file because a still frame cannot show a scrollbar - the content is 1,088 tall, so the last group is always below the fold.

Nowhere in the file, and they should not be. All three are layout: side flips which edge the panel sits on, collapsible decides whether folding leaves a 48 rail, closes to nothing, or is disabled, and variant lifts either the panel or the content off the edge with a shadow. The full-layout section on this page lets you set all three and watch what changes.

The sidebar stops being a column and becomes an off-canvas panel over the content, at 18rem rather than 16. Nothing inside it changes. That is worth knowing before you design a rail that only works at 48 wide, because on a phone there is no rail - there is a trigger and a scrim.

In the source, yes, on the dir prop: the panel moves to the other edge, the rows reverse, and the chevrons mirror. None of that is drawn in the file and none of it should be - mirroring fifty-six menu button variants would make a hundred and twelve for something no designer sets by hand. The last section on this page shows the mirrored layout so you can see what you are asking for.

Reversing twice. Under dir=rtl a plain flex row already lays its children out from the right, so adding flex-row-reverse on top cancels the flip and the panel ends up back on the left - which is what this page did on its first attempt. Reverse nothing: let dir handle order, use logical properties (inset-inline-start, text-start, ms/ps) for placement, and flip only the chevrons by hand, because a glyph pointing right is a direction rather than a position.

Navigation · 102 variants