
Modern CSS Grid Bento Dashboard
Published
17 hand-coded CSS dashboard layouts for SaaS, fintech, healthcare, e-commerce and internal-tool builders: bento grids, collapsible sidebar shells, KPI card grids, split-pane master-detail, sticky-header + sticky-column data grids, container-query widgets, dark-mode oklch() token systems and full-screen 100vh command centers. Engineered for INP under 100ms with zero client JavaScript on the initial render path, WCAG 2.2 AA out of the box, and a modern CSS surface (@container, :has(), @property, @starting-style). Scoped under .cdl-NN for no-collision pasting, prefers-reduced-motion guarded, framework-agnostic.
Related6 CSS Bento Grid Layouts30 CSS Sidebar Layouts22 CSS Headers

Published

<button aria-expanded> is the accessible way to build a disclosure control. Everything else is CSS.Published

Published

Published

Published

Published

Published

Published

Published

Published

Published

Published

Published

Published

Published

Published

Published
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)) — the auto-fit keyword collapses empty tracks so a 4-column layout on a 1440px canvas becomes 3 columns at 1024px and 2 columns at 640px without a single media query. Second, on any KPI card that needs to reshape itself between narrow (stacked label + number) and wide (label beside number with sparkline strip below): wrap the card in container-type: inline-size, then use @container (min-width: 320px) { .card__value { grid-column: 2 / span 1; ... } }. Container queries let the same card component reflow based on ITS OWN width — not the viewport — so it works correctly whether the sidebar is expanded (narrow card) or collapsed (wide card) without any JS. Third, for spanning-large tiles: grid-column: span 2; grid-row: span 2 on the hero KPI. Combined with grid-auto-rows: minmax(140px, auto) on the parent the layout stays visually balanced even when tile counts vary. This is exactly the recipe Vercel, Linear, Notion Analytics, and Superhuman ship in production — no CSS Grid framework, no JS grid library, no dependencies. See Demos 01, 03, 08 for the full worked recipes.<aside role="navigation" aria-label="Primary"> — never a bare <div>, because screen readers surface role="navigation" in the landmark rotor (VoiceOver, JAWS, NVDA) so keyboard-only users can jump straight there. Collapse toggling uses a real <button aria-expanded="true|false" aria-controls="nav-tree"> — aria-expanded is the WCAG-required attribute for state (2.2 SC 4.1.2, Name Role Value), and every screen reader announces the state change on click. For the collapsed-icon-only state, each nav item must ship an aria-label or a <span class="visually-hidden"> label so the icon alone doesn't become an unreadable target — WCAG 1.1.1 (Non-text Content). Focus-visible rings on every nav item (never :focus alone, which fires for mouse users too and creates outline noise); focus rings must be at least 2px thick with 3:1 contrast against the sidebar background (WCAG 2.4.13, October 2023 update). For multi-level nested nav (Demo 11): use <details><summary> as the collapsible group — free keyboard support, free ARIA (browsers ship the correct aria-expanded automatically), zero JS. This clears Section 508, EN 301 549, ADA Title III, and the Canadian Accessible Canada Act in one shot.position: sticky; top: 0; z-index: 2 on every <th>. Sticky first column alone is easy — position: sticky; left: 0; z-index: 1 on every first-column cell. The trap is the intersection cell (top-left corner): it needs BOTH sticky positions AND a higher z-index than either the header row or the first column, or it disappears behind them at the scroll intersection. The fix: .grid th:first-child { position: sticky; top: 0; left: 0; z-index: 3; }. The second trap is background paint: sticky cells need an opaque background (background: var(--surface)) or the underlying scrolled content bleeds through — a bug that only shows once you scroll to a section with a differently-coloured row. Third: on browsers before Chrome 125 / Safari 17, position: sticky on a <th> inside a table with border-collapse: collapse silently doesn't work — you need border-collapse: separate; border-spacing: 0 and border faux-drawing via box-shadow: inset 0 -1px 0 var(--edge). Demo 14 ships all three fixes. This pattern is the core of Airtable's grid view, Retool's Table component, Metabase's query results, Datadog's monitor list — anywhere a dev needs to render 500+ rows without the "infinite scroll library" tax.:root for light AND on :root[data-theme="dark"] for dark — oklch() is perceptually uniform, so you can shift lightness by fixed amounts (0.15 → 0.10 for hover) and get consistent contrast across every hue, unlike sRGB hex. (2) Use color-mix(in oklch, var(--surface) 92%, var(--ink)) for hover / pressed / disabled states — this generates hovered variants at build time instead of hand-tuning six shades per hue. (3) Set the theme attribute on <html> BEFORE any stylesheet loads via an inline <script> in <head> — reading localStorage.getItem('theme') or window.matchMedia('(prefers-color-scheme: dark)').matches and setting document.documentElement.dataset.theme. This blocks paint for <5ms and completely eliminates FOUC (flash of unstyled content) — a bug most dark-mode tutorials leave in because they set the theme after React hydrates. (4) Every animatable colour uses @property --token-name { syntax: '<color>'; ... } so CSS transitions interpolate through colour space instead of snap-cutting. See Demo 10 for the full token layer, including status colours (good / warn / bad), surface tiers, and elevation shadows.:has() + :checked state (pure CSS, no event listener); collapsible nav uses <details><summary> (native browser handling, not synthetic React state); CLS is 0 because every card uses grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)) which pre-reserves layout tracks (the fallback for a card that hasn't loaded is aspect-ratio: 3/2 — reserved space, no shift). The container-query recipe (Demo 08) is especially INP-friendly because reflow triggered by sidebar toggling stays inside the container's isolate — the browser doesn't re-layout the whole document. Compared to a React admin template with 8-12MB of client JS: this collection ships 0KB of runtime JS by default, which is what turns a "Poor CWV" page into a "Good CWV" page on Google Ads Quality Score (a 20-40% lower cost-per-click for the same ad placement) and moves the page above competitors in the SERP ranking.class to className, drop the JSX into any server or client component (no 'use client' directive needed for the 14 Pure CSS layouts because they have no interactivity that requires hydration). Vue 3 / Nuxt: accepts as-is, class attribute is native. Svelte / SvelteKit: accepts as-is, class is native. Astro: drop into any .astro component. Remix: any route module. Solid.js: rename class to class (yes, Solid uses class not className) and paste. Compared to premium admin templates: shadcn Admin, Radix Themes Dashboard, TailAdmin, AdminLTE, Materio each ships 200KB-1.5MB of framework CSS + JS you can't strip; the hand-coded pattern here totals 4-8KB gzipped per demo when you cherry-pick, and the entire 17-demo collection is under 60KB combined. The .cdl-NN numeric-prefix scoping means all 17 layouts coexist on the gallery page without a single class collision, and the same prefix guarantees you can drop any one demo into a codebase that already uses .dashboard, .shell, .sidebar, .panel, or .grid classes without renaming a single selector. MIT licensed.role="main" landmark + explicit ARIA labels because HIPAA-adjacent tools face WCAG 2.1 AA statutory requirements under HHS Section 508 refresh + ADA Title III. Mortgage / bank loans / insurance (CPM ~$30-80): Demo 09 (E-Commerce Merchant Control Panel) reshapes cleanly into loan-officer + insurance-broker CRMs — the merchant-order card layout maps to loan-application queue + underwriter-review card. Demo 11 (Multi-Level Nested Sidebar) is the correct pick for enterprise legal case-management (Clio, MyCase, Rocket Matter) where the nav tree spans firm → matter → task → document. SaaS pricing / control panels (CPM ~$15-25): Demo 10 (Dark-Mode Native CSS Variable Dashboard) is the reference implementation for Vercel / Linear / Notion / Superhuman-style product interfaces. Each of these VERY-HIGH-tier verticals rewards the accessibility + performance moat this collection ships, because enterprise buyers in regulated industries have accessibility + Core Web Vitals as procurement checklist items.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.