01. Tailwind SaaS Dashboard Sidebar with Native Dark Mode Switch (opens in a new tab)
var(--color-tsl01-*), so one scoped rule re-points the tokens and the whole shell follows without a single conditional class.30 Tailwind CSS sidebar layouts for SaaS dashboard shells, admin consoles, documentation trees, and webmail two-pane inboxes — spanning fixed and sticky rails, collapse-to-icon and off-canvas drawers, dual-panel and three-pane workspaces, nested <details> file trees, and floating glassmorphism panels. Scoped under .tsl-NN for no-collision pasting, prefers-reduced-motion guarded, framework-agnostic.
Related30 CSS Sidebar Layouts16 CSS Two-Column Layouts17 CSS Dashboard Layouts14 Tailwind CSS Wave Section Dividers
Premium template pickPartner: Cruip
Affiliate linkBuilding the whole admin dashboard, not just this layout?
You just browsed 30 Tailwind sidebar layouts. Mosaic by Cruip is a complete Tailwind CSS admin dashboard template, coded in HTML, React, Next.js, Vue and Laravel, with a Figma version too. It costs $69.
Mosaic by Cruip. We may earn a commission, at no extra cost to you.
var(--color-tsl01-*), so one scoped rule re-points the tokens and the whole shell follows without a single conditional class.has-checked: — the collapsed state is declared on each element that changes, instead of in a distant block of descendant selectors.:has(#id:target) selectors into eight arbitrary variants that sit on the links they light.<nav>, two personalities: under 768px an iOS-style bottom tab bar with safe-area padding, at and above it the same markup stands up into a left sidebar. No duplicate nav trees, no resize listeners — the breakpoint prefix does all of it.grid-template-columns: subgrid. Every row borrows the same four tracks from the list, so no width is ever hard-coded.has-checked: reads it from any depth, and the panel slides on a GPU-composited transform. The hamburger morphs into an X from the same signal, using nth-child arbitrary variants.position:fixed plus a magic margin. Each pane owns its overflow, so nothing overlaps and the whole thing nests inside any container.popover="auto" ships Esc-to-close, light dismissal, focus return and top-layer rendering; v4 contributes real variants for the hard part — starting: for the entry animation and an open: variant for the resting state.line-clamp-2, which replaces the four-declaration -webkit-box incantation with one utility.minmax(0,1fr) on the middle track — the answer to the most-asked grid question on the internet, and one that reads more clearly as a utility than as CSS.<details>/<summary> — keyboard-operable, screen-reader-announced and crawlable with zero script. v4's open: variant styles the expanded state, and accent-color brands every checkbox in one utility.backdrop-blur + backdrop-saturate, and finished with the gradient hairline that makes glass read as glass instead of grey plastic. The hairline is the one thing utilities cannot say — and the demo is honest about it.mt-auto in a flex column. The middle nav scrolls when it outgrows the rail, with mask-gradient fades hinting at the overflow, and the demo's real lesson is one easily-forgotten utility: min-h-0.--w variable that a data-state attribute swaps; six lines of JavaScript move a string between localStorage and that attribute, restored before first paint so returning users never see the wrong-width flash.focus-within ring-lighting the entire field when the input takes focus.:target identifies the section, and one indicator element transitions between stops computed from a single row-height variable.<details>, rotating chevrons, indent guides drawn as logical borders, and progressive padding from one --indent variable. Keyboard-operable out of the box because disclosure is native.resize-x plus overflow-auto and a min/max fence, and the browser runs the entire interaction. Tailwind ships the resize utility, so the whole mechanism is three classes.for toggles it, and Tailwind's has-checked: variant reads that state from an ancestor — has-checked:w-16 shrinks the rail, has-checked:opacity-0 hides the labels. No click handler, no state library. The rule that trips people up: has-checked: compiles to :has(:checked), which only matches inside the element's own subtree, so the checkbox must sit in the layout root where the styled nodes can see it — not buried inside a card. Pair the width change with transition-[width] so the fold eases instead of snapping, and keep the checkbox off-screen with sr-only rather than hidden, since a fully hidden input can't take focus for keyboard users.localStorage and drives every dimension from a single custom property. The rail's width is --w, applied with an arbitrary value like w-[var(--w)], and a data-state attribute on the root switches --w between the expanded and collapsed sizes. The toggle writes the new state back to storage. Because all geometry flows from one variable, padding, label opacity and icon centring key off the same attribute instead of a dozen hardcoded widths. The common bug is a flash of the wrong width: if you read localStorage after hydration, the first paint shows the default rail, then it jumps. Fix it by setting data-state in a small blocking inline script in the <head>, before the body renders, so the very first paint already matches the stored preference.h-screen, the rail is a fixed-width column, and the main pane gets flex-1 overflow-y-auto. The rail never scrolls with the page because the whole shell is pinned to the viewport height and only the content column owns the overflow. Two things break this. First, forgetting min-h-0 on the scrolling child — flex items default to min-height: auto, which refuses to shrink below their content, so the pane grows the page instead of scrolling inside it. Second, putting overflow on the wrong element. Keep the height cap on the root, let the rail size naturally, and scope overflow-y-auto to the content column only. If the rail also carries a long menu, give it its own overflow-y-auto so the two panes scroll independently.sticky top-0, and it fails for two predictable reasons. A position: sticky element only travels within its parent's box, so if the parent is no taller than the sidebar there's no room to move and nothing appears to stick — the sidebar's column needs to be the short one beside a tall article that supplies the height. The second killer is overflow: hidden or overflow: auto on any ancestor up to the scroll root: it silently creates a scroll container that clips sticky positioning. Walk every wrapper and remove stray overflow. You also need a real offset like top-0, because sticky with no threshold never engages. Demo 07 also caps the rail with max-h-screen plus its own overflow-y-auto, so a long table of contents scrolls inside the sticky pane rather than overflowing past the viewport.aria-label to every control and mark the decorative glyph with aria-hidden="true". The hover tooltips are a visual nicety, not an accessibility feature — keyboard and screen-reader users never fire hover, so the aria-label is what actually announces each destination. Keep targets at least 44px (demo 14 pins them there) so they stay tappable. Mark the active page with aria-current="page", never colour alone. If the collapse is a real button, give it aria-expanded reflecting the open state and aria-controls pointing at the rail. And never strip the focus ring in the collapsed state — a Tab user needs to see which icon is focused when there's no text beside it, and focus-visible: keeps it from showing on mouse clicks.md it's a fixed bottom bar — fixed bottom-0 inset-x-0 flex with items spread evenly; at md and up those classes flip to a vertical column pinned left. A single <nav> means one source of truth for the links and no duplicated ARIA to drift out of sync. Two details matter on phones: add pb-[env(safe-area-inset-bottom)] so the bar clears the iOS home indicator, and give the main content matching bottom padding so the fixed bar never covers the last row. Labels drop to icon-plus-caption at the bottom size. Don't try to animate the layout switch — it's a hard breakpoint swap, and transitioning between a fixed bottom bar and a flex column just produces jank with no payoff.resize-x plus overflow-auto and a min-w/max-w clamp — the browser draws the handle and does the width maths, with no pointer listeners or drag state. What it does not do is change what's inside as the width changes. That's demo 29's job: an @container query makes the nav respond to its own width, so labels hide and icons centre once the rail drops below a threshold, independent of the viewport. Combine them — resize-x for the drag, a container query for the adaptive contents — and the rail both resizes and reflows. The gotcha with resize: it only shows a handle when overflow is not visible, and it's mouse-only, so treat it as an enhancement, never your mobile story.md. The off-canvas overlay drawers (demos 10, 19) are modal: they trap the page behind a scrim, so don't use them for primary navigation a user needs while reading — a push-content drawer (demo 18) or a persistent rail keeps context visible. Reserve the frosted floating showpieces (demos 16, 30) for marketing shells; heavy backdrop-blur plus backdrop-saturate is a genuine paint cost over long scrolling lists and on low-end devices. And skip the pure-CSS :target tree (demo 23) when a link must survive a refresh or deep-link — :target writes to the URL hash and will hijack the back button in ways users don't expect.15 hand-coded CSS aspect-ratio demos for video embeds, product galleries, IAB ad slots, native dialogs, and CLS-safe placeholders: 16:9 iframe YouTube embed with click-to-load facade + up-next rail, 21:9 full-screen hero video with min-height/max-height:100svh guardrails + Ken Burns drift, 1:1 Instagram-style square grid with 2×2 feature tile, 4:3 magazine card image cover, 9:16 vertical stories rail (TikTok/Reels/Shorts pattern) with scroll-snap + segment bars, 4:5 apparel product image gallery with radio-driven state + 1:1 thumbnails, 1:1 zoom thumbnail carousel with pointer-tracked --zx/--zy magnifier, prevent-layout-shift placeholder with live PerformanceObserver CLS meter (before/after side-by-side lab), dynamic content fallback with three policies (bend/strict/auto) via :has() toggle, IAB ad banner slots (728×90 leaderboard, 300×250 medium rectangle, 300×600 half-page, 320×50 mobile) with skeletons + container-query mobile swap, responsive modal dialog sized min(92vw, 88svh×16/9, 1080px) with @starting-style animation, responsive OpenStreetMap iframe wrapper with 16:9 → 1:1 container-query narrow swap, media query orientation live HUD + resize:both container-ratio playground, object-fit logo cloud with contain/cover/fill switcher via :has(), and side-by-side padding-top hack (height:0 + padding-top:56.25%) → modern aspect-ratio migration comparison with live ratio picker. 11 truly Pure CSS + 4 with a tiny optional vanilla JS snippet (facade swap, pointer magnifier, CLS meter, native dialog). Every demo is scoped under a unique .car-NN prefix so it drops into any project without CSS collisions, ships prefers-reduced-motion guards, and is framework-agnostic (works as-is in React, Vue, Svelte, Astro, Next.js, Remix, or plain HTML).
6 production CSS bento grid layouts with 12 hand-coded designs — Apple-style product showcase, SaaS feature value-prop matrix, analytics dashboard overview, creative portfolio, e-commerce category hub, and link-in-bio social hub. Each topic ships 2 sub-variants side-by-side so visitors see both a keynote aesthetic and a paper-doc variant at once. Container queries, CSS Grid, zero dependencies, copy-paste ready.
20 hand-coded CSS blog and editorial layouts for magazine homepages, news sites, personal archives, newsletter back-issues, recipe and podcast blogs, developer tutorials, and long-form journalism. Covers a magazine homepage with hero plus editor-picks rail, a news homepage with breaking-news ticker, blog archives with sticky year separators, Substack-style issue-numbered archives, recipe card grids with prep-time badges, podcast episode lists with waveforms, long-form articles with scroll-driven reading progress, drop caps and floated pull quotes via first-letter, Medium-style 65ch centred reader layouts, dev tutorials with a sticky code panel beside prose, interview transcripts with alternating speakers, case-study pages with stat counters, video blogs with an episode rail, full-bleed photo essays, news articles with sticky related-stories sidebars, documentation pages with prev/next chapter nav, a standalone blog post card, a scroll-snap category filter bar, an inline newsletter callout that breaks out of the prose column, and a horizontal featured-post rail. 12 are pure CSS with zero JavaScript. Every layout is scoped under a .bl-NN prefix for no-collision pasting, guards prefers-reduced-motion, and ports unchanged to React, Vue, Svelte, Astro, Next.js and Tailwind.