Navigation

v0.0.4
Application pages

Dashboard

Figures across the top and panels in a grid that reflows without queries.

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-grid with --auto-grid-min: 12rem holds 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, then grid-cols(3)@container(--4xl); the wide panel takes two of them with grid-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-flat or card-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 has tabindex="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 with aria-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.