CSS Dashboards: 16 Templates and How to Lay One Out

Plenty of internal admin panels carry a full component framework just to get a sidebar and a few cards onto the page. Plain CSS handles that job fine now that container queries are Baseline widely available, so each card can react to the width of its own grid cell.

Below are 16 CSS dashboard templates you can try and copy, followed by a guide to laying one out.

By Bogdan Sandu · Updated October 28, 2026

Analytics and admin dashboards

Four complete dashboard shells inside a fixed 560px frame where only the main area scrolls. Each one is a container, so the sidebar collapses to an icon rail and then to a top bar based on the width of the frame, not the viewport.

Analytics overview

  • grid-template-areas
  • container queries
  • CSS bar chart

Overview

  • Visitors48,210+12.4%
  • Sessions71,904+8.1%
  • Bounce rate38.2%-2.3 pts
  • Avg. session3m 12s-0.4%
Sessions this week
  1. 10.4kMon
  2. 12.6kTue
  3. 11.7kWed
  4. 15.3kThu
  5. 10.9kFri
  6. 6.1kSat
  7. 4.9kSun
Traffic sources
  • Organic46%
  • Direct28%
  • Referral16%
  • Social10%
Top pages
PageViewsAvg. timeBounce
/pricing12,8402m 41s31%
/blog/grid-guide9,5124m 06s44%
/features7,2331m 58s36%
/signup5,9041m 12s22%

The classic layout: KPI cards, a weekly bar chart, a share-of-traffic donut and a top pages table. The bars are an ordered list whose heights come from a custom property, so every value is real text, and the donut is a hard-stop conic-gradient with the percentages in the legend next to it.

