A dashboard puts a few figures across the top and panels under them. The frame is an app shell on a tray; inside the main sheet, two grids do the work, and neither needs a breakpoint of the screen.
Dashboard
<div class="shell bg-surface-tray fg-text-body text-sm"> <a class="skip" href="#dash-main">Skip to content</a> <aside class="shell-sidebar gap-md p-sm"> <a class="navbar-brand h(40) px-xs" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M12 3a9 9 0 1 0 0 18a9 9 0 0 0 0-18M12 3a9 9 0 0 0 0 18" /> </svg>Atlas</a> <nav class="nav" aria-label="Workspace"> <a class="nav-item" href="#" aria-current="page"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M5 12 12 5l7 7M7 10v9h10v-9" /> </svg>Overview</a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M4 4h7v7H4zM13 4h7v7h-7zM4 13h7v7H4zM13 13h7v7h-7z" /> </svg>Projects <span class="nav-end">12</span> </a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0-18 0M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18" /> </svg>Domains</a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M4 19h16M7 16V9M12 16V5M17 16v-4" /> </svg>Analytics</a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M5 7a4 4 0 1 0 8 0a4 4 0 0 0-8 0M3 21v-2a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v2M16 3.1a4 4 0 0 1 0 7.8M21 21v-2a4 4 0 0 0-3-3.85" /> </svg>Team</a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M14 6a2 2 0 1 0 4 0a2 2 0 0 0-4 0M4 6h10M18 6h2M6 12a2 2 0 1 0 4 0a2 2 0 0 0-4 0M4 12h2M10 12h10M15 18a2 2 0 1 0 4 0a2 2 0 0 0-4 0M4 18h11M19 18h1" /> </svg>Settings</a> </nav> <button type="button" class="btn btn-quiet justify-start mt-auto"> <span class="avatar avatar-xs"> <img class="avatar-image" src="/demo/portrait-1.svg" alt> </span>Ada Lovelace</button> </aside> <div class="shell-main flex flex-col p(8) pxs(0)@container(--3xl)"> <main class="sheet grow(1) container-inline" id="dash-main" tabindex="-1"> <header class="navbar" style="--navbar-color: var(--color-surface-raised)"> <button type="button" class="btn btn-quiet btn-square btn-sm shell-toggle" commandfor="dash-nav" command="show-modal" aria-label="Open navigation"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M4 8h16M4 16h16" /> </svg> </button> <h1 class="heading heading-sm">Overview</h1> <div class="navbar-end"> <select class="select select-raised select-sm" aria-label="Period"> <option class="select-option">Last 24 hours</option> <option class="select-option">Last 7 days</option> <option class="select-option">Last 30 days</option> </select> </div> </header> <div class="flex flex-col gap-md p-lg"> <div class="auto-grid auto-grid-fit" style="--auto-grid-min: 12rem"> <section class="sheet sheet-flat p-md"> <div class="stat"> <p class="stat-label">Requests</p> <div class="stat-row"> <p class="stat-value">1.28M</p> <p class="stat-delta stat-delta-up"> <span class="sr-only">Up</span>12.4%</p> </div> </div> </section> <section class="sheet sheet-flat p-md"> <div class="stat"> <p class="stat-label">Error rate</p> <div class="stat-row"> <p class="stat-value">0.02%</p> <p class="stat-delta stat-delta-down"> <span class="sr-only">Down</span>0.4%</p> </div> </div> </section> <section class="sheet sheet-flat p-md"> <div class="stat"> <p class="stat-label">Median latency</p> <div class="stat-row"> <p class="stat-value">48 ms</p> <p class="stat-delta stat-delta-down"> <span class="sr-only">Down</span>3 ms</p> </div> </div> </section> <section class="sheet sheet-flat p-md"> <div class="stat"> <p class="stat-label">Deployments</p> <div class="stat-row"> <p class="stat-value">37</p> </div> </div> </section> </div> <div class="grid gap-md grid-cols(3)@container(--4xl)"> <section class="card card-flat grid-col-span(2)@container(--4xl)" aria-labelledby="dash-projects"> <header class="card-header"> <h2 class="card-title" id="dash-projects">Projects</h2> <p class="card-description">Requests in the last 24 hours.</p> <a class="btn btn-sm card-action" href="#">View all</a> </header> <div class="scroll-area scroll-area-inline" tabindex="0" role="region" aria-labelledby="dash-projects"> <table class="table"> <thead> <tr class="table-row"> <th class="table-heading" scope="col">Project</th> <th class="table-heading" scope="col">Status</th> <th class="table-heading" scope="col">Region</th> <th class="table-heading table-numeric" scope="col">Requests</th> </tr> </thead> <tbody> <tr class="table-row"> <td class="table-cell table-primary">Atlas</td> <td class="table-cell"> <span class="badge badge-success badge-dot">Ready</span> </td> <td class="table-cell">Tokyo</td> <td class="table-cell table-numeric">1,284,019</td> </tr> <tr class="table-row"> <td class="table-cell table-primary">Borealis</td> <td class="table-cell"> <span class="badge badge-info badge-dot">Building</span> </td> <td class="table-cell">Frankfurt</td> <td class="table-cell table-numeric">402,771</td> </tr> <tr class="table-row"> <td class="table-cell table-primary">Cinder</td> <td class="table-cell"> <span class="badge badge-success badge-dot">Ready</span> </td> <td class="table-cell">Virginia</td> <td class="table-cell table-numeric">96,204</td> </tr> <tr class="table-row"> <td class="table-cell table-primary">Drift</td> <td class="table-cell"> <span class="badge badge-danger badge-dot">Failed</span> </td> <td class="table-cell">Sydney</td> <td class="table-cell table-numeric">12,480</td> </tr> <tr class="table-row"> <td class="table-cell table-primary">Ember</td> <td class="table-cell"> <span class="badge badge-success badge-dot">Ready</span> </td> <td class="table-cell">São Paulo</td> <td class="table-cell table-numeric">8,112</td> </tr> </tbody> </table> </div> </section> <section class="card card-flat" aria-labelledby="dash-usage"> <header class="card-header"> <h2 class="card-title" id="dash-usage">Usage</h2> <p class="card-description">Resets on 1 December.</p> </header> <div class="card-body flex flex-col gap-md"> <div class="flex flex-col gap-xs"> <div class="flex items-baseline justify-between gap-sm"> <span class="fg-text-strong" id="u-bw">Bandwidth</span> <span class="fg-text-muted">74 of 100 GB</span> </div> <meter class="meter" min="0" max="100" low="60" high="90" optimum="0" value="74" aria-labelledby="u-bw">74 of 100 GB</meter> </div> <div class="flex flex-col gap-xs"> <div class="flex items-baseline justify-between gap-sm"> <span class="fg-text-strong" id="u-bm">Build minutes</span> <span class="fg-text-muted">212 of 400</span> </div> <meter class="meter" min="0" max="100" low="60" high="90" optimum="0" value="53" aria-labelledby="u-bm">212 of 400</meter> </div> <div class="flex flex-col gap-xs"> <div class="flex items-baseline justify-between gap-sm"> <span class="fg-text-strong" id="u-st">Seats</span> <span class="fg-text-muted">4 of 5</span> </div> <meter class="meter" min="0" max="100" low="60" high="90" optimum="0" value="80" aria-labelledby="u-st">4 of 5</meter> </div> </div> </section> </div> </div> </main> </div> <dialog class="dialog dialog-drawer dialog-drawer-start" id="dash-nav" closedby="any" aria-label="Navigation"> <div class="dialog-body flex flex-col gap-md"> <a class="navbar-brand h(40) px-xs" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M12 3a9 9 0 1 0 0 18a9 9 0 0 0 0-18M12 3a9 9 0 0 0 0 18" /> </svg>Atlas</a> <nav class="nav" aria-label="Workspace, in the drawer"> <a class="nav-item" href="#" aria-current="page"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M5 12 12 5l7 7M7 10v9h10v-9" /> </svg>Overview</a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M4 4h7v7H4zM13 4h7v7h-7zM4 13h7v7H4zM13 13h7v7h-7z" /> </svg>Projects <span class="nav-end">12</span> </a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0-18 0M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18" /> </svg>Domains</a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M4 19h16M7 16V9M12 16V5M17 16v-4" /> </svg>Analytics</a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M5 7a4 4 0 1 0 8 0a4 4 0 0 0-8 0M3 21v-2a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v2M16 3.1a4 4 0 0 1 0 7.8M21 21v-2a4 4 0 0 0-3-3.85" /> </svg>Team</a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M14 6a2 2 0 1 0 4 0a2 2 0 0 0-4 0M4 6h10M18 6h2M6 12a2 2 0 1 0 4 0a2 2 0 0 0-4 0M4 12h2M10 12h10M15 18a2 2 0 1 0 4 0a2 2 0 0 0-4 0M4 18h11M19 18h1" /> </svg>Settings</a> </nav> </div> <button type="button" class="btn btn-quiet btn-square btn-sm dialog-close" commandfor="dash-nav" command="close" aria-label="Close navigation"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M6 6l12 12M18 6 6 18" /> </svg> </button> </dialog></div>Choose Tablet: the figures reflow from four across to two and the panels stack. At Phone the sidebar moves into a drawer.
#How it is built
- The figures are an auto grid.
auto-gridwith--auto-grid-min: 12remholds as many tiles as fit at 12rem or wider: four across a wide sheet, two on a tablet, one or two on a phone. The grid counts the columns itself. - The panels are a three-column grid inside a container. The main sheet is
container-inline. The grid is one column until the sheet reaches 56rem, thengrid-cols(3)@container(--4xl); the wide panel takes two of them withgrid-col-span(2)@container(--4xl). When the sidebar leaves, the sheet gets wider and the panels may go back to three columns: that is the point of measuring the container and not the screen. - Each tile is a surface from the library. A figure is a stat on a flat sheet; a panel is a card. On a sheet, a tile is
sheet-flatorcard-flat: one contour and no shadow, since a shadow on a raised surface would stack two elevations. - A wide table scrolls in its panel. The table stands in a scroll area with
scroll-area-inline, which keeps a narrow panel from widening the page and fades the edge where columns continue. The region hastabindex="0"and a name, so the keyboard can scroll it.
#Density
One gap, gap-md, between every tile and panel keeps the page one grid. Resist a second gap for "groups": if two panels belong together, make them one panel.
#Accessibility
- Each panel is a
<section>named by its title witharia-labelledby, so the panels can be reached as regions. - A figure's change says its direction in words for assistive technology; see stat.
- A meter carries its value as text inside the element and a visible label beside it.
#Related
- Auto gridAs many equal columns as fit, counted by the grid itself.
- BentoTiles of a few sizes fitted into one box, in columns that follow its room.
- StatOne figure, what it measures and how it moved.
- CardA raised sheet whose parts follow the room the card is given.
- SurfaceTrays, sheets and wells: the material ladder every component is built on.
- TableRows of data on hairlines, with sortable headings and aligned figures.
- Scroll areaA scrolling region whose edges fade where content continues.
- MeterA measurement within a known range.
- NavbarThe bar at the top of a page, which takes its material once content scrolls under it.
- NavA vertical list of destinations for a sidebar.
- DialogA native modal on an overlay sheet, opened and closed without script.
- Skip linkThe first link of a page, shown while it has focus, that jumps past the navigation.