Nested sidebars for a mail app
Collapsible nested sidebars.
Preview
Built with
The components this screen renders, through their own templates. Changing one of them, or a token they read, changes this screen.
Design system gaps
What the design system lacks to render the original as it is. The screen fills each gap with native HTML on semantic tokens until a component or a token covers it.
- Collapsing the sidebar (off canvas or to an icon rail) has no pattern without script yet.
- The sidebar navigation (groups, items, sub-items, current item) is native HTML on semantic tokens: there is no Navigation component yet.
- Menus whose trigger is a whole row (team, version or user switcher) use the Dropdown next to the row: its trigger is a Button with a text label, it cannot hold an avatar or two lines.
- The folder rail names its icons with visually hidden labels: there is no Tooltip to show them on hover and focus.
- The mail list (sender, date, subject, a two-line teaser) is native links on semantic tokens: there is no list or mail item component.
Changes from the original
- Both sidebars are always shown: the outer sidebar does not collapse to its icon rail (that needs script, and so does the trigger button), and the sidebar trigger and its separator are dropped. On wide screens the folder rail shows icons only and the mail list sits beside it; on narrow ones the rail shows its labels and both stack above the content (the original hides the mail list there).
- Choosing a folder does not reshuffle the mail list or change the list title (that needs script): the folders are links, Inbox is the current one.
- The user row sits at the foot of the mail list instead of the foot of the rail, where its menu does not fit: the Dropdown has no icon-only trigger.
- The "Unreads" switch filters nothing (the original does not either).
- Rebuilt as static HTML with the design system's component templates; every color, type style, radius, border and spacing comes from its tokens.
- The original visual design (Tailwind classes, the Geist font) is not reused.
- Lucide and Tabler icons are remapped to Material Symbols; brand logos (Apple, Google, GitHub, Meta) are dropped, the buttons keep their text.
- Placeholder images are drawn with semantic tokens.
- No script: behaviour that needs JavaScript (collapsing the sidebar, toasts, drag and drop, client-side tables) is dropped or simplified, and each screen says so.
Code
The HTML the screen renders, from apps/docs/screens/shadcn-ui/sidebar-09.screen.mjs, with the stylesheets of @quantum-ds/tokens, the reference implementation (packages/components/src/) and apps/docs/screens/screens.css.
HTML
<div class="scr-viewport">
<div class="scr-screen" style="--scr-sidebar: 350px">
<div class="scr-shell" data-variant="sidebar" data-side="left">
<div class="scr-nested">
<nav class="scr-sidebar" aria-label="Folders">
<div class="scr-sidebar__header">
<a class="scr-identity scr-home" href="#">
<span class="scr-tile-mark">
<span
class="ds-icon"
data-size="small"
data-color="current"
aria-hidden="true"
>keyboard_command_key</span>
</span>
<span class="scr-identity__text">
<span class="scr-identity__title">Acme Inc</span>
<span class="scr-identity__subtitle">Enterprise</span>
</span>
</a>
</div>
<div class="scr-sidebar__content">
<div class="scr-nav-group">
<ul class="scr-nav">
<li class="scr-nav__item">
<a class="scr-nav__link" href="#" aria-current="page">
<span
class="ds-icon"
data-size="small"
data-color="current"
aria-hidden="true"
>inbox</span>
<span class="scr-nav__label">Inbox</span>
</a>
</li>
<li class="scr-nav__item">
<a class="scr-nav__link" href="#">
<span
class="ds-icon"
data-size="small"
data-color="current"
aria-hidden="true"
>description</span>
<span class="scr-nav__label">Drafts</span>
</a>
</li>
<li class="scr-nav__item">
<a class="scr-nav__link" href="#">
<span
class="ds-icon"
data-size="small"
data-color="current"
aria-hidden="true"
>send</span>
<span class="scr-nav__label">Sent</span>
</a>
</li>
<li class="scr-nav__item">
<a class="scr-nav__link" href="#">
<span
class="ds-icon"
data-size="small"
data-color="current"
aria-hidden="true"
>archive</span>
<span class="scr-nav__label">Junk</span>
</a>
</li>
<li class="scr-nav__item">
<a class="scr-nav__link" href="#">
<span
class="ds-icon"
data-size="small"
data-color="current"
aria-hidden="true"
>delete</span>
<span class="scr-nav__label">Trash</span>
</a>
</li>
</ul>
</div>
</div>
</nav>
<aside class="scr-sidebar" aria-label="Inbox">
<div class="scr-sidebar__header">
<div class="scr-row" data-justify="between">
<h2 class="scr-title" data-size="small">Inbox</h2>
<div class="ds-switch" data-size="small">
<input
type="checkbox"
role="switch"
class="ds-switch__control"
data-part="control"
id="sidebar-09-unreads"
>
<label
class="ds-switch__label"
data-part="label"
for="sidebar-09-unreads"
>Unreads</label>
</div>
</div>
<form role="search" action="#">
<div class="ds-search-field" data-size="small">
<label
class="ds-search-field__label"
data-part="label"
for="sidebar-09-search"
>Search</label>
<div class="ds-search-field__field" data-part="field">
<span
class="ds-search-field__icon"
data-part="icon"
aria-hidden="true"
>search</span>
<input
type="search"
class="ds-search-field__control"
data-part="control"
id="sidebar-09-search"
name="q"
placeholder="Type to search..."
>
</div>
</div>
</form>
</div>
<div class="scr-sidebar__content">
<ul class="scr-mail-list">
<li>
<a class="scr-mail" href="#">
<span class="scr-mail__top">
<span>William Smith</span>
<span class="scr-mail__date">09:34 AM</span>
</span>
<span class="scr-mail__subject">Meeting Tomorrow</span>
<span class="scr-mail__teaser">Hi team, just a reminder about our meeting tomorrow at 10 AM.
Please come prepared with your project updates.</span>
</a>
</li>
<li>
<a class="scr-mail" href="#">
<span class="scr-mail__top">
<span>Alice Smith</span>
<span class="scr-mail__date">Yesterday</span>
</span>
<span class="scr-mail__subject">Re: Project Update</span>
<span class="scr-mail__teaser">Thanks for the update. The progress looks great so far.
Let's schedule a call to discuss the next steps.</span>
</a>
</li>
<li>
<a class="scr-mail" href="#">
<span class="scr-mail__top">
<span>Bob Johnson</span>
<span class="scr-mail__date">2 days ago</span>
</span>
<span class="scr-mail__subject">Weekend Plans</span>
<span class="scr-mail__teaser">Hey everyone! I'm thinking of organizing a team outing this weekend.
Would you be interested in a hiking trip or a beach day?</span>
</a>
</li>
<li>
<a class="scr-mail" href="#">
<span class="scr-mail__top">
<span>Emily Davis</span>
<span class="scr-mail__date">2 days ago</span>
</span>
<span class="scr-mail__subject">Re: Question about Budget</span>
<span class="scr-mail__teaser">I've reviewed the budget numbers you sent over.
Can we set up a quick call to discuss some potential adjustments?</span>
</a>
</li>
<li>
<a class="scr-mail" href="#">
<span class="scr-mail__top">
<span>Michael Wilson</span>
<span class="scr-mail__date">1 week ago</span>
</span>
<span class="scr-mail__subject">Important Announcement</span>
<span class="scr-mail__teaser">Please join us for an all-hands meeting this Friday at 3 PM.
We have some exciting news to share about the company's future.</span>
</a>
</li>
<li>
<a class="scr-mail" href="#">
<span class="scr-mail__top">
<span>Sarah Brown</span>
<span class="scr-mail__date">1 week ago</span>
</span>
<span class="scr-mail__subject">Re: Feedback on Proposal</span>
<span class="scr-mail__teaser">Thank you for sending over the proposal. I've reviewed it and have some thoughts.
Could we schedule a meeting to discuss my feedback in detail?</span>
</a>
</li>
<li>
<a class="scr-mail" href="#">
<span class="scr-mail__top">
<span>David Lee</span>
<span class="scr-mail__date">1 week ago</span>
</span>
<span class="scr-mail__subject">New Project Idea</span>
<span class="scr-mail__teaser">I've been brainstorming and came up with an interesting project concept.
Do you have time this week to discuss its potential impact and feasibility?</span>
</a>
</li>
<li>
<a class="scr-mail" href="#">
<span class="scr-mail__top">
<span>Olivia Wilson</span>
<span class="scr-mail__date">1 week ago</span>
</span>
<span class="scr-mail__subject">Vacation Plans</span>
<span class="scr-mail__teaser">Just a heads up that I'll be taking a two-week vacation next month.
I'll make sure all my projects are up to date before I leave.</span>
</a>
</li>
<li>
<a class="scr-mail" href="#">
<span class="scr-mail__top">
<span>James Martin</span>
<span class="scr-mail__date">1 week ago</span>
</span>
<span class="scr-mail__subject">Re: Conference Registration</span>
<span class="scr-mail__teaser">I've completed the registration for the upcoming tech conference.
Let me know if you need any additional information from my end.</span>
</a>
</li>
<li>
<a class="scr-mail" href="#">
<span class="scr-mail__top">
<span>Sophia White</span>
<span class="scr-mail__date">1 week ago</span>
</span>
<span class="scr-mail__subject">Team Dinner</span>
<span class="scr-mail__teaser">To celebrate our recent project success, I'd like to organize a team dinner.
Are you available next Friday evening? Please let me know your preferences.</span>
</a>
</li>
</ul>
</div>
<div class="scr-sidebar__footer">
<div class="scr-identity">
<span
class="ds-avatar"
data-size="small"
data-shape="square"
aria-hidden="true"
>
<span
class="ds-avatar__initials"
data-part="initials"
aria-hidden="true"
>S</span>
</span>
<span class="scr-identity__text">
<span class="scr-identity__title">shadcn</span>
<span class="scr-identity__subtitle">m@example.com</span>
</span>
<div class="ds-dropdown">
<button
type="button"
class="ds-button ds-dropdown__trigger"
data-emphasis="ghost"
data-intent="neutral"
data-size="xsmall"
data-part="trigger"
id="sidebar-09-user-trigger"
popovertarget="sidebar-09-user"
>
<span
class="ds-button__label"
data-part="label"
>Account</span>
<span
class="ds-button__icon"
data-part="icon"
data-position="end"
aria-hidden="true"
>expand_more</span>
</button>
<div
class="ds-dropdown__menu"
data-part="menu"
id="sidebar-09-user"
popover
aria-labelledby="sidebar-09-user-trigger"
>
<ul class="ds-dropdown__group" data-part="group">
<li>
<button
type="button"
class="ds-dropdown__item"
data-part="item"
data-intent="neutral"
popovertarget="sidebar-09-user"
popovertargetaction="hide"
>
<span
class="ds-dropdown__item-icon"
data-part="item-icon"
aria-hidden="true"
>auto_awesome</span>
<span
class="ds-dropdown__item-label"
data-part="item-label"
>Upgrade to Pro</span>
</button>
</li>
</ul>
<hr
class="ds-dropdown__separator"
data-part="separator"
>
<ul class="ds-dropdown__group" data-part="group">
<li>
<button
type="button"
class="ds-dropdown__item"
data-part="item"
data-intent="neutral"
popovertarget="sidebar-09-user"
popovertargetaction="hide"
>
<span
class="ds-dropdown__item-icon"
data-part="item-icon"
aria-hidden="true"
>verified</span>
<span
class="ds-dropdown__item-label"
data-part="item-label"
>Account</span>
</button>
</li>
<li>
<button
type="button"
class="ds-dropdown__item"
data-part="item"
data-intent="neutral"
popovertarget="sidebar-09-user"
popovertargetaction="hide"
>
<span
class="ds-dropdown__item-icon"
data-part="item-icon"
aria-hidden="true"
>credit_card</span>
<span
class="ds-dropdown__item-label"
data-part="item-label"
>Billing</span>
</button>
</li>
<li>
<button
type="button"
class="ds-dropdown__item"
data-part="item"
data-intent="neutral"
popovertarget="sidebar-09-user"
popovertargetaction="hide"
>
<span
class="ds-dropdown__item-icon"
data-part="item-icon"
aria-hidden="true"
>notifications</span>
<span
class="ds-dropdown__item-label"
data-part="item-label"
>Notifications</span>
</button>
</li>
</ul>
<hr
class="ds-dropdown__separator"
data-part="separator"
>
<ul class="ds-dropdown__group" data-part="group">
<li>
<button
type="button"
class="ds-dropdown__item"
data-part="item"
data-intent="neutral"
popovertarget="sidebar-09-user"
popovertargetaction="hide"
>
<span
class="ds-dropdown__item-icon"
data-part="item-icon"
aria-hidden="true"
>logout</span>
<span
class="ds-dropdown__item-label"
data-part="item-label"
>Log out</span>
</button>
</li>
</ul>
</div>
</div>
</div>
</div>
</aside>
</div>
<div class="scr-main">
<header class="scr-header" data-sticky>
<nav
class="ds-breadcrumb"
aria-label="Breadcrumb"
data-size="small"
>
<ol class="ds-breadcrumb__list" data-part="list">
<li class="ds-breadcrumb__item" data-part="item">
<a
class="ds-breadcrumb__link"
data-part="link"
href="#"
>All Inboxes</a>
<span
class="ds-breadcrumb__separator"
data-part="separator"
aria-hidden="true"
>chevron_right</span>
</li>
<li class="ds-breadcrumb__item" data-part="item">
<span
class="ds-breadcrumb__link"
data-part="link"
aria-current="page"
>Inbox</span>
</li>
</ol>
</nav>
</header>
<main class="scr-content">
<h1 class="scr-sr">Inbox</h1>
<div class="scr-stack" aria-hidden="true">
<div class="scr-tile" data-size="row"></div>
<div class="scr-tile" data-size="row"></div>
<div class="scr-tile" data-size="row"></div>
<div class="scr-tile" data-size="row"></div>
<div class="scr-tile" data-size="row"></div>
<div class="scr-tile" data-size="row"></div>
<div class="scr-tile" data-size="row"></div>
<div class="scr-tile" data-size="row"></div>
<div class="scr-tile" data-size="row"></div>
<div class="scr-tile" data-size="row"></div>
<div class="scr-tile" data-size="row"></div>
<div class="scr-tile" data-size="row"></div>
<div class="scr-tile" data-size="row"></div>
<div class="scr-tile" data-size="row"></div>
<div class="scr-tile" data-size="row"></div>
<div class="scr-tile" data-size="row"></div>
<div class="scr-tile" data-size="row"></div>
<div class="scr-tile" data-size="row"></div>
<div class="scr-tile" data-size="row"></div>
<div class="scr-tile" data-size="row"></div>
<div class="scr-tile" data-size="row"></div>
<div class="scr-tile" data-size="row"></div>
<div class="scr-tile" data-size="row"></div>
<div class="scr-tile" data-size="row"></div>
</div>
</main>
</div>
</div>
</div>
</div>