View code
.da-an {
  container: da-an / inline-size;
  width: 100%;
  color: #1b2130;
}
.da-an__app {
  display: grid;
  grid-template-columns: 200px minmax(0, 1fr);
  grid-template-rows: auto minmax(0, 1fr);
  grid-template-areas: "side top" "side main";
  height: 560px;
  overflow: hidden;
  border: 1px solid #dfe3ec;
  border-radius: 16px;
  background: #f5f7fb;
  box-shadow: 0 18px 40px rgba(20, 28, 48, .08);
  font-size: 14px;
  line-height: 1.4;
}
.da-an__side {
  grid-area: side;
  display: flex;
  flex-direction: column;
  gap: 22px;
  padding: 18px 12px;
  border-right: 1px solid #e4e7ef;
  background: #fff;
}
.da-an__brand {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  padding: 0 8px;
  font-size: 17px;
  font-weight: 700;
}
.da-an__logo {
  flex: none;
  width: 26px;
  height: 26px;
  border-radius: 8px;
  background: #2f5bea;
  box-shadow: inset -10px -10px 0 #e8962e;
}
.da-an__nav {
  display: grid;
  gap: 4px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.da-an__nav a {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 40px;
  padding: 0 10px;
  border-radius: 10px;
  color: #4a5368;
  font-weight: 500;
  text-decoration: none;
}
.da-an__nav svg {
  flex: none;
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.da-an__nav a:hover {
  background: #f0f3fa;
  color: #1b2130;
}
.da-an__nav a[aria-current="page"] {
  background: #e8eefe;
  color: #1f43c4;
}
.da-an__nav a:focus-visible,
.da-an__range:focus-visible {
  outline: 3px solid #2f5bea;
  outline-offset: 2px;
}
.da-an__main:focus-visible,
.da-an__scroll:focus-visible {
  outline: 3px solid #2f5bea;
  outline-offset: -3px;
}
.da-an__top {
  grid-area: top;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 22px;
  border-bottom: 1px solid #e4e7ef;
  background: #fff;
}
.da-an__title {
  margin: 0;
  font-family: inherit;
  font-size: 20px;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -.01em;
  color: #1b2130;
}
.da-an__range {
  min-height: 36px;
  padding: 0 14px;
  border: 1px solid #cfd5e2;
  border-radius: 9px;
  background: #fff;
  color: #1b2130;
  font: inherit;
  cursor: pointer;
}
.da-an__main {
  grid-area: main;
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  align-content: start;
  gap: 16px;
  padding: 20px 22px;
  overflow: auto;
  overscroll-behavior: contain;
}
.da-an__kpis {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: 12px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.da-an__kpi,
.da-an__card {
  min-width: 0;
  padding: 14px 16px;
  border: 1px solid #e4e7ef;
  border-radius: 14px;
  background: #fff;
}
.da-an__kpi {
  display: grid;
  gap: 4px;
}
.da-an__kpi-label {
  color: #5b6475;
  font-size: 13px;
}
.da-an__kpi strong {
  font-size: 23px;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.01em;
}
.da-an__delta {
  justify-self: start;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 8px;
  border-radius: 99px;
  font-size: 12px;
  font-weight: 600;
}
.da-an__delta::before {
  content: "";
  width: 8px;
  height: 7px;
  background: currentColor;
  clip-path: polygon(50% 0, 100% 100%, 0 100%);
}
.da-an__delta--up,
.da-an__delta--good {
  background: #e3f5ea;
  color: #0f6e3c;
}
.da-an__delta--good::before,
.da-an__delta--down::before {
  rotate: 180deg;
}
.da-an__delta--down {
  background: #fde8e7;
  color: #b42318;
}
.da-an__card--chart {
  grid-column: span 4;
}
.da-an__card--src {
  grid-column: span 2;
}
.da-an__card--table {
  grid-column: 1 / -1;
  padding: 0;
}
.da-an__h {
  margin: 0 0 14px;
  font-family: inherit;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: 0;
  color: #1b2130;
}
.da-an__bars {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  align-items: end;
  gap: 8px;
  height: 190px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.da-an__bars li {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: center;
  gap: 6px;
  height: 100%;
}
.da-an__bar {
  width: 100%;
  max-width: 34px;
  height: calc(var(--da-v) * .72);
  border-radius: 6px 6px 2px 2px;
  background: #2f5bea;
}
.da-an__bars li:nth-child(4) .da-an__bar {
  background: #1a3699;
}
.da-an__val {
  color: #5b6475;
  font-size: 11.5px;
  font-variant-numeric: tabular-nums;
}
.da-an__day {
  color: #4a5368;
  font-size: 12px;
}
.da-an__donut {
  position: relative;
  display: grid;
  place-items: center;
  width: min(132px, 100%);
  aspect-ratio: 1;
  margin: 0 auto 14px;
  border-radius: 50%;
  background: conic-gradient(#2f5bea 0 46%, #e8962e 0 74%, #138a72 0 90%, #9aa5bd 0);
}
.da-an__donut::before {
  content: "";
  position: absolute;
  inset: 22%;
  border-radius: 50%;
  background: #fff;
}
.da-an__donut span {
  position: relative;
  font-weight: 700;
}
.da-an__legend {
  display: grid;
  gap: 6px;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 13px;
}
.da-an__legend li {
  display: flex;
  align-items: center;
  gap: 8px;
}
.da-an__legend i {
  width: 10px;
  height: 10px;
  border-radius: 3px;
  background: var(--da-c);
}
.da-an__legend b {
  margin-left: auto;
  font-variant-numeric: tabular-nums;
}
.da-an__scroll {
  overflow-x: auto;
  border-radius: 14px;
}
.da-an__table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13.5px;
  font-variant-numeric: tabular-nums;
}
.da-an__table caption {
  padding: 14px 16px 6px;
  font-size: 15px;
  font-weight: 600;
  text-align: left;
}
.da-an__table th,
.da-an__table td {
  padding: 10px 16px;
  border-top: 1px solid #edf0f5;
  text-align: right;
  white-space: nowrap;
}
.da-an__table thead th {
  border-top: 0;
  color: #5b6475;
  font-size: 12px;
  font-weight: 600;
}
.da-an__table th:first-child {
  text-align: left;
}
.da-an__table tbody th {
  font-weight: 500;
}
@container da-an (max-width: 760px) {
  .da-an__app {
    grid-template-columns: 68px minmax(0, 1fr);
  }
  .da-an__side {
    align-items: center;
    padding: 18px 10px;
  }
  .da-an__brand {
    padding: 0;
  }
  .da-an__nav a {
    justify-content: center;
    width: 44px;
    min-height: 44px;
    padding: 0;
  }
  .da-an__label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}
@container da-an (max-width: 600px) {
  .da-an__card--chart,
  .da-an__card--src {
    grid-column: 1 / -1;
  }
  .da-an__card--src {
    display: grid;
    grid-template-columns: 110px minmax(0, 1fr);
    align-items: center;
    gap: 0 16px;
  }
  .da-an__card--src .da-an__h {
    grid-column: 1 / -1;
  }
  .da-an__donut {
    margin: 0;
  }
}
@container da-an (max-width: 480px) {
  .da-an__app {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto auto minmax(0, 1fr);
    grid-template-areas: "side" "top" "main";
  }
  .da-an__side {
    flex-direction: row;
    gap: 8px;
    padding: 8px 10px 8px 14px;
    border-right: 0;
    border-bottom: 1px solid #e4e7ef;
  }
  .da-an__nav {
    display: flex;
    gap: 2px;
    margin-left: auto;
  }
  .da-an__nav a {
    width: 40px;
    min-height: 40px;
  }
  .da-an__top {
    padding: 12px 14px;
  }
  .da-an__title {
    font-size: 18px;
  }
  .da-an__main {
    gap: 12px;
    padding: 14px;
  }
  .da-an__kpi strong {
    font-size: 20px;
  }
  .da-an__bars {
    gap: 4px;
  }
  .da-an__card--src {
    grid-template-columns: 96px minmax(0, 1fr);
  }
}

SaaS admin with sidebar nav

  • sectioned sidebar
  • usage meters
  • sticky table header

Members

Plan usage
  • Seats18 of 25
  • Storage64 of 100 GB
  • API calls412k of 1M
Monthly recurring revenue

$24,860 +8.7% vs September

Twelve months, rising from $10,400 to $24,860.

Workspace members
NameRoleLast active
MOMara OkaforOwnerNow
DLDaniel LindAdmin12 min ago
PSPriya ShahMember2 h ago
TKTomas KralMemberYesterday
AJAna JovicInvitedNever

A workspace admin with a dark, sectioned sidebar, a search bar and a members table. Section titles and the plan card drop out when the sidebar shrinks to icons, and the link names stay in the accessibility tree through a visually hidden class instead of display: none.

View code
.da-sa {
  container: da-sa / inline-size;
  width: 100%;
  color: #1d2421;
}
.da-sa__app {
  display: grid;
  grid-template-columns: 216px minmax(0, 1fr);
  grid-template-rows: auto minmax(0, 1fr);
  grid-template-areas: "side top" "side main";
  height: 560px;
  overflow: hidden;
  border-radius: 18px;
  background: #faf8f3;
  box-shadow: 0 18px 40px rgba(18, 49, 43, .12);
  font-size: 14px;
  line-height: 1.4;
}
.da-sa__side {
  grid-area: side;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 18px 12px;
  overflow-y: auto;
  background: #12312b;
  color: #d9e4dc;
}
.da-sa__brand {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 14px;
  padding: 0 8px;
  color: #fff;
  font-family: "Fraunces", Georgia, serif;
  font-size: 19px;
  font-weight: 600;
}
.da-sa__mark {
  display: grid;
  flex: none;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 9px;
  background: #f3c96b;
  color: #12312b;
  font-size: 17px;
}
.da-sa__sect {
  margin: 12px 0 4px;
  padding: 0 10px;
  color: #a9bfb3;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
}
.da-sa__nav {
  display: grid;
  gap: 2px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.da-sa__nav a {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 40px;
  padding: 0 10px;
  border-radius: 10px;
  color: #d9e4dc;
  text-decoration: none;
}
.da-sa svg {
  flex: none;
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.da-sa__nav a:hover {
  background: #1c443c;
  color: #fff;
}
.da-sa__nav a[aria-current="page"] {
  background: #f3efe4;
  color: #12312b;
  font-weight: 600;
}
.da-sa__nav a:focus-visible {
  outline: 3px solid #f3c96b;
  outline-offset: 2px;
}
.da-sa__plan {
  display: grid;
  gap: 2px;
  margin: auto 0 0;
  padding: 12px;
  border: 1px solid #2b5a50;
  border-radius: 12px;
  color: #fff;
  font-weight: 600;
}
.da-sa__plan span {
  color: #a9bfb3;
  font-size: 12.5px;
  font-weight: 400;
}
.da-sa__top {
  grid-area: top;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 20px;
  border-bottom: 1px solid #e7e2d6;
}
.da-sa__search {
  display: flex;
  flex: 1;
  align-items: center;
  gap: 8px;
  min-width: 0;
  max-width: 360px;
  min-height: 40px;
  padding: 0 12px;
  border: 1px solid #d6d0c2;
  border-radius: 10px;
  background: #fff;
  color: #5c6660;
}
.da-sa__search:focus-within {
  outline: 3px solid #1f6f5c;
  outline-offset: 1px;
}
.da-sa__search input {
  flex: 1;
  min-width: 0;
  border: 0;
  outline: 0;
  background: none;
  color: #1d2421;
  font: inherit;
}
.da-sa__search input::placeholder {
  color: #6b736e;
}
.da-sa__icon-btn {
  position: relative;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  margin-left: auto;
  border: 1px solid #d6d0c2;
  border-radius: 10px;
  background: #fff;
  color: #1d2421;
  cursor: pointer;
}
.da-sa__badge {
  position: absolute;
  top: -5px;
  right: -5px;
  display: grid;
  place-items: center;
  min-width: 18px;
  height: 18px;
  border-radius: 9px;
  background: #b42318;
  color: #fff;
  font-size: 11px;
  font-style: normal;
  font-weight: 700;
}
.da-sa__avatar {
  display: grid;
  flex: none;
  place-items: center;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: #b4532a;
  color: #fff;
  font-size: 13px;
  font-weight: 700;
}
.da-sa__icon-btn:focus-visible,
.da-sa__btn:focus-visible {
  outline: 3px solid #1f6f5c;
  outline-offset: 2px;
}
.da-sa__main:focus-visible,
.da-sa__table-wrap:focus-visible {
  outline: 3px solid #1f6f5c;
  outline-offset: -3px;
}
.da-sa__main {
  grid-area: main;
  display: grid;
  align-content: start;
  gap: 16px;
  padding: 20px;
  overflow: auto;
  overscroll-behavior: contain;
}
.da-sa__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
.da-sa__title {
  margin: 0;
  font-family: "Fraunces", Georgia, serif;
  font-size: 24px;
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -.01em;
  color: #12312b;
}
.da-sa__btn {
  min-height: 40px;
  padding: 0 16px;
  border: 0;
  border-radius: 10px;
  background: #1f6f5c;
  color: #fff;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
.da-sa__btn:hover {
  background: #185a4a;
}
.da-sa__cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));
  gap: 14px;
}
.da-sa__card {
  padding: 16px;
  border: 1px solid #e7e2d6;
  border-radius: 14px;
  background: #fff;
}
.da-sa__h {
  margin: 0 0 12px;
  font-family: inherit;
  font-size: 14.5px;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: 0;
  color: #1d2421;
}
.da-sa__meters {
  display: grid;
  gap: 12px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.da-sa__meters li {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 6px;
  font-size: 13px;
}
.da-sa__meters b {
  font-variant-numeric: tabular-nums;
}
.da-sa__meters i {
  flex-basis: 100%;
  height: 8px;
  overflow: hidden;
  border-radius: 4px;
  background: #e9e5da;
}
.da-sa__meters i::before {
  content: "";
  display: block;
  width: var(--da-v);
  height: 100%;
  border-radius: 4px;
  background: #1f6f5c;
}
.da-sa__big {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px;
  margin: 0 0 10px;
  font-size: 26px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.da-sa__big span {
  color: #0f6e3c;
  font-size: 13px;
  font-weight: 600;
}
.da-sa__spark {
  display: flex;
  align-items: flex-end;
  gap: 4px;
  height: 56px;
}
.da-sa__spark i {
  flex: 1;
  height: var(--da-v);
  border-radius: 3px 3px 0 0;
  background: #b9d6cb;
}
.da-sa__spark i:last-child {
  background: #1f6f5c;
}
.da-sa__small {
  margin: 8px 0 0;
  color: #5c6660;
  font-size: 12.5px;
}
.da-sa__table-wrap {
  max-height: 240px;
  overflow: auto;
  border: 1px solid #e7e2d6;
  border-radius: 14px;
  background: #fff;
}
.da-sa__table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13.5px;
}
.da-sa__table th,
.da-sa__table td {
  padding: 10px 14px;
  border-bottom: 1px solid #f0ece2;
  text-align: left;
  white-space: nowrap;
}
.da-sa__table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: #f6f3ec;
  color: #5c6660;
  font-size: 12px;
  font-weight: 600;
}
.da-sa__table tbody th {
  font-weight: 500;
}
.da-sa__person {
  display: flex;
  align-items: center;
  gap: 10px;
}
.da-sa__person i {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--da-c);
  color: #fff;
  font-size: 11px;
  font-style: normal;
  font-weight: 700;
}
.da-sa__role {
  padding: 3px 9px;
  border-radius: 99px;
  background: #ece8de;
  color: #3d4642;
  font-size: 12px;
  font-weight: 600;
}
.da-sa__role--owner {
  background: #12312b;
  color: #fff;
}
.da-sa__role--pending {
  background: #fdf0d5;
  color: #7a4a00;
}
.da-sa__sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
@container da-sa (max-width: 760px) {
  .da-sa__app {
    grid-template-columns: 68px minmax(0, 1fr);
  }
  .da-sa__side {
    align-items: center;
    padding: 18px 10px;
  }
  .da-sa__brand {
    padding: 0;
  }
  .da-sa__sect,
  .da-sa__plan {
    display: none;
  }
  .da-sa__nav + .da-sa__sect + .da-sa__nav {
    margin-top: 10px;
    padding-top: 10px;
    border-top: 1px solid #2b5a50;
  }
  .da-sa__nav a {
    justify-content: center;
    width: 44px;
    min-height: 44px;
    padding: 0;
  }
  .da-sa__label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}
@container da-sa (max-width: 480px) {
  .da-sa__app {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto auto minmax(0, 1fr);
    grid-template-areas: "side" "top" "main";
  }
  .da-sa__side {
    flex-direction: row;
    gap: 2px;
    padding: 8px 10px;
    overflow-x: auto;
  }
  .da-sa__brand {
    margin: 0 auto 0 4px;
  }
  .da-sa__nav {
    display: flex;
    gap: 2px;
  }
  .da-sa__nav + .da-sa__sect + .da-sa__nav {
    margin: 0;
    padding: 0 0 0 4px;
    border-top: 0;
    border-left: 1px solid #2b5a50;
  }
  .da-sa__nav a {
    width: 40px;
    min-height: 40px;
  }
  .da-sa__top {
    padding: 10px 14px;
  }
  .da-sa__avatar {
    display: none;
  }
  .da-sa__main {
    padding: 14px;
  }
}

E-commerce orders

  • :has() filters
  • table to cards
  • ARIA table roles

Orders

Revenue today
$3,482.90
Orders today
41
Average order
$84.95
Filter orders by status
Recent orders
OrderCustomerDateTotalStatus
#10482Lena FischerOct 27$128.40Pending
#10481Omar HaddadOct 27$64.00Shipped
#10480Grace WuOct 26$212.75Pending
#10479Jonas BergOct 26$39.90Refunded
#10478Ama MensahOct 25$96.20Shipped
#10477Luca RomanoOct 25$58.30Pending
#10476Sofia AlvesOct 24$145.00Shipped
#10475Ben CarterOct 24$22.50Refunded

Pick a status filter above the table.

The status pills are radio buttons, and :has() on the dashboard hides the rows that do not match, with no script. In a narrow frame each row turns into a card through a container query, and explicit table roles keep the table readable for screen readers after the display change.

View code
.da-eo {
  container: da-eo / inline-size;
  width: 100%;
  color: #22201c;
}
.da-eo__app {
  display: grid;
  grid-template-columns: 196px minmax(0, 1fr);
  grid-template-areas: "side main";
  height: 560px;
  overflow: hidden;
  border: 1px solid #e6e1d9;
  border-radius: 16px;
  background: #fff;
  box-shadow: 0 18px 40px rgba(60, 40, 20, .08);
  font-size: 14px;
  line-height: 1.4;
}
.da-eo__side {
  grid-area: side;
  display: flex;
  flex-direction: column;
  gap: 22px;
  padding: 18px 12px;
  background: #f8f5f0;
  border-right: 1px solid #ece6dc;
}
.da-eo__brand {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  padding: 0 8px;
  font-size: 17px;
  font-weight: 700;
}
.da-eo__logo {
  flex: none;
  width: 26px;
  height: 26px;
  background: #c2410c;
  clip-path: polygon(50% 0, 100% 100%, 0 100%);
}
.da-eo__nav {
  display: grid;
  gap: 4px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.da-eo__nav a {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 40px;
  padding: 0 10px;
  border-radius: 10px;
  color: #514a40;
  font-weight: 500;
  text-decoration: none;
}
.da-eo__nav svg {
  flex: none;
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.da-eo__nav a:hover {
  background: #efe9df;
}
.da-eo__nav a[aria-current="page"] {
  background: #c2410c;
  color: #fff;
}
.da-eo__count {
  margin-left: auto;
  padding: 1px 7px;
  border-radius: 99px;
  background: #fff;
  color: #9a330a;
  font-size: 12px;
}
.da-eo__nav a:focus-visible,
.da-eo__btn:focus-visible {
  outline: 3px solid #c2410c;
  outline-offset: 2px;
}
.da-eo__main:focus-visible {
  outline: 3px solid #c2410c;
  outline-offset: -3px;
}
.da-eo__main {
  grid-area: main;
  display: grid;
  align-content: start;
  gap: 16px;
  padding: 20px 22px;
  overflow: auto;
  overscroll-behavior: contain;
}
.da-eo__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
.da-eo__title {
  margin: 0;
  font-family: inherit;
  font-size: 22px;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -.01em;
  color: #22201c;
}
.da-eo__btn {
  min-height: 38px;
  padding: 0 14px;
  border: 1px solid #d8d0c3;
  border-radius: 9px;
  background: #fff;
  color: #22201c;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
.da-eo__stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 12px;
  margin: 0;
}
.da-eo__stats div {
  padding: 12px 14px;
  border-radius: 12px;
  background: #f8f5f0;
}
.da-eo__stats dt {
  color: #6a6155;
  font-size: 12.5px;
}
.da-eo__stats dd {
  margin: 2px 0 0;
  font-size: 21px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.da-eo__filter {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0;
  padding: 0;
  border: 0;
}
.da-eo__filter input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.da-eo__filter label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 36px;
  padding: 0 14px;
  border: 1px solid #d8d0c3;
  border-radius: 99px;
  color: #514a40;
  font-weight: 500;
  cursor: pointer;
}
.da-eo__filter label span {
  color: #6a6155;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}
.da-eo__filter label:hover {
  background: #f8f5f0;
}
.da-eo__filter input:checked + label {
  border-color: #22201c;
  background: #22201c;
  color: #fff;
}
.da-eo__filter input:checked + label span {
  color: #e6dfd3;
}
.da-eo__filter input:focus-visible + label {
  outline: 3px solid #c2410c;
  outline-offset: 2px;
}
.da-eo:has(#da-eo-pending:checked) tbody tr:not([data-status="pending"]),
.da-eo:has(#da-eo-shipped:checked) tbody tr:not([data-status="shipped"]),
.da-eo:has(#da-eo-refunded:checked) tbody tr:not([data-status="refunded"]) {
  display: none;
}
.da-eo__table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13.5px;
  font-variant-numeric: tabular-nums;
}
.da-eo__table th,
.da-eo__table td {
  padding: 11px 12px;
  border-bottom: 1px solid #f0ebe3;
  text-align: left;
  white-space: nowrap;
}
.da-eo__table thead th {
  color: #6a6155;
  font-size: 12px;
  font-weight: 600;
}
.da-eo__table td:first-child {
  font-weight: 600;
}
.da-eo__table td:nth-child(4) {
  text-align: right;
}
.da-eo__table thead th:nth-child(4) {
  text-align: right;
}
.da-eo__pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px;
  border-radius: 99px;
  font-size: 12px;
  font-weight: 600;
}
.da-eo__pill::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
}
.da-eo__pill--pending {
  background: #fef3c7;
  color: #8a3b0a;
}
.da-eo__pill--shipped {
  background: #dcfce7;
  color: #166534;
}
.da-eo__pill--refunded {
  background: #e7e5e4;
  color: #44403c;
}
.da-eo__pill--refunded::before {
  border-radius: 1px;
}
.da-eo__label {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
@container da-eo (min-width: 761px) {
  .da-eo__brand .da-eo__label,
  .da-eo__nav .da-eo__label {
    position: static;
    width: auto;
    height: auto;
    overflow: visible;
    clip-path: none;
  }
}
@container da-eo (max-width: 760px) {
  .da-eo__app {
    grid-template-columns: 68px minmax(0, 1fr);
  }
  .da-eo__side {
    align-items: center;
    padding: 18px 10px;
  }
  .da-eo__brand {
    padding: 0;
  }
  .da-eo__nav a {
    justify-content: center;
    width: 44px;
    min-height: 44px;
    padding: 0;
  }
  .da-eo__count {
    position: absolute;
    top: 2px;
    right: 0;
    background: #22201c;
    color: #fff;
    font-size: 10.5px;
  }
}
@container da-eo (max-width: 560px) {
  .da-eo__table,
  .da-eo__table tbody,
  .da-eo__table tr,
  .da-eo__table td {
    display: block;
  }
  .da-eo__table thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }
  .da-eo__table tbody tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 2px 12px;
    margin-bottom: 10px;
    padding: 12px 14px;
    border: 1px solid #ece6dc;
    border-radius: 12px;
  }
  .da-eo:has(#da-eo-pending:checked) tbody tr:not([data-status="pending"]),
  .da-eo:has(#da-eo-shipped:checked) tbody tr:not([data-status="shipped"]),
  .da-eo:has(#da-eo-refunded:checked) tbody tr:not([data-status="refunded"]) {
    display: none;
  }
  .da-eo__table td {
    padding: 0;
    border: 0;
  }
  .da-eo__table td:nth-child(2) {
    grid-row: 2;
    color: #514a40;
  }
  .da-eo__table td:nth-child(3) {
    grid-row: 3;
    color: #6a6155;
    font-size: 12.5px;
  }
  .da-eo__table td:nth-child(4) {
    grid-column: 2;
    grid-row: 1;
    font-weight: 700;
  }
  .da-eo__table td:nth-child(5) {
    grid-column: 2;
    grid-row: 2 / span 2;
    align-self: end;
    text-align: right;
  }
}
@container da-eo (max-width: 480px) {
  .da-eo__app {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
    grid-template-areas: "side" "main";
  }
  .da-eo__side {
    flex-direction: row;
    gap: 8px;
    padding: 8px 10px 8px 14px;
    border-right: 0;
    border-bottom: 1px solid #ece6dc;
  }
  .da-eo__nav {
    display: flex;
    gap: 4px;
    margin-left: auto;
  }
  .da-eo__nav a {
    width: 42px;
    min-height: 42px;
  }
  .da-eo__main {
    gap: 12px;
    padding: 14px;
  }
  .da-eo__stats {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 6px;
  }
  .da-eo__stats div {
    padding: 8px 10px;
  }
  .da-eo__stats dd {
    font-size: 16px;
  }
  .da-eo__filter label {
    padding: 0 11px;
  }
}

Personal finance and banking

  • icon rail
  • conic-gradient donut
  • budget bars

Good morning, Iris

Tuesday, October 27

Checking •••• 4821

$12,480.32 Available balance

Savings •••• 0937

$38,215.00 +$500.00 this month
Spending in October
  • Housing38%
  • Food21%
  • Shopping17%
  • Transport14%
  • Other10%
Budgets
  • Groceries$412 of $500
  • Dining out$186 of $200
  • Travel$90 of $300
Recent transactions
  • Corner Coffee LabFood, today-$4.80
  • Salary, Northpoint LtdIncome, Oct 26+$4,200.00
  • Gridline EnergyHousing, Oct 25-$86.12
  • Transfer to savingsTransfer, Oct 25-$500.00

A banking overview with an icon rail instead of a full sidebar, which gives the money more room. The spending donut uses hard color stops, and every slice is repeated as text in the legend, so the chart is decoration on top of data that is already readable.

View code
.da-fi {
  container: da-fi / inline-size;
  width: 100%;
  color: #13294b;
}
.da-fi__app {
  display: grid;
  grid-template-columns: 72px minmax(0, 1fr);
  grid-template-areas: "rail main";
  height: 560px;
  overflow: hidden;
  border-radius: 20px;
  background: #eef1f6;
  box-shadow: 0 18px 40px rgba(19, 41, 75, .12);
  font-size: 14px;
  line-height: 1.4;
}
.da-fi__rail {
  grid-area: rail;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 26px;
  padding: 20px 0;
  background: #13294b;
}
.da-fi__logo {
  width: 30px;
  height: 30px;
  border: 7px solid #f2b84b;
  border-radius: 50% 50% 50% 0;
}
.da-fi__nav {
  display: grid;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.da-fi__nav a {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: 12px;
  color: #b9c6dd;
}
.da-fi__nav svg {
  width: 21px;
  height: 21px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.da-fi__nav a:hover {
  background: #1e3a66;
  color: #fff;
}
.da-fi__nav a[aria-current="page"] {
  background: #f2b84b;
  color: #13294b;
}
.da-fi__nav a:focus-visible {
  outline: 3px solid #fff;
  outline-offset: 2px;
}
.da-fi__main:focus-visible {
  outline: 3px solid #13294b;
  outline-offset: -3px;
}
.da-fi__main {
  grid-area: main;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-content: start;
  gap: 14px;
  padding: 22px;
  overflow: auto;
  overscroll-behavior: contain;
}
.da-fi__head,
.da-fi__accounts {
  grid-column: 1 / -1;
}
.da-fi__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 4px 12px;
}
.da-fi__title {
  margin: 0;
  font-family: "Fraunces", Georgia, serif;
  font-size: 24px;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -.01em;
  color: #13294b;
}
.da-fi__date {
  margin: 0;
  color: #4b5b78;
  font-size: 13px;
}
.da-fi__accounts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr));
  gap: 14px;
}
.da-fi__acct {
  display: grid;
  gap: 4px;
  padding: 18px;
  border-radius: 16px;
  background: #fff;
}
.da-fi__acct p {
  display: flex;
  justify-content: space-between;
  margin: 0;
  font-weight: 600;
}
.da-fi__acct p span {
  color: #4b5b78;
  font-weight: 400;
  letter-spacing: .08em;
}
.da-fi__acct strong {
  font-size: 27px;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.01em;
}
.da-fi__acct small {
  color: #4b5b78;
  font-size: 12.5px;
}
.da-fi__acct--main {
  background: #13294b;
  color: #fff;
}
.da-fi__acct--main p span,
.da-fi__acct--main small {
  color: #c4cfe3;
}
.da-fi__card {
  min-width: 0;
  padding: 16px 18px;
  border-radius: 16px;
  background: #fff;
}
.da-fi__card--tx {
  grid-column: 1 / -1;
}
.da-fi__h {
  margin: 0 0 12px;
  font-family: inherit;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: 0;
  color: #13294b;
}
.da-fi__spend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px;
}
.da-fi__donut {
  position: relative;
  display: grid;
  flex: none;
  place-items: center;
  width: 118px;
  aspect-ratio: 1;
  border-radius: 50%;
  background: conic-gradient(#13294b 0 38%, #2f7d6d 0 59%, #d9822b 0 76%, #7a8ab0 0 90%, #c9cfdc 0);
}
.da-fi__donut::before {
  content: "";
  position: absolute;
  inset: 16px;
  border-radius: 50%;
  background: #fff;
}
.da-fi__donut span {
  position: relative;
  display: grid;
  color: #4b5b78;
  font-size: 11.5px;
  text-align: center;
}
.da-fi__donut b {
  color: #13294b;
  font-size: 16px;
}
.da-fi__legend {
  display: grid;
  flex: 1;
  gap: 5px;
  min-width: 130px;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 13px;
}
.da-fi__legend li {
  display: flex;
  align-items: center;
  gap: 8px;
}
.da-fi__legend i {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--da-c);
}
.da-fi__legend b {
  margin-left: auto;
  font-variant-numeric: tabular-nums;
}
.da-fi__budgets {
  display: grid;
  gap: 14px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.da-fi__budgets li {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 6px;
  font-size: 13px;
}
.da-fi__budgets b {
  font-variant-numeric: tabular-nums;
}
.da-fi__budgets i {
  flex-basis: 100%;
  height: 10px;
  overflow: hidden;
  border-radius: 5px;
  background: #e3e8f1;
}
.da-fi__budgets i::before {
  content: "";
  display: block;
  width: var(--da-v);
  height: 100%;
  border-radius: 5px;
  background: #2f7d6d;
}
.da-fi__warn b {
  color: #9a4a0a;
}
.da-fi__warn i::before {
  background: #d9822b;
}
.da-fi__tx {
  display: grid;
  margin: 0;
  padding: 0;
  list-style: none;
}
.da-fi__tx li {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 0;
  border-top: 1px solid #edf0f5;
}
.da-fi__tx li:first-child {
  border-top: 0;
}
.da-fi__tx span:not(.da-fi__ico) {
  display: grid;
  flex: 1;
  min-width: 0;
  font-weight: 500;
}
.da-fi__tx small {
  color: #4b5b78;
  font-size: 12px;
  font-weight: 400;
}
.da-fi__ico {
  display: grid;
  flex: none;
  place-items: center;
  width: 36px;
  height: 36px;
  border-radius: 10px;
  background: #e3e8f1;
  color: #13294b;
  font-weight: 700;
}
.da-fi__ico--in {
  background: #dcefe9;
  color: #1f5f52;
}
.da-fi__tx b {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.da-fi__in {
  color: #1d6b4a;
}
.da-fi__out {
  color: #13294b;
}
@container da-fi (max-width: 640px) {
  .da-fi__main {
    grid-template-columns: minmax(0, 1fr);
  }
}
@container da-fi (max-width: 480px) {
  .da-fi__app {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(0, 1fr) auto;
    grid-template-areas: "main" "rail";
  }
  .da-fi__rail {
    flex-direction: row;
    justify-content: center;
    padding: 6px 0;
  }
  .da-fi__logo {
    display: none;
  }
  .da-fi__nav {
    display: flex;
    gap: 18px;
  }
  .da-fi__main {
    gap: 12px;
    padding: 16px 14px;
  }
  .da-fi__title {
    font-size: 21px;
  }
  .da-fi__acct strong {
    font-size: 23px;
  }
}

Workflow and team dashboards

Boards, pipelines and directories where the layout has to carry lists of items, not just numbers. The kanban and pipeline views scroll sideways inside their own region, and the directory filters with a short script.

Project kanban board

  • scroll-snap columns
  • :has() WIP limit
  • quantity query

Sprint 14

Oct 20 to Nov 2

To do 3
  • Design

    Empty states for the reports page

    Oct 30Assigned to Mara Okafor
  • Backend

    Rate-limit the export endpoint

    Nov 1Assigned to Daniel Lind
  • Docs

    Write the webhook retry guide

    Nov 2Assigned to Priya Shah
In progress 4 / 3

Over the WIP limit of 3

  • Bug

    Chart tooltip clipped in Safari

    Oct 28Assigned to Tomas Kral
  • Backend

    Move invoices to the new queue

    Oct 29Assigned to Daniel Lind
  • Design

    Dark theme tokens for charts

    Oct 31Assigned to Mara Okafor
  • Docs

    Update the API changelog

    Oct 30Assigned to Priya Shah
Review 2
  • Bug

    Date picker skips March 30

    Oct 27Assigned to Ana Jovic
  • Design

    Onboarding checklist layout

    Oct 28Assigned to Mara Okafor
Done 2
  • Backend

    Paginate the audit log

    Done Oct 24Assigned to Tomas Kral
  • Bug

    Fix double toast on save

    Done Oct 23Assigned to Ana Jovic

Columns sit in a horizontal scroller with scroll-snap, and each column scrolls its own cards, which is how real boards behave. The In progress column carries a work-in-progress limit of three: a :has() quantity query spots the fourth card and turns the column header amber with a written warning.

View code
.da-kb {
  container: da-kb / inline-size;
  width: 100%;
  color: #1f1d1a;
}
.da-kb__app {
  display: grid;
  grid-template-columns: 180px minmax(0, 1fr);
  grid-template-rows: auto minmax(0, 1fr);
  grid-template-areas: "side top" "side board";
  height: 560px;
  overflow: hidden;
  border: 1px solid #e3e0da;
  border-radius: 16px;
  background: #fff;
  box-shadow: 0 18px 40px rgba(30, 25, 15, .08);
  font-size: 14px;
  line-height: 1.4;
}
.da-kb__side {
  grid-area: side;
  display: flex;
  flex-direction: column;
  gap: 20px;
  padding: 18px 12px;
  border-right: 1px solid #ebe8e2;
}
.da-kb__brand {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  padding: 0 8px;
  font-size: 17px;
  font-weight: 700;
}
.da-kb__logo {
  flex: none;
  width: 24px;
  height: 24px;
  border: 5px solid #1f1d1a;
  border-radius: 50%;
  box-shadow: 6px -6px 0 -2px #f59e0b;
}
.da-kb__nav {
  display: grid;
  gap: 2px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.da-kb__nav a {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 38px;
  padding: 0 10px;
  border-radius: 9px;
  color: #4d4840;
  text-decoration: none;
}
.da-kb__nav i {
  flex: none;
  width: 12px;
  height: 12px;
  border-radius: 4px;
  background: var(--da-c);
}
.da-kb__nav a:hover {
  background: #f5f3ef;
}
.da-kb__nav a[aria-current="page"] {
  background: #f1efe9;
  color: #1f1d1a;
  font-weight: 600;
}
.da-kb__nav a:focus-visible,
.da-kb__btn:focus-visible {
  outline: 3px solid #1f1d1a;
  outline-offset: 2px;
}
.da-kb__board:focus-visible {
  outline: 3px solid #1f1d1a;
  outline-offset: -3px;
}
.da-kb__top {
  grid-area: top;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 14px;
  padding: 14px 20px;
  border-bottom: 1px solid #ebe8e2;
}
.da-kb__title {
  margin: 0;
  font-family: inherit;
  font-size: 20px;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -.01em;
  color: #1f1d1a;
}
.da-kb__meta {
  margin: 0;
  color: #615b51;
  font-size: 13px;
}
.da-kb__btn {
  min-height: 38px;
  margin-left: auto;
  padding: 0 14px;
  border: 0;
  border-radius: 9px;
  background: #1f1d1a;
  color: #fff;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
.da-kb__board {
  grid-area: board;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(220px, 1fr);
  gap: 12px;
  padding: 16px;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scroll-padding: 16px;
  background: #f7f6f3;
}
.da-kb__col {
  display: flex;
  flex-direction: column;
  min-height: 0;
  scroll-snap-align: start;
  border-radius: 12px;
  background: #efede8;
}
.da-kb__h {
  display: flex;
  justify-content: space-between;
  margin: 0;
  padding: 12px 14px 8px;
  font-family: inherit;
  font-size: 13.5px;
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: 0;
  color: #1f1d1a;
}
.da-kb__h span {
  color: #615b51;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}
.da-kb__over {
  display: none;
  margin: 0 10px 6px;
  padding: 6px 10px;
  border-radius: 8px;
  background: #fef3c7;
  color: #7c3a06;
  font-size: 12.5px;
  font-weight: 600;
}
.da-kb__col--limit:has(.da-kb__card:nth-child(4)) {
  box-shadow: inset 0 3px 0 #d97706;
}
.da-kb__col--limit:has(.da-kb__card:nth-child(4)) .da-kb__over {
  display: block;
}
.da-kb__list {
  display: grid;
  align-content: start;
  gap: 8px;
  min-height: 0;
  margin: 0;
  padding: 2px 10px 10px;
  overflow-y: auto;
  list-style: none;
}
.da-kb__card {
  position: relative;
  display: grid;
  gap: 6px;
  padding: 10px 12px;
  border: 1px solid #e3e0da;
  border-radius: 10px;
  background: #fff;
  box-shadow: 0 1px 2px rgba(30, 25, 15, .06);
}
.da-kb__card p {
  margin: 0;
  font-weight: 500;
}
.da-kb__card--done p {
  color: #615b51;
  text-decoration: line-through;
}
.da-kb__tag {
  justify-self: start;
  padding: 2px 8px;
  border-radius: 6px;
  font-size: 11.5px;
  font-weight: 700;
}
.da-kb__tag--design {
  background: #f1eafe;
  color: #5b21b6;
}
.da-kb__tag--back {
  background: #e0f2fe;
  color: #075985;
}
.da-kb__tag--bug {
  background: #fde8e8;
  color: #9f1d1d;
}
.da-kb__tag--docs {
  background: #e7f6ec;
  color: #166534;
}
.da-kb__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  color: #615b51;
  font-size: 12px;
}
.da-kb__foot i {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--da-c);
  color: #fff;
  font-size: 10.5px;
  font-style: normal;
  font-weight: 700;
}
.da-kb__sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
@container da-kb (max-width: 760px) {
  .da-kb__app {
    grid-template-columns: 60px minmax(0, 1fr);
  }
  .da-kb__side {
    align-items: center;
    padding: 18px 8px;
  }
  .da-kb__brand {
    padding: 0;
  }
  .da-kb__nav a {
    justify-content: center;
    width: 44px;
    min-height: 44px;
    padding: 0;
  }
  .da-kb__nav i {
    width: 16px;
    height: 16px;
  }
  .da-kb__label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}
@container da-kb (max-width: 480px) {
  .da-kb__app {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto auto minmax(0, 1fr);
    grid-template-areas: "side" "top" "board";
  }
  .da-kb__side {
    flex-direction: row;
    gap: 8px;
    padding: 6px 10px 6px 14px;
    border-right: 0;
    border-bottom: 1px solid #ebe8e2;
  }
  .da-kb__nav {
    display: flex;
    margin-left: auto;
  }
  .da-kb__top {
    padding: 10px 14px;
  }
  .da-kb__board {
    grid-auto-columns: 82%;
    padding: 12px;
    scroll-padding: 12px;
  }
}

CRM sales pipeline

  • flex-grow funnel
  • subgrid rows
  • probability bars

Q4 pipeline

87 open deals

Open pipeline
$1.24M
Weighted
$350k
Win rate
31%
Avg. cycle
38 days
Value by stage
  • Lead42 deals$520k
  • Qualified24 deals$380k
  • Proposal14 deals$210k
  • Negotiation7 deals$130k
Deals closing soon
  • Halden FreightNegotiation, closes Nov 4$48,00075%
  • Marrow and PikeProposal, closes Nov 9$31,50050%
  • Sundial ClinicsNegotiation, closes Nov 12$26,20075%
  • Quarry LabsQualified, closes Nov 30$19,80025%

The pipeline bar is a single flex row where each stage grows by its deal value, so the proportions come straight from the data in the markup. Below it, the stage list uses subgrid so names, counts and totals line up in columns whatever their length.

View code
.da-cr {
  container: da-cr / inline-size;
  width: 100%;
  color: #2a1726;
}
.da-cr__app {
  display: grid;
  grid-template-columns: 190px minmax(0, 1fr);
  grid-template-areas: "side main";
  height: 560px;
  overflow: hidden;
  border-radius: 16px;
  background: #faf7f9;
  box-shadow: 0 18px 40px rgba(60, 20, 50, .1);
  font-size: 14px;
  line-height: 1.4;
}
.da-cr__side {
  grid-area: side;
  display: flex;
  flex-direction: column;
  gap: 22px;
  padding: 18px 12px;
  background: #5e2a50;
}
.da-cr__brand {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  padding: 0 8px;
  color: #fff;
  font-size: 17px;
  font-weight: 700;
}
.da-cr__logo {
  display: grid;
  flex: none;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: #fff;
  color: #5e2a50;
  font-family: "Fraunces", Georgia, serif;
}
.da-cr__nav {
  display: grid;
  gap: 4px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.da-cr__nav a {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 40px;
  padding: 0 10px;
  border-radius: 10px;
  color: #f2e4ee;
  text-decoration: none;
}
.da-cr__nav svg {
  flex: none;
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.da-cr__nav a:hover {
  background: #73385f;
}
.da-cr__nav a[aria-current="page"] {
  background: #fff;
  color: #5e2a50;
  font-weight: 600;
}
.da-cr__nav a:focus-visible {
  outline: 3px solid #fff;
  outline-offset: 2px;
}
.da-cr__main:focus-visible {
  outline: 3px solid #5e2a50;
  outline-offset: -3px;
}
.da-cr__main {
  grid-area: main;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-content: start;
  gap: 14px;
  padding: 20px 22px;
  overflow: auto;
  overscroll-behavior: contain;
}
.da-cr__head,
.da-cr__kpis {
  grid-column: 1 / -1;
}
.da-cr__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}
.da-cr__title {
  margin: 0;
  font-family: "Fraunces", Georgia, serif;
  font-size: 24px;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -.01em;
  color: #2a1726;
}
.da-cr__meta {
  margin: 0;
  color: #6b5566;
  font-size: 13px;
}
.da-cr__kpis {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 10px;
  margin: 0;
}
.da-cr__kpis div {
  padding: 12px 14px;
  border: 1px solid #eadfe6;
  border-radius: 12px;
  background: #fff;
}
.da-cr__kpis dt {
  color: #6b5566;
  font-size: 12.5px;
}
.da-cr__kpis dd {
  margin: 2px 0 0;
  font-size: 21px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.da-cr__card {
  min-width: 0;
  padding: 16px;
  border: 1px solid #eadfe6;
  border-radius: 14px;
  background: #fff;
}
.da-cr__h {
  margin: 0 0 12px;
  font-family: inherit;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: 0;
  color: #2a1726;
}
.da-cr__funnel {
  display: flex;
  gap: 3px;
  height: 18px;
  margin-bottom: 14px;
}
.da-cr__funnel i {
  flex: var(--da-g) 1 0;
  border-radius: 4px;
  background: var(--da-c);
}
.da-cr__stages {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  gap: 8px 14px;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 13.5px;
}
.da-cr__stages li {
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: subgrid;
  align-items: center;
}
.da-cr__stages span:first-child {
  display: flex;
  align-items: center;
  gap: 8px;
}
.da-cr__stages i {
  flex: none;
  width: 10px;
  height: 10px;
  border-radius: 3px;
  background: var(--da-c);
}
.da-cr__stages span + span {
  color: #6b5566;
}
.da-cr__stages b {
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.da-cr__deals {
  display: grid;
  margin: 0;
  padding: 0;
  list-style: none;
}
.da-cr__deals li {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 4px 12px;
  padding: 10px 0;
  border-top: 1px solid #f1e9ee;
}
.da-cr__deals li:first-child {
  padding-top: 0;
  border-top: 0;
}
.da-cr__co {
  display: grid;
  font-weight: 600;
}
.da-cr__co small {
  color: #6b5566;
  font-size: 12px;
  font-weight: 400;
}
.da-cr__deals b {
  font-variant-numeric: tabular-nums;
}
.da-cr__prob {
  display: flex;
  grid-column: 1 / -1;
  align-items: center;
  gap: 8px;
  color: #6b5566;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}
.da-cr__prob i {
  flex: 1;
  height: 6px;
  overflow: hidden;
  border-radius: 3px;
  background: #f1e9ee;
}
.da-cr__prob i::before {
  content: "";
  display: block;
  width: var(--da-v);
  height: 100%;
  background: #864f76;
}
@supports not (grid-template-columns: subgrid) {
  .da-cr__stages li {
    grid-template-columns: minmax(0, 1fr) 70px 60px;
  }
}
@container da-cr (max-width: 760px) {
  .da-cr__app {
    grid-template-columns: 68px minmax(0, 1fr);
  }
  .da-cr__side {
    align-items: center;
    padding: 18px 10px;
  }
  .da-cr__brand {
    padding: 0;
  }
  .da-cr__nav a {
    justify-content: center;
    width: 44px;
    min-height: 44px;
    padding: 0;
  }
  .da-cr__label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}
@container da-cr (max-width: 640px) {
  .da-cr__main {
    grid-template-columns: minmax(0, 1fr);
  }
}
@container da-cr (max-width: 480px) {
  .da-cr__app {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
    grid-template-areas: "side" "main";
  }
  .da-cr__side {
    flex-direction: row;
    gap: 8px;
    padding: 8px 10px 8px 14px;
  }
  .da-cr__nav {
    display: flex;
    gap: 4px;
    margin-left: auto;
  }
  .da-cr__nav a {
    width: 42px;
    min-height: 42px;
  }
  .da-cr__main {
    gap: 12px;
    padding: 14px;
  }
  .da-cr__kpis {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

HR team directory

  • auto-fill grid
  • live filter
  • role="status"

Directory

Showing 8 of 8 people

Team
  • Nadia AmariProduct designerLisbonIn office
  • Kofi BoatengBackend engineerAccraRemote
  • Elin HolmPeople partnerOsloIn office
  • Ravi MenonEngineering managerPuneOn leave
  • Chloe LaurentBrand designerLyonRemote
  • Mateo SilvaFrontend engineerLisbonIn office
  • Yuki TanakaFinance leadOsakaRemote
  • Hana OkoyeQA engineerLagosIn office

Type a name or pick a team.

A people directory where search and team chips filter the cards with a few lines of script. The result count sits in a role="status" element, so screen reader users hear how many people match, and the card grid uses auto-fill with min() so it never overflows a narrow frame.

View code
.da-hr {
  container: da-hr / inline-size;
  width: 100%;
  color: #24261c;
}
.da-hr__app {
  display: grid;
  grid-template-columns: 200px minmax(0, 1fr);
  grid-template-areas: "side main";
  height: 560px;
  overflow: hidden;
  border: 1px solid #e2e0d2;
  border-radius: 16px;
  background: #f7f6ef;
  box-shadow: 0 18px 40px rgba(40, 45, 20, .08);
  font-size: 14px;
  line-height: 1.4;
}
.da-hr__side {
  grid-area: side;
  display: flex;
  flex-direction: column;
  gap: 22px;
  padding: 18px 12px;
  border-right: 1px solid #e2e0d2;
  background: #fff;
}
.da-hr__brand {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  padding: 0 8px;
  font-family: "Fraunces", Georgia, serif;
  font-size: 17px;
  font-weight: 600;
}
.da-hr__logo {
  flex: none;
  width: 26px;
  height: 26px;
  border-radius: 50% 0;
  background: #4d5d1a;
}
.da-hr__nav {
  display: grid;
  gap: 4px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.da-hr__nav a {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 40px;
  padding: 0 10px;
  border-radius: 10px;
  color: #4a4d3d;
  text-decoration: none;
}
.da-hr svg {
  flex: none;
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.da-hr__nav a:hover {
  background: #f1f0e6;
}
.da-hr__nav a[aria-current="page"] {
  background: #4d5d1a;
  color: #fff;
}
.da-hr__nav a:focus-visible {
  outline: 3px solid #4d5d1a;
  outline-offset: 2px;
}
.da-hr__main:focus-visible {
  outline: 3px solid #4d5d1a;
  outline-offset: -3px;
}
.da-hr__main {
  grid-area: main;
  display: grid;
  align-content: start;
  gap: 14px;
  padding: 20px 22px;
  overflow: auto;
  overscroll-behavior: contain;
}
.da-hr__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 4px 12px;
}
.da-hr__title {
  margin: 0;
  font-family: "Fraunces", Georgia, serif;
  font-size: 24px;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -.01em;
  color: #24261c;
}
.da-hr__count {
  margin: 0;
  color: #5a5d4a;
  font-size: 13px;
}
.da-hr__tools {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
}
.da-hr__search {
  display: flex;
  flex: 1 1 220px;
  align-items: center;
  gap: 8px;
  min-height: 42px;
  padding: 0 12px;
  border: 1px solid #cfccb8;
  border-radius: 10px;
  background: #fff;
  color: #5a5d4a;
}
.da-hr__search:focus-within {
  outline: 3px solid #4d5d1a;
  outline-offset: 1px;
}
.da-hr__input {
  flex: 1;
  min-width: 0;
  border: 0;
  outline: 0;
  background: none;
  color: #24261c;
  font: inherit;
}
.da-hr__input::placeholder {
  color: #6b6e5a;
}
.da-hr__chips {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0;
  padding: 0;
  border: 0;
}
.da-hr__chips input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.da-hr__chips span {
  display: inline-flex;
  align-items: center;
  min-height: 34px;
  padding: 0 12px;
  border: 1px solid #cfccb8;
  border-radius: 99px;
  background: #fff;
  color: #4a4d3d;
  font-size: 13px;
  cursor: pointer;
}
.da-hr__chips input:checked + span {
  border-color: #4d5d1a;
  background: #4d5d1a;
  color: #fff;
}
.da-hr__chips input:focus-visible + span {
  outline: 3px solid #4d5d1a;
  outline-offset: 2px;
}
.da-hr__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 170px), 1fr));
  gap: 12px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.da-hr__person {
  display: grid;
  justify-items: start;
  gap: 2px;
  padding: 14px;
  border: 1px solid #e2e0d2;
  border-radius: 14px;
  background: #fff;
  color: #5a5d4a;
  font-size: 13px;
}
.da-hr__person[hidden] {
  display: none;
}
.da-hr__person b {
  color: #24261c;
  font-size: 14.5px;
}
.da-hr__av {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  margin-bottom: 8px;
  border-radius: 50%;
  background: var(--da-c);
  color: #fff;
  font-size: 14px;
  font-weight: 700;
}
.da-hr__city {
  color: #24261c;
}
.da-hr__st {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 8px;
  padding: 2px 9px;
  border-radius: 99px;
  font-size: 12px;
  font-weight: 600;
}
.da-hr__st::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
}
.da-hr__st--office {
  background: #e6f0d6;
  color: #3d4a12;
}
.da-hr__st--remote {
  background: #e3ecf5;
  color: #1f4a73;
}
.da-hr__st--leave {
  background: #f4e7d9;
  color: #7a3f0c;
}
.da-hr__st--leave::before {
  border-radius: 1px;
}
.da-hr__empty {
  margin: 0;
  padding: 24px;
  border: 1px dashed #cfccb8;
  border-radius: 14px;
  color: #5a5d4a;
  text-align: center;
}
.da-hr__empty[hidden] {
  display: none;
}
.da-hr__sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
@container da-hr (max-width: 760px) {
  .da-hr__app {
    grid-template-columns: 68px minmax(0, 1fr);
  }
  .da-hr__side {
    align-items: center;
    padding: 18px 10px;
  }
  .da-hr__brand {
    padding: 0;
  }
  .da-hr__nav a {
    justify-content: center;
    width: 44px;
    min-height: 44px;
    padding: 0;
  }
  .da-hr__label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}
@container da-hr (max-width: 480px) {
  .da-hr__app {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
    grid-template-areas: "side" "main";
  }
  .da-hr__side {
    flex-direction: row;
    gap: 8px;
    padding: 8px 10px 8px 14px;
    border-right: 0;
    border-bottom: 1px solid #e2e0d2;
  }
  .da-hr__nav {
    display: flex;
    gap: 4px;
    margin-left: auto;
  }
  .da-hr__nav a {
    width: 42px;
    min-height: 42px;
  }
  .da-hr__main {
    gap: 12px;
    padding: 14px;
  }
  .da-hr__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
  }
  .da-hr__person {
    padding: 12px;
  }
}

Marketing campaign stats

  • table as bar chart
  • role="switch"
  • :has() comparison

Autumn knit drop

Impressions
1.82M
Click-through rate
2.54%
Conversions
1,388
Cost per acquisition
$21.40
Conversions by channelDark tick: previous period
ChannelConversionsChartSpendCPA
Search612prev. 540$10,400$16.99
Social438prev. 470$9,800$22.37
Email214prev. 180$1,900$8.88
Display124prev. 150$7,603$61.31
All campaigns
  • Autumn knit dropLive1,388 conv.
  • Free shipping weekendEnded904 conv.
  • Win-back newsletterScheduledStarts Nov 3

Turn on Compare with previous period.

The channel chart is a real data table with a bar drawn in one cell per row, so the numbers stay in table form for screen readers. The compare switch is a checkbox with role="switch", and :has() adds the previous period as an outlined bar plus its value in text.

View code
.da-mk {
  container: da-mk / inline-size;
  width: 100%;
  color: #102a30;
}
.da-mk__app {
  display: grid;
  grid-template-columns: 196px minmax(0, 1fr);
  grid-template-areas: "side main";
  height: 560px;
  overflow: hidden;
  border: 1px solid #dbe5e7;
  border-radius: 16px;
  background: #fff;
  box-shadow: 0 18px 40px rgba(10, 60, 70, .08);
  font-size: 14px;
  line-height: 1.4;
}
.da-mk__side {
  grid-area: side;
  display: flex;
  flex-direction: column;
  gap: 22px;
  padding: 18px 12px;
  background: #0b5563;
}
.da-mk__brand {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  padding: 0 8px;
  color: #fff;
  font-size: 17px;
  font-weight: 700;
}
.da-mk__logo {
  flex: none;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: #f5c400;
  box-shadow: inset 0 0 0 7px #0b5563, inset 0 0 0 26px #f5c400;
}
.da-mk__nav {
  display: grid;
  gap: 4px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.da-mk__nav a {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 40px;
  padding: 0 10px;
  border-radius: 10px;
  color: #d5eaee;
  text-decoration: none;
}
.da-mk__nav svg {
  flex: none;
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.da-mk__nav a:hover {
  background: #0e6575;
  color: #fff;
}
.da-mk__nav a[aria-current="page"] {
  background: #f5c400;
  color: #102a30;
  font-weight: 600;
}
.da-mk__nav a:focus-visible {
  outline: 3px solid #fff;
  outline-offset: 2px;
}
.da-mk__main:focus-visible,
.da-mk__scroll:focus-visible {
  outline: 3px solid #0b5563;
  outline-offset: -3px;
}
.da-mk__main {
  grid-area: main;
  display: grid;
  align-content: start;
  gap: 14px;
  padding: 20px 22px;
  overflow: auto;
  overscroll-behavior: contain;
}
.da-mk__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
.da-mk__title {
  margin: 0;
  font-family: inherit;
  font-size: 21px;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -.01em;
  color: #102a30;
}
.da-mk__switch {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-height: 36px;
  color: #33545b;
  font-size: 13.5px;
  cursor: pointer;
}
.da-mk__toggle {
  position: absolute;
  opacity: 0;
  width: 44px;
  height: 26px;
  margin: 0;
  cursor: pointer;
}
.da-mk__track {
  position: relative;
  flex: none;
  width: 44px;
  height: 26px;
  border-radius: 13px;
  background: #9db3b8;
}
.da-mk__track::after {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: #fff;
}
.da-mk__toggle:checked + .da-mk__track {
  background: #0b5563;
}
.da-mk__toggle:checked + .da-mk__track::after {
  translate: 18px 0;
}
.da-mk__toggle:focus-visible + .da-mk__track {
  outline: 3px solid #0b5563;
  outline-offset: 2px;
}
.da-mk__kpis {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 10px;
  margin: 0;
}
.da-mk__kpis div {
  padding: 12px 14px;
  border-left: 4px solid #f5c400;
  border-radius: 4px 12px 12px 4px;
  background: #f1f6f7;
}
.da-mk__kpis dt {
  color: #3f5f66;
  font-size: 12.5px;
}
.da-mk__kpis dd {
  margin: 2px 0 0;
  font-size: 21px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.da-mk__card {
  min-width: 0;
  border: 1px solid #dbe5e7;
  border-radius: 14px;
}
.da-mk__card--list {
  padding: 16px;
}
.da-mk__scroll {
  position: relative;
  overflow-x: auto;
  border-radius: 14px;
}
.da-mk__table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13.5px;
  font-variant-numeric: tabular-nums;
}
.da-mk__table caption {
  padding: 14px 16px 4px;
  font-size: 15px;
  font-weight: 600;
  text-align: left;
}
.da-mk__table th,
.da-mk__table td {
  padding: 10px 14px;
  border-top: 1px solid #eef3f4;
  text-align: right;
  white-space: nowrap;
}
.da-mk__table thead th {
  border-top: 0;
  color: #3f5f66;
  font-size: 12px;
  font-weight: 600;
}
.da-mk__table th:first-child {
  text-align: left;
}
.da-mk__table tbody th {
  font-weight: 600;
}
.da-mk__barcell {
  width: 40%;
  min-width: 110px;
}
.da-mk__barcell i {
  position: relative;
  display: block;
  height: 14px;
}
.da-mk__barcell i::before,
.da-mk__barcell i::after {
  content: "";
  position: absolute;
  left: 0;
  border-radius: 0 4px 4px 0;
}
.da-mk__barcell i::before {
  top: 0;
  width: var(--da-v);
  height: 14px;
  background: #0b7285;
}
.da-mk__barcell i::after {
  display: none;
  top: -4px;
  left: calc(var(--da-p) - 2px);
  width: 4px;
  height: 22px;
  border-radius: 2px;
  background: #102a30;
  box-shadow: 0 0 0 2px #fff;
}
.da-mk__key {
  display: none;
  margin-top: 2px;
  color: #3f5f66;
  font-size: 12px;
  font-weight: 400;
}
.da-mk:has(.da-mk__toggle:checked) .da-mk__key {
  display: block;
}
.da-mk__prev {
  display: none;
  color: #3f5f66;
  font-size: 11.5px;
}
.da-mk:has(.da-mk__toggle:checked) .da-mk__barcell i::after {
  display: block;
}
.da-mk:has(.da-mk__toggle:checked) .da-mk__prev {
  display: block;
}
.da-mk__h {
  margin: 0 0 10px;
  font-family: inherit;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: 0;
  color: #102a30;
}
.da-mk__list {
  display: grid;
  margin: 0;
  padding: 0;
  list-style: none;
}
.da-mk__list li {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 12px;
  padding: 9px 0;
  border-top: 1px solid #eef3f4;
}
.da-mk__list li:first-child {
  border-top: 0;
}
.da-mk__list b {
  min-width: 96px;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.da-mk__st {
  padding: 2px 9px;
  border-radius: 99px;
  background: #e8eeef;
  color: #33545b;
  font-size: 12px;
  font-weight: 600;
}
.da-mk__st--live {
  background: #dff3e8;
  color: #17603a;
}
.da-mk__st--soon {
  background: #fff4c2;
  color: #6b4f00;
}
.da-mk__sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
@media (prefers-reduced-motion: no-preference) {
  .da-mk__track::after {
    transition: translate .2s ease;
  }
}
@container da-mk (max-width: 760px) {
  .da-mk__app {
    grid-template-columns: 68px minmax(0, 1fr);
  }
  .da-mk__side {
    align-items: center;
    padding: 18px 10px;
  }
  .da-mk__brand {
    padding: 0;
  }
  .da-mk__nav a {
    justify-content: center;
    width: 44px;
    min-height: 44px;
    padding: 0;
  }
  .da-mk__label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}
@container da-mk (max-width: 520px) {
  .da-mk__table thead th:nth-child(4),
  .da-mk__table td:nth-child(4) {
    display: none;
  }
  .da-mk__barcell {
    width: auto;
    min-width: 44px;
  }
  .da-mk__table {
    font-size: 12.5px;
  }
  .da-mk__table th,
  .da-mk__table td {
    padding: 9px 6px;
  }
  .da-mk__table th:first-child {
    padding-left: 12px;
  }
  .da-mk__table td:last-child,
  .da-mk__table th:last-child {
    padding-right: 12px;
  }
  .da-mk__list li {
    grid-template-columns: minmax(0, 1fr) auto;
  }
  .da-mk__list b {
    grid-column: 1 / -1;
    text-align: left;
    color: #3f5f66;
    font-size: 12.5px;
  }
}
@container da-mk (max-width: 480px) {
  .da-mk__app {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
    grid-template-areas: "side" "main";
  }
  .da-mk__side {
    flex-direction: row;
    gap: 8px;
    padding: 8px 10px 8px 14px;
  }
  .da-mk__nav {
    display: flex;
    gap: 4px;
    margin-left: auto;
  }
  .da-mk__nav a {
    width: 42px;
    min-height: 42px;
  }
  .da-mk__main {
    gap: 12px;
    padding: 14px;
  }
  .da-mk__kpis {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

Monitoring, trading and device dashboards

Dense, glanceable screens: status tiles, sparklines, candlesticks and control panels. Every chart is CSS or inline SVG with the values also written out as text, so nothing depends on color or on a charting library.

Server monitoring

  • status tiles
  • SVG sparklines
  • uptime strip

Production, eu-west

Live, updated 09:31 UTC

  • api-gatewayOperationalp95 84 ms
  • auth-serviceOperationalp95 61 ms
  • db-primaryDegradedp95 412 ms
  • worker-queueDownSince 09:14 UTC
  • search-indexOperationalp95 120 ms
  • cdn-edgeOperationalHit ratio 96%

CPU42%

Memory68%

Requests/s1,240

api-gateway uptime, last 30 days99.98%

29 days fully operational, 1 day with degraded performance (Oct 9).

Incident log
  • Majorworker-queue stopped consuming jobs. Investigating.
  • Minordb-primary p95 latency above 400 ms.
  • Resolvedcdn-edge cache purge delay.

An operations screen where each service tile pairs its color with a shape and a written status, so a red tile is never the only signal. The sparklines are inline SVG polylines with vector-effect: non-scaling-stroke, which keeps the line crisp while the SVG stretches to any card width.

View code
.da-sm {
  container: da-sm / inline-size;
  width: 100%;
  color: #e6edf3;
}
.da-sm__app {
  display: grid;
  grid-template-columns: 184px minmax(0, 1fr);
  grid-template-areas: "side main";
  height: 560px;
  overflow: hidden;
  border: 1px solid #262c36;
  border-radius: 14px;
  background: #0d1117;
  font-size: 14px;
  line-height: 1.4;
}
.da-sm__side {
  grid-area: side;
  display: flex;
  flex-direction: column;
  gap: 22px;
  padding: 18px 12px;
  border-right: 1px solid #262c36;
  background: #010409;
}
.da-sm__brand {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  padding: 0 8px;
  font-size: 16px;
  font-weight: 700;
}
.da-sm__logo {
  flex: none;
  width: 24px;
  height: 24px;
  border: 3px solid #3fb950;
  border-radius: 50%;
  box-shadow: inset 0 0 0 4px #010409, inset 0 0 0 12px #3fb950;
}
.da-sm__nav {
  display: grid;
  gap: 4px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.da-sm__nav a {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 40px;
  padding: 0 10px;
  border-radius: 8px;
  color: #9ba6b2;
  text-decoration: none;
}
.da-sm__nav svg {
  flex: none;
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.da-sm__nav a:hover {
  background: #161b22;
  color: #e6edf3;
}
.da-sm__nav a[aria-current="page"] {
  background: #1f2630;
  color: #e6edf3;
  box-shadow: inset 3px 0 0 #3fb950;
}
.da-sm__nav a:focus-visible {
  outline: 3px solid #58a6ff;
  outline-offset: 2px;
}
.da-sm__main:focus-visible {
  outline: 3px solid #58a6ff;
  outline-offset: -3px;
}
.da-sm__main {
  grid-area: main;
  display: grid;
  align-content: start;
  gap: 14px;
  padding: 18px 20px;
  overflow: auto;
  overscroll-behavior: contain;
}
.da-sm__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 6px 12px;
}
.da-sm__title {
  margin: 0;
  font-family: ui-monospace, Consolas, monospace;
  font-size: 17px;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: 0;
  color: #e6edf3;
}
.da-sm__live {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  color: #9ba6b2;
  font-size: 12.5px;
}
.da-sm__live i {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #3fb950;
}
.da-sm__tiles {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 150px), 1fr));
  gap: 10px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.da-sm__tile {
  position: relative;
  display: grid;
  gap: 2px;
  padding: 12px 12px 12px 36px;
  border: 1px solid #262c36;
  border-radius: 10px;
  background: #161b22;
}
.da-sm__tile::before {
  content: "";
  position: absolute;
  top: 14px;
  left: 12px;
  width: 14px;
  height: 14px;
}
.da-sm__tile b {
  font-family: ui-monospace, Consolas, monospace;
  font-size: 13px;
}
.da-sm__tile span {
  font-weight: 600;
}
.da-sm__tile small {
  color: #9ba6b2;
  font-size: 12px;
}
.da-sm__tile--ok span {
  color: #56d364;
}
.da-sm__tile--ok::before {
  border-radius: 50%;
  background: #3fb950;
}
.da-sm__tile--warn {
  border-color: #6e5618;
}
.da-sm__tile--warn span {
  color: #e3b341;
}
.da-sm__tile--warn::before {
  background: #d29922;
  clip-path: polygon(50% 0, 100% 100%, 0 100%);
}
.da-sm__tile--down {
  border-color: #7d2a26;
  background: #1f1416;
}
.da-sm__tile--down span {
  color: #ff7b72;
}
.da-sm__tile--down::before {
  background: #f85149;
  rotate: 45deg;
  scale: .8;
}
.da-sm__metrics {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 160px), 1fr));
  gap: 10px;
}
.da-sm__card {
  min-width: 0;
  padding: 12px 14px;
  border: 1px solid #262c36;
  border-radius: 10px;
  background: #161b22;
}
.da-sm__k {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 4px 10px;
  margin: 0 0 8px;
  color: #9ba6b2;
  font-size: 12.5px;
}
.da-sm__k b {
  color: #e6edf3;
  font-size: 15px;
  font-variant-numeric: tabular-nums;
}
.da-sm__spark {
  display: block;
  width: 100%;
  height: 40px;
  overflow: visible;
}
.da-sm__spark polyline {
  fill: none;
  stroke: #58a6ff;
  stroke-width: 2;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
.da-sm__spark--b polyline {
  stroke: #bc8cff;
}
.da-sm__spark--c polyline {
  stroke: #3fb950;
}
.da-sm__days {
  display: flex;
  gap: 2px;
  height: 26px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.da-sm__days li {
  flex: 1;
  border-radius: 2px;
  background: #3fb950;
}
.da-sm__days .da-sm__d--warn {
  background: #d29922;
}
.da-sm__small {
  margin: 8px 0 0;
  color: #9ba6b2;
  font-size: 12.5px;
}
.da-sm__h {
  margin: 0 0 8px;
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: 0;
  color: #e6edf3;
}
.da-sm__log {
  display: grid;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 13px;
}
.da-sm__log li {
  display: grid;
  grid-template-columns: 76px minmax(0, 1fr);
  gap: 10px;
}
.da-sm__log time {
  color: #9ba6b2;
  font-family: ui-monospace, Consolas, monospace;
  font-size: 12.5px;
}
.da-sm__sev {
  display: inline-block;
  margin-right: 8px;
  padding: 0 7px;
  border: 1px solid #3d444d;
  border-radius: 99px;
  color: #c9d1d9;
  font-size: 11.5px;
}
.da-sm__sev--down {
  border-color: #f85149;
  color: #ff7b72;
}
.da-sm__sev--warn {
  border-color: #d29922;
  color: #e3b341;
}
@media (prefers-reduced-motion: no-preference) {
  .da-sm__live i {
    animation: da-sm-pulse 2s ease-out infinite;
  }
}
@keyframes da-sm-pulse {
  0% {
    box-shadow: 0 0 0 0 rgba(63, 185, 80, .6);
  }
  100% {
    box-shadow: 0 0 0 8px rgba(63, 185, 80, 0);
  }
}
@container da-sm (max-width: 760px) {
  .da-sm__app {
    grid-template-columns: 64px minmax(0, 1fr);
  }
  .da-sm__side {
    align-items: center;
    padding: 18px 8px;
  }
  .da-sm__brand {
    padding: 0;
  }
  .da-sm__nav a {
    justify-content: center;
    width: 44px;
    min-height: 44px;
    padding: 0;
  }
  .da-sm__label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}
@container da-sm (max-width: 480px) {
  .da-sm__app {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
    grid-template-areas: "side" "main";
  }
  .da-sm__side {
    flex-direction: row;
    gap: 8px;
    padding: 6px 10px 6px 14px;
    border-right: 0;
    border-bottom: 1px solid #262c36;
  }
  .da-sm__nav {
    display: flex;
    gap: 4px;
    margin-left: auto;
  }
  .da-sm__nav a[aria-current="page"] {
    box-shadow: inset 0 -3px 0 #3fb950;
  }
  .da-sm__main {
    gap: 12px;
    padding: 14px;
  }
  .da-sm__tiles {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
  }
  .da-sm__tile {
    padding: 10px 10px 10px 30px;
  }
  .da-sm__tile::before {
    left: 10px;
    width: 12px;
    height: 12px;
  }
  .da-sm__tile b {
    font-size: 12px;
    overflow-wrap: anywhere;
  }
}

Dark trading dashboard

  • CSS candlesticks
  • order book depth
  • :has() buy and sell

NVLTNovalight Inc.

188.95+3.96 (+2.14%)

Open
184.99
High
189.42
Low
183.10
Volume
14.2M
Order book
NVLT order book, asks then bids
PriceSize
189.301,240
189.202,115
189.10806
189.052,590
Spread 0.10
188.952,340
188.901,460
188.802,995
188.70980
Watchlist
  • ORBXOrbix Systems72.18-1.04%
  • KSTLKestrel Air41.60+0.62%
  • BRNEBrine Energy18.07+3.31%
  • QMTXQuantix Labs256.40-0.27%
Order side

Estimated total$1,889.50

Switch the order ticket between Buy and Sell.

The candlestick chart is pure CSS: each candle is a list item with four custom properties, the wick is a ::before and the body an ::after, both positioned in percent of the chart height. The order ticket swaps color and label with :has() on the Buy and Sell radios, and uses dark text on the green and red buttons to keep the contrast above 4.5:1.

View code
.da-tr {
  container: da-tr / inline-size;
  width: 100%;
  color: #e8ecf3;
}
.da-tr__app {
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  height: 560px;
  overflow: hidden;
  border: 1px solid #1f2633;
  border-radius: 14px;
  background: #0b0e14;
  font-size: 13.5px;
  line-height: 1.4;
  font-variant-numeric: tabular-nums;
}
.da-tr__top {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 18px;
  padding: 12px 16px;
  border-bottom: 1px solid #1f2633;
}
.da-tr__sym,
.da-tr__px {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin: 0;
}
.da-tr__sym b {
  font-size: 17px;
}
.da-tr__sym span {
  color: #8a94a6;
}
.da-tr__px b {
  font-size: 19px;
}
.da-tr__up {
  color: #26a69a;
  font-style: normal;
}
.da-tr__dn {
  color: #ef6461;
  font-style: normal;
}
.da-tr__tf {
  display: flex;
  gap: 2px;
  margin-left: auto;
  padding: 2px;
  border-radius: 8px;
  background: #151b26;
}
.da-tr__tf button {
  min-width: 38px;
  min-height: 30px;
  border: 0;
  border-radius: 6px;
  background: none;
  color: #8a94a6;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
.da-tr__tf button[aria-pressed="true"] {
  background: #263043;
  color: #e8ecf3;
}
.da-tr__tf button:focus-visible,
.da-tr__go:focus-visible,
.da-tr__field input:focus-visible,
.da-tr__field select:focus-visible {
  outline: 2px solid #7aa7ff;
  outline-offset: 2px;
}
.da-tr__grid:focus-visible {
  outline: 2px solid #7aa7ff;
  outline-offset: -2px;
}
.da-tr__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 220px;
  grid-template-areas: "chart book" "watch ticket";
  align-content: start;
  gap: 10px;
  padding: 10px;
  overflow: auto;
  overscroll-behavior: contain;
}
.da-tr__panel {
  min-width: 0;
  padding: 12px 14px;
  border: 1px solid #1f2633;
  border-radius: 10px;
  background: #121722;
}
.da-tr__panel--chart {
  grid-area: chart;
}
.da-tr__panel--book {
  grid-area: book;
}
.da-tr__panel--watch {
  grid-area: watch;
}
.da-tr__panel--ticket {
  grid-area: ticket;
}
.da-tr__h {
  margin: 0 0 8px;
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: 0;
  color: #e8ecf3;
}
.da-tr__chart {
  position: relative;
  height: 210px;
  padding-right: 52px;
}
.da-tr__axis {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  margin: 0;
  padding: 0;
  list-style: none;
}
.da-tr__axis li {
  display: flex;
  justify-content: flex-end;
  border-top: 1px dashed #232b3a;
  color: #8a94a6;
  font-size: 11px;
  line-height: 0;
}
.da-tr__candles {
  position: relative;
  display: flex;
  gap: 3px;
  height: 100%;
  margin: 0;
  padding: 0;
  list-style: none;
}
.da-tr__candles li {
  position: relative;
  flex: 1;
  color: #26a69a;
}
.da-tr__candles .da-tr__c--dn {
  color: #ef6461;
}
.da-tr__candles li::before {
  content: "";
  position: absolute;
  left: calc(50% - .5px);
  bottom: calc(var(--da-l) * 1%);
  width: 1px;
  height: calc((var(--da-h) - var(--da-l)) * 1%);
  background: currentColor;
}
.da-tr__candles li::after {
  content: "";
  position: absolute;
  left: 12%;
  right: 12%;
  bottom: calc(var(--da-a) * 1%);
  height: max(2px, calc((var(--da-b) - var(--da-a)) * 1%));
  border-radius: 1px;
  background: currentColor;
}
.da-tr__ohlc {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 8px;
  margin: 12px 0 0;
}
.da-tr__ohlc dt {
  color: #8a94a6;
  font-size: 11.5px;
}
.da-tr__ohlc dd {
  margin: 0;
  font-weight: 600;
}
.da-tr__book {
  width: 100%;
  border-collapse: collapse;
  font-size: 12.5px;
}
.da-tr__book th {
  padding: 0 6px 6px;
  color: #8a94a6;
  font-size: 11.5px;
  font-weight: 500;
  text-align: left;
}
.da-tr__book th + th,
.da-tr__book td + td {
  text-align: right;
}
.da-tr__book td {
  position: relative;
  z-index: 0;
  padding: 4px 6px;
}
.da-tr__asks td:last-child::before,
.da-tr__bids td:last-child::before {
  content: "";
  position: absolute;
  top: 2px;
  bottom: 2px;
  right: 0;
  width: var(--da-d);
  border-radius: 2px;
  z-index: -1;
}
.da-tr__asks td:last-child::before {
  background: rgba(239, 100, 97, .16);
}
.da-tr__bids td:last-child::before {
  background: rgba(38, 166, 154, .16);
}
.da-tr__asks td:first-child {
  color: #ef6461;
}
.da-tr__bids td:first-child {
  color: #26a69a;
}
.da-tr__spread td {
  padding: 6px;
  border-block: 1px solid #1f2633;
  color: #8a94a6;
  text-align: center;
}
.da-tr__watch {
  display: grid;
  margin: 0;
  padding: 0;
  list-style: none;
}
.da-tr__watch li {
  display: grid;
  grid-template-columns: 52px minmax(0, 1fr) auto 64px;
  align-items: baseline;
  gap: 10px;
  padding: 7px 0;
  border-top: 1px solid #1a2130;
}
.da-tr__watch li:first-child {
  border-top: 0;
}
.da-tr__watch span {
  overflow: hidden;
  color: #8a94a6;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.da-tr__watch em {
  font-style: normal;
  font-weight: 600;
}
.da-tr__watch i {
  text-align: right;
}
.da-tr__side {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4px;
  margin: 0 0 10px;
  padding: 3px;
  border: 0;
  border-radius: 8px;
  background: #0b0e14;
}
.da-tr__side input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.da-tr__side label {
  display: grid;
  place-items: center;
  min-height: 34px;
  border-radius: 6px;
  color: #8a94a6;
  font-weight: 700;
  cursor: pointer;
}
.da-tr__side input:focus-visible + label {
  outline: 2px solid #7aa7ff;
  outline-offset: 1px;
}
#da-tr-buy:checked + label {
  background: #26a69a;
  color: #04110f;
}
#da-tr-sell:checked + label {
  background: #ef6461;
  color: #1a0605;
}
.da-tr__field {
  display: grid;
  gap: 4px;
  margin-bottom: 10px;
}
.da-tr__field label {
  color: #8a94a6;
  font-size: 12px;
}
.da-tr__field input,
.da-tr__field select {
  width: 100%;
  min-height: 36px;
  padding: 0 10px;
  border: 1px solid #263043;
  border-radius: 7px;
  background: #0b0e14;
  color: #e8ecf3;
  font: inherit;
}
.da-tr__est {
  display: flex;
  justify-content: space-between;
  margin: 0 0 10px;
  color: #8a94a6;
}
.da-tr__est b {
  color: #e8ecf3;
}
.da-tr__go {
  width: 100%;
  min-height: 44px;
  border: 0;
  border-radius: 8px;
  background: #26a69a;
  color: #04110f;
  font: inherit;
  font-weight: 700;
  cursor: pointer;
}
.da-tr__go-sell {
  display: none;
}
.da-tr:has(#da-tr-sell:checked) .da-tr__go {
  background: #ef6461;
  color: #1a0605;
}
.da-tr:has(#da-tr-sell:checked) .da-tr__go-buy {
  display: none;
}
.da-tr:has(#da-tr-sell:checked) .da-tr__go-sell {
  display: inline;
}
.da-tr__sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
@container da-tr (max-width: 600px) {
  .da-tr__grid {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "chart" "ticket" "book" "watch";
  }
  .da-tr__tf {
    margin-left: 0;
  }
  .da-tr__chart {
    height: 170px;
    padding-right: 46px;
  }
  .da-tr__candles {
    gap: 2px;
  }
  .da-tr__ohlc {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .da-tr__watch li {
    grid-template-columns: 48px minmax(0, 1fr) auto 58px;
    gap: 8px;
  }
}

Smart home control panel

  • conic-gradient gauge
  • role="switch"
  • :has() tile state

Living room

Inside 22.4 °C, outside 9 °C

Heating

Target temperature 21°C

Heating to target
Energy today

8.4 kWh12% less than yesterday

Peak between 18:00 and 20:00.

Raise the temperature or switch a device.

A wall-panel style dashboard. The thermostat ring is a 270 degree conic-gradient gauge driven by one custom property that a short script updates, and the reading sits in a role="status" element. Each device tile is a native checkbox with role="switch", and :has() recolors the whole tile when it is on.

View code
.da-sh {
  container: da-sh / inline-size;
  width: 100%;
  color: #2a2420;
}
.da-sh__app {
  display: grid;
  grid-template-columns: 190px minmax(0, 1fr);
  grid-template-areas: "side main";
  height: 560px;
  overflow: hidden;
  border-radius: 24px;
  background: #efe9df;
  box-shadow: 0 18px 40px rgba(60, 40, 20, .12);
  font-size: 14px;
  line-height: 1.4;
}
.da-sh__side {
  grid-area: side;
  display: flex;
  flex-direction: column;
  gap: 22px;
  padding: 20px 12px;
}
.da-sh__brand {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  padding: 0 8px;
  font-family: "Fraunces", Georgia, serif;
  font-size: 19px;
  font-weight: 600;
}
.da-sh__logo {
  flex: none;
  width: 26px;
  height: 26px;
  border-radius: 50% 50% 6px 6px;
  background: #b45309;
}
.da-sh__nav {
  display: grid;
  gap: 4px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.da-sh__nav a {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 44px;
  padding: 0 12px;
  border-radius: 14px;
  color: #5b5047;
  text-decoration: none;
}
.da-sh svg {
  flex: none;
  width: 22px;
  height: 22px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.da-sh__nav a:hover {
  background: #e6ddcf;
}
.da-sh__nav a[aria-current="page"] {
  background: #2a2420;
  color: #fffaf2;
}
.da-sh__nav a:focus-visible,
.da-sh__step:focus-visible {
  outline: 3px solid #b45309;
  outline-offset: 2px;
}
.da-sh__main:focus-visible {
  outline: 3px solid #b45309;
  outline-offset: -3px;
}
.da-sh__main {
  grid-area: main;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  grid-template-areas: "head head" "thermo devices" "energy energy";
  align-content: start;
  gap: 14px;
  padding: 20px 20px 20px 6px;
  overflow: auto;
  overscroll-behavior: contain;
}
.da-sh__head {
  grid-area: head;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 4px 12px;
}
.da-sh__title {
  margin: 0;
  font-family: "Fraunces", Georgia, serif;
  font-size: 26px;
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -.01em;
  color: #2a2420;
}
.da-sh__meta {
  margin: 0;
  color: #6b5e52;
  font-size: 13px;
}
.da-sh__card {
  min-width: 0;
  padding: 16px;
  border-radius: 20px;
  background: #fffaf2;
}
.da-sh__card--thermo {
  grid-area: thermo;
  display: grid;
  justify-items: center;
  gap: 10px;
}
.da-sh__card--energy {
  grid-area: energy;
}
.da-sh__h {
  justify-self: start;
  margin: 0;
  font-family: inherit;
  font-size: 14.5px;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: 0;
  color: #2a2420;
}
.da-sh__ring {
  position: relative;
  display: grid;
  place-items: center;
  width: min(170px, 100%);
  aspect-ratio: 1;
  border-radius: 50%;
  background: conic-gradient(from 225deg, #b45309 0 calc(var(--da-sh-p) * .75), #e9dfd0 0 75%, #fffaf2 0);
}
.da-sh__ring::before {
  content: "";
  position: absolute;
  inset: 14px;
  border-radius: 50%;
  background: #fffaf2;
}
.da-sh__read {
  position: relative;
  display: flex;
  align-items: flex-start;
  margin: 0;
  font-family: "Fraunces", Georgia, serif;
  font-size: 46px;
  font-weight: 600;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.da-sh__unit {
  margin-top: 6px;
  color: #6b5e52;
  font-size: 17px;
}
.da-sh__steps {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  color: #6b5e52;
  font-size: 12.5px;
  text-align: center;
}
.da-sh__step {
  display: grid;
  flex: none;
  place-items: center;
  width: 44px;
  height: 44px;
  border: 0;
  border-radius: 50%;
  background: #2a2420;
  color: #fffaf2;
  cursor: pointer;
}
.da-sh__step:hover {
  background: #4a3f37;
}
.da-sh__devices {
  grid-area: devices;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.da-sh__dev {
  position: relative;
  display: grid;
  align-content: space-between;
  gap: 4px;
  height: 100%;
  min-height: 112px;
  padding: 14px;
  border-radius: 18px;
  background: #fffaf2;
  color: #5b5047;
  cursor: pointer;
}
.da-sh__dev input {
  position: absolute;
  top: 14px;
  right: 14px;
  z-index: 1;
  width: 40px;
  height: 24px;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}
.da-sh__sw {
  position: absolute;
  top: 14px;
  right: 14px;
  width: 40px;
  height: 24px;
  border-radius: 12px;
  background: #cbbfae;
}
.da-sh__sw::after {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #fff;
}
.da-sh__dev input:checked + .da-sh__sw {
  background: #e08a2c;
}
.da-sh__dev input:checked + .da-sh__sw::after {
  translate: 16px 0;
}
.da-sh__dev input:focus-visible + .da-sh__sw {
  outline: 3px solid #b45309;
  outline-offset: 2px;
}
.da-sh__dev svg {
  width: 26px;
  height: 26px;
}
.da-sh__name {
  color: #2a2420;
  font-weight: 600;
}
.da-sh__on,
.da-sh__off {
  font-size: 12.5px;
}
.da-sh__dev .da-sh__on {
  display: none;
}
.da-sh__dev:has(input:checked) {
  background: #2a2420;
  color: #f2c48d;
}
.da-sh__dev:has(input:checked) .da-sh__name {
  color: #fffaf2;
}
.da-sh__dev:has(input:checked) .da-sh__on {
  display: block;
}
.da-sh__dev:has(input:checked) .da-sh__off {
  display: none;
}
.da-sh__kwh {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 10px;
  margin: 8px 0 12px;
  color: #6b5e52;
  font-size: 13px;
}
.da-sh__kwh b {
  color: #2a2420;
  font-size: 22px;
}
.da-sh__bars {
  display: flex;
  align-items: flex-end;
  gap: 6px;
  height: 70px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.da-sh__bars li {
  flex: 1;
  height: var(--da-v);
  border-radius: 6px 6px 2px 2px;
  background: #d9c7ad;
}
.da-sh__bars li:nth-child(9),
.da-sh__bars li:nth-child(10) {
  background: #b45309;
}
.da-sh__axis {
  display: flex;
  justify-content: space-between;
  margin: 6px 0 0;
  color: #6b5e52;
  font-size: 11px;
}
.da-sh__small {
  margin: 8px 0 0;
  color: #6b5e52;
  font-size: 12.5px;
}
.da-sh__sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
@media (prefers-reduced-motion: no-preference) {
  .da-sh__sw::after {
    transition: translate .2s ease;
  }
}
@container da-sh (max-width: 760px) {
  .da-sh__app {
    grid-template-columns: 72px minmax(0, 1fr);
  }
  .da-sh__side {
    align-items: center;
    padding: 20px 10px;
  }
  .da-sh__brand {
    padding: 0;
  }
  .da-sh__nav a {
    justify-content: center;
    width: 48px;
    min-height: 48px;
    padding: 0;
  }
  .da-sh__label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}
@container da-sh (max-width: 600px) {
  .da-sh__main {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "head" "thermo" "devices" "energy";
  }
}
@container da-sh (max-width: 480px) {
  .da-sh__app {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
    grid-template-areas: "side" "main";
  }
  .da-sh__side {
    flex-direction: row;
    gap: 8px;
    padding: 8px 10px 4px 16px;
  }
  .da-sh__nav {
    display: flex;
    gap: 2px;
    margin-left: auto;
  }
  .da-sh__nav a {
    width: 44px;
    min-height: 44px;
  }
  .da-sh__main {
    gap: 12px;
    padding: 10px 14px 16px;
  }
  .da-sh__title {
    font-size: 22px;
  }
  .da-sh__dev {
    min-height: 100px;
    padding: 12px;
  }
  .da-sh__dev input,
  .da-sh__sw {
    top: 12px;
    right: 12px;
  }
}

Fitness tracker app

  • nested conic rings
  • phone layout
  • bottom tab bar

Today

Tue, Oct 27

  • Move420/600 kcal
  • Exercise24/30 min
  • Stand9/12 h

Steps

8,412

84% of 10,000

Heart rate

72 bpm

Resting 58 bpm

This week

  1. Mon6.2k
  2. Tue9.1k
  3. Wed4.8k
  4. Thu10.4k
  5. Fri7.9k
  6. Sat5.6k
  7. Sun8.4k

Workouts

  • Morning run5.2 km, 28:40312 kcal
  • Yoga flow30 min96 kcal

A phone-sized activity dashboard. The three rings are nested elements, each a hard-stop conic-gradient with a solid inner gap, and the legend beside them repeats every goal as text. The frame is a three-row grid, so the header and the tab bar stay fixed while only the middle scrolls.

View code
.da-ft {
  container: da-ft / inline-size;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
  height: 100%;
  background: #f4f5ef;
  color: #16181d;
  font-size: 14px;
  line-height: 1.4;
}
.da-ft__top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding: 10px 18px 8px;
}
.da-ft__title {
  margin: 0;
  font-family: inherit;
  font-size: 28px;
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: -.02em;
  color: #16181d;
}
.da-ft__date {
  margin: 0;
  color: #555a63;
  font-size: 13px;
}
.da-ft__scroll {
  display: grid;
  align-content: start;
  gap: 10px;
  padding: 4px 14px 14px;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.da-ft__scroll:focus-visible {
  outline: 3px solid #0a7bd6;
  outline-offset: -3px;
}
.da-ft__card {
  min-width: 0;
  padding: 14px;
  border-radius: 18px;
  background: #fff;
}
.da-ft__card--rings {
  display: flex;
  align-items: center;
  gap: 16px;
}
.da-ft__ring {
  box-sizing: border-box;
  flex: none;
  padding: 11px;
  border-radius: 50%;
  background: conic-gradient(var(--da-c) var(--da-p), #e7e8e2 0);
}
.da-ft__card--rings > .da-ft__ring {
  width: 132px;
  aspect-ratio: 1;
}
.da-ft__gap {
  box-sizing: border-box;
  height: 100%;
  padding: 3px;
  border-radius: 50%;
  background: #fff;
}
.da-ft__gap > .da-ft__ring {
  height: 100%;
}
.da-ft__core {
  height: 100%;
  border-radius: 50%;
  background: #fff;
}
.da-ft__legend {
  display: grid;
  gap: 10px;
  min-width: 0;
  margin: 0;
  padding: 0;
  list-style: none;
}
.da-ft__legend li {
  display: grid;
  padding-left: 12px;
  border-left: 4px solid var(--da-c);
}
.da-ft__legend span {
  color: #555a63;
  font-size: 12.5px;
}
.da-ft__legend b {
  font-size: 15px;
  font-variant-numeric: tabular-nums;
}
.da-ft__pair {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}
.da-ft__k {
  margin: 0;
  color: #555a63;
  font-size: 12.5px;
  font-weight: 600;
}
.da-ft__v {
  margin: 2px 0 8px;
  font-size: 24px;
  font-weight: 800;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.da-ft__v small {
  color: #555a63;
  font-size: 13px;
  font-weight: 600;
}
.da-ft__bar {
  height: 8px;
  margin: 0;
  overflow: hidden;
  border-radius: 4px;
  background: #e7e8e2;
}
.da-ft__bar i {
  display: block;
  width: var(--da-v);
  height: 100%;
  border-radius: 4px;
  background: #3f9142;
}
.da-ft__hr {
  display: block;
  width: 100%;
  height: 26px;
}
.da-ft__hr polyline {
  fill: none;
  stroke: #e5484d;
  stroke-width: 2;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
.da-ft__s {
  margin: 6px 0 0;
  color: #555a63;
  font-size: 12px;
}
.da-ft__week {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 6px;
  height: 120px;
  margin: 10px 0 0;
  padding: 0;
  list-style: none;
}
.da-ft__week li {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: center;
  gap: 4px;
}
.da-ft__week i {
  width: 100%;
  max-width: 22px;
  height: calc(var(--da-v) * .62);
  border-radius: 6px;
  background: #c9d7c6;
}
.da-ft__week .da-ft__today i {
  background: #3f9142;
}
.da-ft__week span {
  color: #555a63;
  font-size: 11px;
}
.da-ft__week b {
  font-size: 10.5px;
  font-variant-numeric: tabular-nums;
}
.da-ft__list {
  display: grid;
  margin: 8px 0 0;
  padding: 0;
  list-style: none;
}
.da-ft__list li {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 0;
  border-top: 1px solid #eeefe9;
}
.da-ft__list li:first-child {
  border-top: 0;
}
.da-ft__list span:not(.da-ft__dot) {
  display: grid;
  flex: 1;
  font-weight: 600;
}
.da-ft__list small {
  color: #555a63;
  font-size: 12px;
  font-weight: 400;
}
.da-ft__dot {
  flex: none;
  width: 34px;
  height: 34px;
  border-radius: 11px;
  background: #fde2e3;
  box-shadow: inset 0 0 0 11px #fde2e3, inset 0 0 0 17px #e5484d;
}
.da-ft__dot--b {
  background: #dcebfa;
  box-shadow: inset 0 0 0 11px #dcebfa, inset 0 0 0 17px #0a7bd6;
}
.da-ft__tabs {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  padding: 6px 6px 10px;
  border-top: 1px solid #e3e4dd;
  background: #fff;
}
.da-ft__tabs a {
  display: grid;
  justify-items: center;
  gap: 2px;
  min-height: 48px;
  padding-top: 4px;
  border-radius: 12px;
  color: #555a63;
  font-size: 11.5px;
  font-weight: 600;
  text-decoration: none;
}
.da-ft__tabs svg {
  width: 22px;
  height: 22px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.da-ft__tabs a[aria-current="page"] {
  color: #b4232a;
}
.da-ft__tabs a:focus-visible {
  outline: 3px solid #0a7bd6;
  outline-offset: -3px;
}
@container da-ft (max-width: 330px) {
  .da-ft__card--rings > .da-ft__ring {
    width: 112px;
    padding: 9px;
  }
  .da-ft__ring {
    padding: 9px;
  }
  .da-ft__legend b {
    font-size: 13.5px;
  }
}
@container da-ft (min-width: 560px) {
  .da-ft__scroll {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .da-ft__card--rings {
    grid-column: 1 / -1;
  }
}

Dashboard layout techniques

The building blocks behind the templates above, isolated so you can see each one work: named grid areas, a resizable frame driving container queries, a collapsible sidebar with aria-expanded, and a settings page inside the shell.

grid-template-areas skeleton, explained

  • grid-template-areas
  • container queries
  • :has() width picker
Frame width
headerSearch, account
sidebarNavigation
mainminmax(0, 1fr) stops a wide table from stretching this track
asideActivity feed
footerStatus bar
grid-template-columns: 150px minmax(0, 1fr) 170px;
grid-template-areas:
  "header  header header"
  "sidebar main   aside"
  "sidebar footer footer";grid-template-columns: 64px minmax(0, 1fr);
grid-template-areas:
  "header  header"
  "sidebar main"
  "sidebar aside"
  "sidebar footer";grid-template-columns: minmax(0, 1fr);
grid-template-areas:
  "header"
  "sidebar"
  "main"
  "aside"
  "footer";

Pick a frame width and watch the areas move.

The whole layout is written once as named areas on the frame, and each container query only rewrites grid-template-areas and the track sizes. The code panel inside the frame shows the rule that is active at that width. On a phone all three widths fall under the narrow query, so the picker matters most on a wide screen.

View code
.da-ga {
  display: grid;
  justify-items: center;
  gap: 14px;
  width: 100%;
  color: #1e1b4b;
  font-size: 14px;
  line-height: 1.4;
}
.da-ga__pick {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 6px;
  margin: 0;
  padding: 0;
  border: 0;
}
.da-ga__pick legend {
  float: left;
  margin-right: 6px;
  color: #3f3d6b;
  font-weight: 600;
}
.da-ga__pick input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.da-ga__pick label {
  display: inline-flex;
  align-items: center;
  min-height: 36px;
  padding: 0 14px;
  border: 1px solid #c7c5e6;
  border-radius: 99px;
  background: #fff;
  color: #3f3d6b;
  font-weight: 500;
  cursor: pointer;
}
.da-ga__pick input:checked + label {
  border-color: #4338ca;
  background: #4338ca;
  color: #fff;
}
.da-ga__pick input:focus-visible + label {
  outline: 3px solid #4338ca;
  outline-offset: 2px;
}
.da-ga__frame {
  container: da-ga / inline-size;
  width: 100%;
  max-width: 100%;
  padding: 10px;
  border: 1px solid #d9d7ef;
  border-radius: 16px;
  background: #fff;
  box-sizing: border-box;
}
.da-ga:has(#da-ga-mid:checked) .da-ga__frame {
  width: min(520px, 100%);
}
.da-ga:has(#da-ga-narrow:checked) .da-ga__frame {
  width: min(320px, 100%);
}
.da-ga__grid {
  display: grid;
  grid-template-columns: 150px minmax(0, 1fr) 170px;
  grid-template-rows: auto minmax(0, 1fr) auto;
  grid-template-areas:
    "header  header header"
    "sidebar main   aside"
    "sidebar footer footer";
  gap: 8px;
  height: 330px;
}
.da-ga__area {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
  min-height: 0;
  padding: 10px 12px;
  overflow: hidden;
  border: 2px dashed #4338ca;
  border-radius: 10px;
}
.da-ga__area code {
  color: #1e1b4b;
  font-family: ui-monospace, Consolas, monospace;
  font-size: 13px;
  font-weight: 700;
}
.da-ga__area span {
  color: #3f3d6b;
  font-size: 12.5px;
}
.da-ga__area--head {
  grid-area: header;
  flex-direction: row;
  align-items: baseline;
  justify-content: space-between;
  background: #e0e7ff;
}
.da-ga__area--side {
  grid-area: sidebar;
  background: #ffe8cc;
  border-color: #b45309;
}
.da-ga__area--main {
  grid-area: main;
  justify-content: center;
  background: #fff;
  border-color: #1e1b4b;
}
.da-ga__area--aside {
  grid-area: aside;
  background: #d9f2e6;
  border-color: #15803d;
}
.da-ga__area--foot {
  grid-area: footer;
  flex-direction: row;
  align-items: baseline;
  justify-content: space-between;
  background: #ede9fe;
  border-color: #6d28d9;
}
.da-ga__code {
  margin: 10px 0 0;
  padding: 12px 14px;
  overflow-x: auto;
  border-radius: 10px;
  background: #1e1b4b;
  color: #e0e7ff;
  font-family: ui-monospace, Consolas, monospace;
  font-size: 12.5px;
  line-height: 1.5;
}
.da-ga__code:focus-visible {
  outline: 3px solid #4338ca;
  outline-offset: 2px;
}
.da-ga__c {
  display: none;
  font: inherit;
}
.da-ga__c--wide {
  display: block;
}
@media (prefers-reduced-motion: no-preference) {
  .da-ga__frame {
    transition: width .35s ease;
  }
}
@container da-ga (max-width: 600px) {
  .da-ga__grid {
    grid-template-columns: 64px minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr) auto auto;
    grid-template-areas:
      "header  header"
      "sidebar main"
      "sidebar aside"
      "sidebar footer";
  }
  .da-ga__area--side span {
    display: none;
  }
  .da-ga__area--side code {
    writing-mode: vertical-rl;
  }
  .da-ga__c--wide {
    display: none;
  }
  .da-ga__c--mid {
    display: block;
  }
}
@container da-ga (max-width: 420px) {
  .da-ga__grid {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto auto minmax(0, 1fr) auto auto;
    grid-template-areas: "header" "sidebar" "main" "aside" "footer";
  }
  .da-ga__area {
    padding: 7px 10px;
  }
  .da-ga__area--side {
    flex-direction: row;
  }
  .da-ga__area--side code {
    writing-mode: horizontal-tb;
  }
  .da-ga__area--aside span,
  .da-ga__area--head span,
  .da-ga__area--foot span {
    display: none;
  }
  .da-ga__c--mid {
    display: none;
  }
  .da-ga__c--narrow {
    display: block;
  }
}

Resizable widget grid

  • resize: horizontal
  • nested container queries
  • auto-fill widgets
  • Revenue this month

    $84,210

    +9.6% vs September

  • Orders

    1,026

    +4.1%

  • Refund rate

    1.8%

    -0.3 pts

  • Low stock items

    7

    3 sell out this week

  • Revenue by region

    • Europe$36.2k
    • North America$26.1k
    • Asia Pacific$14.0k
    • Other$7.9k

Drag the bottom-right corner of the frame, or use the slider.

The frame has resize: horizontal, so you can drag it narrower and watch two levels of container queries react: the frame decides sidebar, rail or top bar, and each widget is its own container that switches between a detailed and a compact layout. Touch screens do not show the resize handle, which is why the slider sets the same width.

View code
.da-rz {
  display: grid;
  gap: 12px;
  width: 100%;
  color: #1e293b;
  font-size: 14px;
  line-height: 1.4;
}
.da-rz__bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 12px;
  color: #334155;
  font-weight: 600;
}
.da-rz__range {
  flex: 1 1 160px;
  min-width: 0;
  min-height: 24px;
  accent-color: #047857;
}
.da-rz__range:focus-visible {
  outline: 3px solid #047857;
  outline-offset: 2px;
}
.da-rz__out {
  min-width: 52px;
  color: #475569;
  font-family: ui-monospace, Consolas, monospace;
  font-size: 13px;
  font-weight: 400;
}
.da-rz__frame {
  container: da-rz / inline-size;
  width: 100%;
  min-width: 260px;
  max-width: 100%;
  height: 480px;
  overflow: hidden;
  resize: horizontal;
  border: 1px solid #cbd5e1;
  border-radius: 14px;
  background: #fff;
  box-shadow: 0 14px 34px rgba(15, 23, 42, .08);
  box-sizing: border-box;
}
.da-rz__app {
  display: grid;
  grid-template-columns: 170px minmax(0, 1fr);
  grid-template-areas: "side main";
  height: 100%;
}
.da-rz__side {
  grid-area: side;
  display: flex;
  flex-direction: column;
  gap: 20px;
  padding: 16px 10px;
  background: #1e293b;
}
.da-rz__brand {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  padding: 0 8px;
  color: #fff;
  font-weight: 700;
}
.da-rz__logo {
  flex: none;
  width: 22px;
  height: 22px;
  border-radius: 4px;
  background: #34d399;
  box-shadow: inset 0 -8px 0 #047857;
}
.da-rz__nav {
  display: grid;
  gap: 4px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.da-rz__nav a {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 40px;
  padding: 0 10px;
  border-radius: 8px;
  color: #cbd5e1;
  text-decoration: none;
}
.da-rz__nav svg {
  flex: none;
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.da-rz__nav a:hover {
  background: #334155;
  color: #fff;
}
.da-rz__nav a[aria-current="page"] {
  background: #f1f5f9;
  color: #0f172a;
  font-weight: 600;
}
.da-rz__nav a:focus-visible {
  outline: 3px solid #34d399;
  outline-offset: 2px;
}
.da-rz__main {
  grid-area: main;
  padding: 16px;
  overflow: auto;
  overscroll-behavior: contain;
  background: #f8fafc;
}
.da-rz__main:focus-visible {
  outline: 3px solid #047857;
  outline-offset: -3px;
}
.da-rz__widgets {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 150px), 1fr));
  grid-auto-flow: dense;
  gap: 10px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.da-rz__w {
  container: da-rz-w / inline-size;
  min-width: 0;
  border: 1px solid #e2e8f0;
  border-radius: 12px;
  background: #fff;
}
.da-rz__in {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 2px;
  padding: 12px 14px;
}
.da-rz__k {
  margin: 0;
  color: #475569;
  font-size: 12.5px;
  font-weight: 600;
}
.da-rz__v {
  margin: 0;
  font-size: 22px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.da-rz__d {
  margin: 0;
  color: #047857;
  font-size: 12.5px;
  font-weight: 600;
}
.da-rz__d--good {
  color: #047857;
}
.da-rz__d--warn {
  color: #a16207;
}
.da-rz__bars {
  display: flex;
  align-items: flex-end;
  gap: 4px;
  height: 54px;
  margin: 8px 0 0;
  padding: 0;
  list-style: none;
}
.da-rz__bars li {
  flex: 1;
  height: var(--da-v);
  border-radius: 3px 3px 0 0;
  background: #a7f3d0;
}
.da-rz__bars li:last-child {
  background: #047857;
}
.da-rz__regions {
  display: grid;
  gap: 8px;
  margin: 8px 0 0;
  padding: 0;
  list-style: none;
  font-size: 13px;
}
.da-rz__regions li {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 4px 8px;
}
.da-rz__regions b {
  font-variant-numeric: tabular-nums;
}
.da-rz__regions i {
  flex-basis: 100%;
  height: 6px;
  overflow: hidden;
  border-radius: 3px;
  background: #e2e8f0;
}
.da-rz__regions i::before {
  content: "";
  display: block;
  width: var(--da-v);
  height: 100%;
  background: #047857;
}
@container da-rz-w (min-width: 300px) {
  .da-rz__w--wide .da-rz__in {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr);
    align-items: end;
    column-gap: 16px;
  }
  .da-rz__w--wide .da-rz__k,
  .da-rz__w--wide .da-rz__v,
  .da-rz__w--wide .da-rz__d {
    grid-column: 1;
  }
  .da-rz__w--wide .da-rz__bars,
  .da-rz__w--wide .da-rz__regions {
    grid-column: 2;
    grid-row: 1 / span 3;
    margin: 0;
  }
}
@container da-rz-w (max-width: 170px) {
  .da-rz__v {
    font-size: 19px;
  }
  .da-rz__d {
    font-size: 11.5px;
  }
}
@container da-rz (min-width: 500px) {
  .da-rz__w--wide {
    grid-column: span 2;
  }
}
@container da-rz (max-width: 640px) {
  .da-rz__app {
    grid-template-columns: 60px minmax(0, 1fr);
  }
  .da-rz__side {
    align-items: center;
    padding: 16px 8px;
  }
  .da-rz__brand {
    padding: 0;
  }
  .da-rz__nav a {
    justify-content: center;
    width: 44px;
    min-height: 44px;
    padding: 0;
  }
  .da-rz__label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}
@container da-rz (max-width: 440px) {
  .da-rz__app {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
    grid-template-areas: "side" "main";
  }
  .da-rz__side {
    flex-direction: row;
    gap: 8px;
    padding: 6px 10px 6px 14px;
  }
  .da-rz__nav {
    display: flex;
    gap: 2px;
    margin-left: auto;
  }
  .da-rz__nav a {
    width: 40px;
    min-height: 40px;
  }
  .da-rz__main {
    padding: 12px;
  }
}

Collapsible sidebar with aria-expanded

  • aria-expanded
  • grid track transition
  • focus tooltips

Releases

  • v4.12.0Live

    Bulk export for audit logs, faster search on large workspaces.

    Shipped Oct 26 by Daniel Lind
  • v4.11.2Patch

    Fixes the double toast after saving a view.

    Shipped Oct 21 by Ana Jovic
  • v4.11.0Minor

    Saved filters and a new keyboard shortcut sheet.

    Shipped Oct 14 by Priya Shah
  • v4.10.0Minor

    Dark theme for charts and tables.

    Shipped Oct 2 by Mara Okafor

Use the panel button at the top of the sidebar.

One button with aria-expanded and aria-controls collapses the sidebar to an icon rail, and the grid column animates because grid-template-columns is interpolable in current browsers. Collapsed links keep their names for assistive tech, and the same label reappears as a tooltip on hover and keyboard focus. In a narrow frame the same button hides the nav row under the top bar.

View code
.da-cs {
  container: da-cs / inline-size;
  width: 100%;
  color: #18181b;
}
.da-cs__app {
  display: grid;
  grid-template-columns: 200px minmax(0, 1fr);
  grid-template-areas: "side main";
  height: 560px;
  overflow: hidden;
  border-radius: 16px;
  background: #fafaf9;
  box-shadow: 0 18px 40px rgba(24, 24, 27, .12);
  font-size: 14px;
  line-height: 1.4;
}
.da-cs__app:has(.da-cs__nav--collapsed) {
  grid-template-columns: 68px minmax(0, 1fr);
}
.da-cs__side {
  grid-area: side;
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: 18px;
  min-width: 0;
  padding: 16px 12px;
  background: #18181b;
  color: #d4d4d8;
}
.da-cs__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.da-cs__brand {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
  margin: 0;
  padding-left: 8px;
  color: #fff;
  font-weight: 700;
  white-space: nowrap;
}
.da-cs__logo {
  flex: none;
  width: 22px;
  height: 22px;
  border-radius: 6px;
  background: #a3e635;
  box-shadow: inset 7px 7px 0 #18181b;
}
.da-cs__toggle {
  display: grid;
  flex: none;
  place-items: center;
  width: 40px;
  height: 40px;
  border: 1px solid #3f3f46;
  border-radius: 10px;
  background: #27272a;
  color: #fafafa;
  cursor: pointer;
}
.da-cs__toggle:hover {
  background: #3f3f46;
}
.da-cs svg {
  flex: none;
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.da-cs__toggle[aria-expanded="false"] svg {
  scale: -1 1;
}
.da-cs__nav {
  display: grid;
  gap: 4px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.da-cs__nav a {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 42px;
  padding: 0 12px;
  border-radius: 10px;
  color: #d4d4d8;
  text-decoration: none;
  white-space: nowrap;
}
.da-cs__nav a:hover {
  background: #27272a;
  color: #fff;
}
.da-cs__nav a[aria-current="page"] {
  background: #27272a;
  color: #fff;
  box-shadow: inset 3px 0 0 #a3e635;
}
.da-cs__toggle:focus-visible,
.da-cs__nav a:focus-visible {
  outline: 3px solid #a3e635;
  outline-offset: 2px;
}
.da-cs__nav--collapsed a {
  justify-content: center;
  width: 44px;
  min-height: 44px;
  padding: 0;
}
.da-cs__nav--collapsed .da-cs__label,
.da-cs__sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.da-cs__nav--collapsed a:hover .da-cs__label,
.da-cs__nav--collapsed a:focus-visible .da-cs__label {
  top: 50%;
  left: calc(100% + 14px);
  width: auto;
  height: auto;
  padding: 5px 10px;
  overflow: visible;
  clip-path: none;
  border-radius: 7px;
  background: #fafafa;
  color: #18181b;
  font-size: 13px;
  font-weight: 600;
  translate: 0 -50%;
  box-shadow: 0 6px 18px rgba(0, 0, 0, .2);
}
.da-cs__app:has(.da-cs__nav--collapsed) .da-cs__side {
  align-items: center;
  padding: 16px 12px;
}
.da-cs__app:has(.da-cs__nav--collapsed) .da-cs__row {
  flex-direction: column;
}
.da-cs__app:has(.da-cs__nav--collapsed) .da-cs__brand {
  padding: 0;
}
.da-cs__app:has(.da-cs__nav--collapsed) .da-cs__name {
  display: none;
}
.da-cs__main {
  grid-area: main;
  min-width: 0;
  padding: 22px;
  overflow: auto;
  overscroll-behavior: contain;
}
.da-cs__main:focus-visible {
  outline: 3px solid #4d7c0f;
  outline-offset: -3px;
}
.da-cs__title {
  margin: 0 0 14px;
  font-family: inherit;
  font-size: 22px;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -.01em;
  color: #18181b;
}
.da-cs__list {
  display: grid;
  gap: 10px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.da-cs__list li {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: 4px 10px;
  padding: 14px 16px;
  border: 1px solid #e7e5e4;
  border-radius: 12px;
  background: #fff;
}
.da-cs__list b {
  font-family: ui-monospace, Consolas, monospace;
  font-size: 14px;
}
.da-cs__list p,
.da-cs__list small {
  grid-column: 1 / -1;
  margin: 0;
}
.da-cs__list small {
  color: #57534e;
  font-size: 12.5px;
}
.da-cs__tag {
  justify-self: start;
  padding: 1px 8px;
  border-radius: 99px;
  background: #f5f5f4;
  color: #44403c;
  font-size: 12px;
  font-weight: 600;
}
.da-cs__tag--live {
  background: #ecfccb;
  color: #3f6212;
}
@media (prefers-reduced-motion: no-preference) {
  .da-cs__app {
    transition: grid-template-columns .25s ease;
  }
}
@container da-cs (max-width: 480px) {
  .da-cs__app,
  .da-cs__app:has(.da-cs__nav--collapsed) {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
    grid-template-areas: "side" "main";
  }
  .da-cs__side,
  .da-cs__app:has(.da-cs__nav--collapsed) .da-cs__side {
    align-items: stretch;
    gap: 10px;
    padding: 10px 12px;
  }
  .da-cs__app:has(.da-cs__nav--collapsed) .da-cs__row {
    flex-direction: row;
  }
  .da-cs__app:has(.da-cs__nav--collapsed) .da-cs__brand {
    padding-left: 4px;
  }
  .da-cs__app:has(.da-cs__nav--collapsed) .da-cs__name {
    display: inline;
  }
  .da-cs__nav {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .da-cs__nav.da-cs__nav--collapsed {
    display: none;
  }
  .da-cs__main {
    padding: 16px 14px;
  }
}

Settings page in a dashboard shell

  • two-level containers
  • sticky save bar
  • role="switch"

Settings

Profile

How you appear to teammates in this workspace.

Email notifications

Edit a field and press Save changes.

A settings screen with a second navigation level. The outer container collapses the app sidebar, and the settings panel is its own container that moves labels from a left column to above the fields when it gets narrow. The save bar is sticky to the bottom of the scrolling region, and the form only reports a demo message.

View code
.da-st {
  container: da-st / inline-size;
  width: 100%;
  color: #1c1917;
}
.da-st__app {
  display: grid;
  grid-template-columns: 190px minmax(0, 1fr);
  grid-template-areas: "side main";
  height: 560px;
  overflow: hidden;
  border: 1px solid #e7e5e4;
  border-radius: 16px;
  background: #fff;
  box-shadow: 0 18px 40px rgba(28, 25, 23, .08);
  font-size: 14px;
  line-height: 1.4;
}
.da-st__side {
  grid-area: side;
  display: flex;
  flex-direction: column;
  gap: 22px;
  padding: 18px 12px;
  border-right: 1px solid #f0eeec;
  background: #fafaf9;
}
.da-st__brand {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  padding: 0 8px;
  font-weight: 700;
}
.da-st__logo {
  display: grid;
  flex: none;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 8px;
  background: #be123c;
  color: #fff;
  font-family: "Fraunces", Georgia, serif;
}
.da-st__nav {
  display: grid;
  gap: 4px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.da-st__nav a {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 40px;
  padding: 0 10px;
  border-radius: 10px;
  color: #57534e;
  text-decoration: none;
}
.da-st__nav svg {
  flex: none;
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.da-st__nav a:hover {
  background: #f5f5f4;
}
.da-st__nav a[aria-current="page"] {
  background: #ffe4e8;
  color: #9f1239;
  font-weight: 600;
}
.da-st__nav a:focus-visible,
.da-st__tabs a:focus-visible,
.da-st__btn:focus-visible {
  outline: 3px solid #be123c;
  outline-offset: 2px;
}
.da-st__main {
  grid-area: main;
  min-width: 0;
  overflow: auto;
  overscroll-behavior: contain;
}
.da-st__title {
  margin: 0;
  padding: 20px 22px 10px;
  font-family: inherit;
  font-size: 22px;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -.01em;
  color: #1c1917;
}
.da-st__tabs {
  display: flex;
  gap: 4px;
  margin: 0;
  padding: 0 22px;
  overflow-x: auto;
  border-bottom: 1px solid #e7e5e4;
  list-style: none;
}
.da-st__tabs a {
  display: inline-flex;
  align-items: center;
  min-height: 40px;
  padding: 0 12px;
  border-bottom: 2px solid transparent;
  color: #57534e;
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
}
.da-st__tabs a:hover {
  color: #1c1917;
}
.da-st__tabs a[aria-current="page"] {
  border-bottom-color: #be123c;
  color: #9f1239;
  font-weight: 600;
}
.da-st__panel {
  container: da-st-panel / inline-size;
  display: grid;
  gap: 8px;
  padding: 8px 22px 16px;
}
.da-st__section {
  display: grid;
  gap: 12px;
  padding: 16px 0;
  border-bottom: 1px solid #f0eeec;
}
.da-st__section:last-child {
  border-bottom: 0;
}
.da-st__h {
  margin: 0;
  font-family: inherit;
  font-size: 15.5px;
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: 0;
  color: #1c1917;
}
.da-st__help {
  margin: -8px 0 4px;
  color: #57534e;
  font-size: 13px;
}
.da-st__row {
  display: grid;
  grid-template-columns: 150px minmax(0, 1fr);
  align-items: center;
  gap: 6px 16px;
}
.da-st__row label {
  color: #44403c;
  font-weight: 600;
}
.da-st__row input,
.da-st__row select,
.da-st__row textarea {
  width: 100%;
  max-width: 420px;
  min-height: 40px;
  padding: 8px 12px;
  border: 1px solid #d6d3d1;
  border-radius: 9px;
  background: #fff;
  color: #1c1917;
  font: inherit;
  box-sizing: border-box;
}
.da-st__row textarea {
  resize: vertical;
}
.da-st__row input:focus-visible,
.da-st__row select:focus-visible,
.da-st__row textarea:focus-visible {
  border-color: #be123c;
  outline: 3px solid #fecdd3;
  outline-offset: 0;
}
.da-st__switch {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  max-width: 586px;
  cursor: pointer;
}
.da-st__switch span {
  display: grid;
  font-weight: 600;
}
.da-st__switch small {
  color: #57534e;
  font-size: 12.5px;
  font-weight: 400;
}
.da-st__switch input {
  position: absolute;
  right: 0;
  width: 44px;
  height: 26px;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}
.da-st__switch i {
  position: relative;
  flex: none;
  width: 44px;
  height: 26px;
  border-radius: 13px;
  background: #a8a29e;
}
.da-st__switch i::after {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: #fff;
}
.da-st__switch input:checked + i {
  background: #be123c;
}
.da-st__switch input:checked + i::after {
  translate: 18px 0;
}
.da-st__switch input:focus-visible + i {
  outline: 3px solid #be123c;
  outline-offset: 2px;
}
.da-st__save {
  position: sticky;
  bottom: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
  padding: 12px 22px;
  border-top: 1px solid #e7e5e4;
  background: #fff;
}
.da-st__status {
  margin: 0 auto 0 0;
  color: #57534e;
  font-size: 13px;
}
.da-st__btn {
  min-height: 42px;
  padding: 0 18px;
  border: 0;
  border-radius: 10px;
  background: #be123c;
  color: #fff;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
.da-st__btn:hover {
  background: #9f1239;
}
.da-st__btn--ghost {
  border: 1px solid #d6d3d1;
  background: #fff;
  color: #1c1917;
}
.da-st__btn--ghost:hover {
  background: #f5f5f4;
}
@media (prefers-reduced-motion: no-preference) {
  .da-st__switch i::after {
    transition: translate .2s ease;
  }
}
@container da-st-panel (max-width: 500px) {
  .da-st__row {
    grid-template-columns: minmax(0, 1fr);
  }
  .da-st__row input,
  .da-st__row select,
  .da-st__row textarea {
    max-width: none;
  }
}
@container da-st (max-width: 760px) {
  .da-st__app {
    grid-template-columns: 68px minmax(0, 1fr);
  }
  .da-st__side {
    align-items: center;
    padding: 18px 10px;
  }
  .da-st__brand {
    padding: 0;
  }
  .da-st__nav a {
    justify-content: center;
    width: 44px;
    min-height: 44px;
    padding: 0;
  }
  .da-st__label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}
@container da-st (max-width: 480px) {
  .da-st__app {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
    grid-template-areas: "side" "main";
  }
  .da-st__side {
    flex-direction: row;
    gap: 8px;
    padding: 8px 10px 8px 14px;
    border-right: 0;
    border-bottom: 1px solid #f0eeec;
  }
  .da-st__nav {
    display: flex;
    gap: 4px;
    margin-left: auto;
  }
  .da-st__nav a {
    width: 42px;
    min-height: 42px;
  }
  .da-st__title {
    padding: 14px 14px 6px;
    font-size: 19px;
  }
  .da-st__tabs {
    padding: 0 8px;
  }
  .da-st__panel {
    padding: 4px 14px 12px;
  }
  .da-st__save {
    padding: 10px 14px;
  }
  .da-st__status {
    flex-basis: 100%;
  }
}

What Is a CSS Dashboard?

Take the data away and what’s left is one page split into named regions. Navigation, KPI cards, tables and chart containers all sit in those regions, positioned with CSS Grid, Flexbox and custom properties.

The stylesheet decides layout, theme and responsive behavior. The HTML stays plain, and the data comes from wherever the project already keeps it.

Most dashboards end up with the same skeleton. The header carries search and account controls, and the sidebar holds navigation. Everything else lives in the main area, which is the widget grid with the KPI cards, tables and chart containers inside it.

Since the whole user interface lives in one stylesheet, changing the sidebar width or the accent color takes a one-line edit.

The term gets stretched in a few directions, though. Libraries such as Highcharts Dashboards ship their own markup, and the Highcharts documentation lists a fixed set of class names (such as highcharts-dashboards-row and highcharts-dashboards-cell) that developers override with plain CSS.

Hosted tools go further in the same direction. Checkly lets customers restyle its dashboards through a custom CSS editor, but only on its Team and Enterprise plans, and the vendor still controls the markup.

Then there’s the version where the markup and the stylesheet are both yours. That’s what the rest of this article assumes.

CSS places widgets and styles them. Fetching data and drawing chart values stays with JavaScript.

Which CSS Layout Module Fits Each Dashboard Region?

Grid runs the page frame and the widget area. Flexbox works better once you’re inside a single component, and subgrid only comes in when neighboring cards need their content to line up.

RegionModuleReason
Page frame (header, sidebar, main)CSS GridRows and columns defined together, named areas
Widget areaCSS GridAuto-fit columns, per-card spans
Card header, toolbar, nav itemsFlexboxOne axis, sized by content
Card content across a rowSubgridReuses parent tracks so labels and values align

A grid layout fits the frame because the header, sidebar and main region depend on each other’s size. Flexbox can’t express that relationship without nested wrappers.

A flex-only frame still works for a single-column admin panel. Once there’s more than one content column, Grid saves you the extra wrapper divs and the percentage math.

Subgrid fixes cards whose titles wrap to different heights and push their values out of line, because the nested grid reuses the parent’s tracks. MDN lists it as Baseline widely available, supported across browsers since September 2023.

Each of these has a spot where it quietly breaks. A subgridded dimension has no implicit grid, so any surplus items land in the last track (MDN).

The 1fr column catches people more often. It has an automatic minimum size, so a wide table stretches the layout past the screen until the track is written as minmax(0, 1fr). Flexbox has the same habit, since items refuse to shrink below their content width unless min-width is set to 0.

Use Grid for the frame and Flexbox inside components. Reach for subgrid only when cards need shared alignment. That split covers most dashboards.

Building the Dashboard Frame with grid-template-areas

The idea is to name the regions on the elements and describe the whole layout once, on the container. The main region then scrolls on its own.

  1. Write semantic HTML with a header, a nav or aside for the sidebar, and a main element.
  2. Give each element a grid-area name (header, sidebar and main).
  3. On the container, set display: grid, grid-template-columns: 240px minmax(0, 1fr), and grid-template-areas: “sidebar header” “sidebar main”.
  4. Set the container height to 100svh and grid-template-rows to auto minmax(0, 1fr), so the frame fills the screen and the page itself never scrolls.
  5. Add overflow: auto to main. The header and sidebar stay in place because they sit outside the scrolling region.

The area names have to describe a complete grid of rectangles. MDN’s guide to grid template areas states that every row needs the same number of cells and every named area must be rectangular, otherwise the property is ignored. That one bites easily, since a single typo in one row throws the whole declaration away.

Height needs care on phones. According to MDN, plain vh equals the large viewport, so a 100vh frame can run under the browser toolbar while the toolbar is showing.

svh sizes to the small viewport, so the frame always fits. dvh tracks the toolbar as it moves, but MDN notes that dynamic units are not stable even when the viewport is unchanged, which makes them a poor fit for a large scrolling region. I’d skip dvh here.

The minmax(0, 1fr) in step 3 is what stops a wide data table from stretching the main track.

I’d sketch the track sizes in a visual CSS grid generator first. It saves a few rounds of trial and error.

How to Make a CSS Dashboard Responsive

On a dashboard, responsive design mostly means keeping the data readable. Stacking everything into one column isn’t the goal. A table that scrolls sideways inside its card beats a table squeezed to an unreadable width.

The card grid doesn’t need breakpoints at all. repeat(auto-fit, minmax(240px, 1fr)) fills each row with as many cards as fit.

The page skeleton is different. Below a chosen width the sidebar moves to the top or into an off-canvas panel, and that’s still a job for media queries. MDN’s grid template areas guide shows the same pattern: assign the area names to the elements once, then redefine only grid-template-areas inside the query, so a sidebar can move without any change to the HTML.

Widgets are where container queries come in. A card shows full detail in a wide cell and a compact summary in a narrow one, whatever the viewport does.

Size container queries became Baseline newly available in February 2023, and web.dev’s August 2025 digest marks them widely available, which matches Baseline’s 30-month rule.

Style queries are newer. Container style queries for custom properties became Baseline newly available on 19 May 2026, when Firefox 151 joined Chrome and Edge 111 and Safari 18. Because they are not yet widely available, give visitors on older Firefox versions a fallback.

Every container has one limit. Setting container-type applies containment, so a container cannot take its size from its own contents on the queried axis.

Sidebar, Header, KPI Card and Data Table Styling

The sidebar works best as a fixed-width track with a clear active link. Keep the text labels visible by default in the sidebar navigation and collapse to icons only on narrow screens.

In the frame built above, the header already stays put because main scrolls beneath it. Use position: sticky only when the whole page scrolls, and add scroll-padding-top equal to the header height so anchor links do not land underneath it.

Each KPI card needs a value and a label, plus some kind of change indicator. Pull border-radius, shadow and padding from shared custom properties so the cards match, then adapt existing card styles and vary only the accent color per metric.

Tables go inside an overflow-x: auto wrapper, and the header row should be sticky. Row actions need a hit area of at least 24 by 24 CSS pixels.

That 24-pixel floor is WCAG 2.2 success criterion 2.5.8 (Level AA). W3C’s Understanding document shows six icon buttons at 20 by 20 pixels passing with 4 pixels between them and failing with none.

Chart containers should reserve their space before the chart renders, with aspect-ratio or a fixed min-height, so a late-loading chart does not push the cards below it.

Every component should pull color from custom properties, and radius and spacing as well. That habit pays off the moment the theme changes.

Chart Rendering Options for a CSS Dashboard

Draw small, static charts with CSS or inline SVG. Bring in a charting library when a chart needs tooltips or zoom, or when the data updates live.

A progress bar or share-of-total ring needs no more than a custom property and conic-gradient(), and the theme tokens recolor it for free. Examples of pure CSS charts usually stop there, because axes and tooltips are not something a stylesheet can supply.

Inline SVG in HTML goes further. Each mark is an element, so CSS can color it and a title element can name it for screen readers.

OptionProsCons
CSS-onlyNo JavaScript, themed by tokensNo axes, no tooltips
Inline SVGFull shape control, styled by CSSHand-built markup grows fast
Library (Chart.js, ApexCharts)Tooltips, zoom, live updatesScript weight, extra accessibility work

Libraries cost you in weight first. The ApexCharts installation docs list the default script-tag bundle at 263,188 bytes gzipped and the bare core at 157,032 (measured on version 8.0.0), which is a lot to ship for three bars.

Accessibility takes extra work too. Chart.js draws on a canvas, and its documentation says canvas content is not available to screen readers unless the page adds an aria-label with role=”img”, or fallback text inside the canvas tags.

The same page warns that a generic “browser does not support canvas” message counts as inaccessible fallback content.

Pick the lightest option that still shows the data honestly.

How to Add Dark Mode with Custom Properties

Define each color token once on :root, set color-scheme to light dark, and let light-dark() pick the value. A prefers-color-scheme media query does the same job with more lines.

MDN lists light-dark() as Baseline 2024 newly available, working across browsers since May 2024. It only runs when color-scheme is light dark, usually declared on :root. The function also has an image form (two images instead of two colors), but that part is much newer: Chrome, Edge and Firefox added it in version 150, and Safari 27 completed the set on 14 September 2026, so it is only Baseline newly available.

Following the system setting is the simpler route. The tokens switch with the operating system and there’s no JavaScript and no stored state. The catch is that users cannot override it from inside the dashboard.

Letting the user choose takes more work. A data-theme attribute on the html element holds light, dark or auto, a short script reads the saved choice before first paint, and a control flips the attribute and stores the new value.

Bootstrap 5.3 takes the second route, with data-bs-theme on the html element or on a single component. Its documentation notes that switching the Sass mixin to the media query output removes per-component themes.

The same docs suggest loading the toggler script at the top of the page to reduce flicker on reload. That flicker is the usual failure of attribute-based themes, where the page paints light and then flips.

Hard-coded hex values inside components ignore the token swap, which is why one card stays light in a dark theme. Chart series need their own dark set too, and an accessible color palette generator helps when choosing the pairs.

With the image form of light-dark(), a logo can swap with the theme in one declaration. Visitors on older browsers still need a prefers-color-scheme media query for the logo.

How to Check a CSS Dashboard for Accessibility and Performance

These are the thresholds worth testing against, all taken from W3C and web.dev.

  • Text contrast of 4.5:1, or 3:1 for large-scale text of 18 point or 14 point bold (W3C, WCAG 2.2 SC 1.4.3)
  • Interface components and chart marks at 3:1, unless visible labels and values carry the same information (W3C, SC 1.4.11)
  • Largest Contentful Paint at 2.5 seconds or less (web.dev)
  • Interaction to Next Paint at 200 milliseconds or less (web.dev)
  • Cumulative Layout Shift at 0.1 or less (web.dev)

Accessibility checks

Landmarks come first. Header, nav, main and aside map onto the frame regions and give screen reader users places to jump to.

Text and chart marks must meet the contrast ratios above in both themes. Check color contrast on each one, because a pair that passes on the light surface can fail on the dark one.

Focus is the easy one to forget. A sticky header or footer that completely covers a focused control fails WCAG 2.2 SC 2.4.11 (Focus Not Obscured, Minimum) at Level AA. W3C names scroll-padding as a sufficient technique (C43) and lists a header hiding focus as failure F110.

The prefers-reduced-motion: reduce media feature is Baseline widely available and has worked across browsers since January 2020 (MDN), so card hover motion and chart entry animations can be toned down for users who ask.

Data tables also need real header cells and a caption, which the accessible tables guidance walks through.

Performance checks

Core Web Vitals are judged at the 75th percentile of page loads, split by mobile and desktop, according to web.dev. A page passes only when all three metrics meet their targets.

Interaction to Next Paint became a stable Core Web Vital in 2024 and replaced First Input Delay, so a test plan that still cites FID is out of date.

Lighthouse’s default page-load run cannot measure INP because it loads pages with no user input. Total Blocking Time is the lab proxy, and field data is the only full answer (web.dev, page last updated September 2025).

Layout shift is the metric a CSS dashboard controls most directly. Fixed sidebar tracks and reserved chart heights keep widgets in place while data loads.

Profile blur and shadow effects in DevTools instead of guessing at their cost.

When a CSS Dashboard Is the Wrong Choice

Plain CSS is the wrong tool when users need to rearrange widgets and have the layout saved for next time. It’s also a poor fit when the team needs ready-made forms, modals and date pickers on a deadline.

Webix shows what the first case takes. Its Dashboard widget lets users drag panels into new cells and resize them with a handle, then save and restore the layout through a cookie, local storage or session storage. It only ships in the Webix Pro edition, though.

SituationBetter fitWhy
Fixed internal screen, few widgetsPlain CSS dashboardNo dependency to update
Many forms, modals, date pickersBootstrap or a Tailwind CSS kitPrebuilt components
Widgets users arrange and saveDashboard library such as WebixDrag, resize, state saving built in
Large or live datasetsCharting library inside the CSS frameRendering handled in JavaScript

A framework trades stylesheet weight and override work for build time. That trade pays off once the interface needs more than a few components.

A Tailwind CSS dashboard keeps the layout in utility classes inside the markup, which suits teams that already work that way. It does not remove the need for a charting library.

For an internal tool with fewer than a handful of fixed widgets, plain CSS wins.

CSS Dashboard FAQ

Where can I find free CSS dashboard templates?

GitHub and free template sites carry most of them. TemplateMo lists free HTML and CSS dashboard templates, while Tabler is an open-source HTML dashboard kit built on Bootstrap.

Check the stack before downloading. A template that pulls in Bootstrap or Tailwind CSS is not a framework-free build.

Can a sidebar open and close without JavaScript?

Yes. A hidden checkbox with a label toggles the :checked state, and :has() lets the page react to it. :has() became Baseline newly available in December 2023 and widely available in June 2026.

Give the checkbox an accessible name and a visible focus style. The open or closed state resets on reload unless a script stores it.

How do I build a bento-style widget grid?

Set a fixed number of columns and let selected cards span extra tracks with grid-column and grid-row. Penpot’s own tutorial builds a bento layout for a sales dashboard on a four-column, four-row grid, with selected cards spanning several cells.

Add grid-auto-flow: dense to fill gaps, but know that it can pull cards out of DOM order, so the keyboard tab sequence no longer matches what users see.

How should I prototype a dashboard layout before coding it?

Sketch the header, sidebar and widget regions in a design tool first. Penpot builds CSS Grid layouts visually without code, and a CodePen scratch pad turns the track sizes into live CSS.

Keep the prototype to boxes and sizes. Colors and tokens come after the frame works.

Where to Start When Building a CSS Dashboard

Get the grid frame right first, set up design tokens second, and leave the widgets for last. That order puts the costliest changes up front, before anything depends on them.

Start with named areas for the header, sidebar and main. Custom properties for color, spacing and type come next, and cards, tables and charts go into the finished frame after that.

Reordering regions after widgets exist forces edits to every card. Tokens defined early let a theme change land in one rule block.

The catch is that the layout lives only in the stylesheet, so source order in the markup still has to match the reading order. Grid placement does not change the tab sequence.