17 CSS Dashboard Layouts08 / 17

Pure CSSMIT licensed

Container Query Responsive Dashboard Cards

The same widget markup pasted into three panels — 260px, 420px, and one you resize yourself — renders three different layouts: stacked, side-by-side, and full analytics with a legend rail. Media queries can't do this: they ask “how wide is the screen?” when a dashboard widget needs “how wide is MY slot?”. Container queries flip responsive design from page-level to component-level, and this demo makes the difference draggable.

Published

Live Demo
Try it

The code

<section class="cdl-08" aria-label="Container query widget demo">
  <div class="cdl-08__stage">
    <div class="cdl-08__row">
      <div class="cdl-08__slot" style="flex:0 0 250px"><p class="cdl-08__cap">260px slot → stacked</p>
        <div class="cdl-08__widget">
          <div class="cdl-08__kpi"><h3>Bandwidth</h3><p class="cdl-08__big">4.6<small>TB</small></p><span class="cdl-08__delta">▲ 18% this week</span></div>
          <div class="cdl-08__chart" aria-hidden="true"><i style="--h:35%"></i><i style="--h:55%"></i><i style="--h:42%"></i><i style="--h:68%"></i><i style="--h:58%"></i><i style="--h:80%"></i><i style="--h:72%"></i><i style="--h:95%"></i></div>
          <ul class="cdl-08__legend"><li><i class="cdl-08__c1" aria-hidden="true"></i>CDN 62%</li><li><i class="cdl-08__c2" aria-hidden="true"></i>API 27%</li><li><i class="cdl-08__c3" aria-hidden="true"></i>Media 11%</li></ul>
        </div>
      </div>
      <div class="cdl-08__slot" style="flex:1 1 300px"><p class="cdl-08__cap">≥ 340px → value beside chart</p>
        <div class="cdl-08__widget">
          <div class="cdl-08__kpi"><h3>Bandwidth</h3><p class="cdl-08__big">4.6<small>TB</small></p><span class="cdl-08__delta">▲ 18% this week</span></div>
          <div class="cdl-08__chart" aria-hidden="true"><i style="--h:35%"></i><i style="--h:55%"></i><i style="--h:42%"></i><i style="--h:68%"></i><i style="--h:58%"></i><i style="--h:80%"></i><i style="--h:72%"></i><i style="--h:95%"></i></div>
          <ul class="cdl-08__legend"><li><i class="cdl-08__c1" aria-hidden="true"></i>CDN 62%</li><li><i class="cdl-08__c2" aria-hidden="true"></i>API 27%</li><li><i class="cdl-08__c3" aria-hidden="true"></i>Media 11%</li></ul>
        </div>
      </div>
    </div>
    <div class="cdl-08__slot cdl-08__slot--free"><p class="cdl-08__cap">⤡ drag my corner — breakpoints at 340px and 520px</p>
      <div class="cdl-08__widget">
        <div class="cdl-08__kpi"><h3>Bandwidth</h3><p class="cdl-08__big">4.6<small>TB</small></p><span class="cdl-08__delta">▲ 18% this week</span></div>
        <div class="cdl-08__chart" aria-hidden="true"><i style="--h:35%"></i><i style="--h:55%"></i><i style="--h:42%"></i><i style="--h:68%"></i><i style="--h:58%"></i><i style="--h:80%"></i><i style="--h:72%"></i><i style="--h:95%"></i></div>
        <ul class="cdl-08__legend"><li><i class="cdl-08__c1" aria-hidden="true"></i>CDN 62%</li><li><i class="cdl-08__c2" aria-hidden="true"></i>API 27%</li><li><i class="cdl-08__c3" aria-hidden="true"></i>Media 11%</li></ul>
      </div>
    </div>
  </div>
</section>
.cdl-08,
.cdl-08 *,
.cdl-08 *::before,
.cdl-08 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.cdl-08 {
  background: var(--bg);
  width: 100%;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  --bg: oklch(0.975 0.005 285);
  --panel: oklch(1 0 0);
  --edge: oklch(0.9 0.012 285);
  --ink: oklch(0.27 0.02 285);
  --mut: oklch(0.55 0.02 285);
  --acc: oklch(0.58 0.18 290);
  --c2: oklch(0.7 0.14 220);
  --c3: oklch(0.8 0.12 90);
  font-family: 'Segoe UI',system-ui,sans-serif;
  color: var(--ink);
}

.cdl-08__stage {
  width: 100%;
  height: 100vh;
  display: grid;
  gap: 16px;
  border: 1px solid var(--edge);
  background: linear-gradient(175deg,var(--bg),oklch(0.955 0.008 285));
  padding: 18px;
}

.cdl-08__row {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
}

.cdl-08__slot {
  container-type: inline-size;
  container-name: cdl08w;
  min-width: 0;
  display: grid;
  gap: 9px;
  align-content: start;
}

.cdl-08__slot--free {
  resize: horizontal;
  overflow: auto;
  min-width: 240px;
  max-width: 100%;
  padding-bottom: 6px;
  border-right: 2px dashed color-mix(in oklch,var(--acc) 40%,transparent);
  padding-right: 14px;
}

.cdl-08__cap {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--mut);
}

.cdl-08__slot--free .cdl-08__cap {
  color: var(--acc);
}

.cdl-08__widget {
  display: grid;
  gap: 14px;
  background: var(--panel);
  border: 1px solid var(--edge);
  border-radius: 16px;
  padding: 18px;
  box-shadow: 0 10px 26px -20px oklch(0.4 0.06 290 / .5);
}

.cdl-08__kpi h3 {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .11em;
  text-transform: uppercase;
  color: var(--mut);
}

.cdl-08__big {
  font-size: clamp(24px,10cqi,40px);
  font-weight: 700;
  letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
  margin: 4px 0 2px;
}

.cdl-08__big small {
  font-size: .5em;
  color: var(--mut);
  font-weight: 600;
  margin-left: 2px;
}

.cdl-08__delta {
  font-size: 11.5px;
  font-weight: 700;
  color: oklch(0.55 0.14 155);
}

.cdl-08__chart {
  display: flex;
  align-items: flex-end;
  gap: 6px;
  height: 64px;
  min-width: 0;
}

.cdl-08__chart i {
  flex: 1;
  height: var(--h);
  border-radius: 4px 4px 0 0;
  background: linear-gradient(to top,color-mix(in oklch,var(--acc) 30%,transparent),var(--acc));
}

.cdl-08__legend {
  list-style: none;
  display: none;
  gap: 8px;
  align-content: center;
}

.cdl-08__legend li {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  font-weight: 600;
  color: var(--mut);
  white-space: nowrap;
}

.cdl-08__legend i {
  width: 10px;
  height: 10px;
  border-radius: 3px;
}

.cdl-08__c1 {
  background: var(--acc);
}

.cdl-08__c2 {
  background: var(--c2);
}

.cdl-08__c3 {
  background: var(--c3);
}

@container cdl08w (min-width: 340px) {
  .cdl-08__widget {
    grid-template-columns: auto minmax(0,1fr);
    align-items: end;
  }

  .cdl-08__kpi {
    align-self: center;
    padding-right: 8px;
  }
}

@container cdl08w (min-width: 520px) {
  .cdl-08__widget {
    grid-template-columns: auto minmax(0,1fr) 132px;
  }

  .cdl-08__legend {
    display: grid;
  }
}

@media (prefers-reduced-motion: reduce) {
  .cdl-08 * {
    transition: none !important;
  }
}
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS Dashboard Layout from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Container Query Responsive Dashboard Cards
Source: https://codefronts.com/layouts/css-dashboard-layouts/container-query-responsive-dashboard-cards/

The same widget markup pasted into three panels — 260px, 420px, and one you resize yourself — renders three different layouts: stacked, side-by-side, and full analytics with a legend rail. Media queries can't do this: they ask “how wide is the screen?” when a dashboard widget needs “how wide is MY slot?”. Container queries flip responsive design from page-level to component-level, and this demo makes the difference draggable.
## HTML
```html
<section class="cdl-08" aria-label="Container query widget demo">
  <div class="cdl-08__stage">
    <div class="cdl-08__row">
      <div class="cdl-08__slot" style="flex:0 0 250px"><p class="cdl-08__cap">260px slot → stacked</p>
        <div class="cdl-08__widget">
          <div class="cdl-08__kpi"><h3>Bandwidth</h3><p class="cdl-08__big">4.6<small>TB</small></p><span class="cdl-08__delta">▲ 18% this week</span></div>
          <div class="cdl-08__chart" aria-hidden="true"><i style="--h:35%"></i><i style="--h:55%"></i><i style="--h:42%"></i><i style="--h:68%"></i><i style="--h:58%"></i><i style="--h:80%"></i><i style="--h:72%"></i><i style="--h:95%"></i></div>
          <ul class="cdl-08__legend"><li><i class="cdl-08__c1" aria-hidden="true"></i>CDN 62%</li><li><i class="cdl-08__c2" aria-hidden="true"></i>API 27%</li><li><i class="cdl-08__c3" aria-hidden="true"></i>Media 11%</li></ul>
        </div>
      </div>
      <div class="cdl-08__slot" style="flex:1 1 300px"><p class="cdl-08__cap">≥ 340px → value beside chart</p>
        <div class="cdl-08__widget">
          <div class="cdl-08__kpi"><h3>Bandwidth</h3><p class="cdl-08__big">4.6<small>TB</small></p><span class="cdl-08__delta">▲ 18% this week</span></div>
          <div class="cdl-08__chart" aria-hidden="true"><i style="--h:35%"></i><i style="--h:55%"></i><i style="--h:42%"></i><i style="--h:68%"></i><i style="--h:58%"></i><i style="--h:80%"></i><i style="--h:72%"></i><i style="--h:95%"></i></div>
          <ul class="cdl-08__legend"><li><i class="cdl-08__c1" aria-hidden="true"></i>CDN 62%</li><li><i class="cdl-08__c2" aria-hidden="true"></i>API 27%</li><li><i class="cdl-08__c3" aria-hidden="true"></i>Media 11%</li></ul>
        </div>
      </div>
    </div>
    <div class="cdl-08__slot cdl-08__slot--free"><p class="cdl-08__cap">⤡ drag my corner — breakpoints at 340px and 520px</p>
      <div class="cdl-08__widget">
        <div class="cdl-08__kpi"><h3>Bandwidth</h3><p class="cdl-08__big">4.6<small>TB</small></p><span class="cdl-08__delta">▲ 18% this week</span></div>
        <div class="cdl-08__chart" aria-hidden="true"><i style="--h:35%"></i><i style="--h:55%"></i><i style="--h:42%"></i><i style="--h:68%"></i><i style="--h:58%"></i><i style="--h:80%"></i><i style="--h:72%"></i><i style="--h:95%"></i></div>
        <ul class="cdl-08__legend"><li><i class="cdl-08__c1" aria-hidden="true"></i>CDN 62%</li><li><i class="cdl-08__c2" aria-hidden="true"></i>API 27%</li><li><i class="cdl-08__c3" aria-hidden="true"></i>Media 11%</li></ul>
      </div>
    </div>
  </div>
</section>
```
## CSS
```css
.cdl-08,
.cdl-08 *,
.cdl-08 *::before,
.cdl-08 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.cdl-08 {
  background: var(--bg);
  width: 100%;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  --bg: oklch(0.975 0.005 285);
  --panel: oklch(1 0 0);
  --edge: oklch(0.9 0.012 285);
  --ink: oklch(0.27 0.02 285);
  --mut: oklch(0.55 0.02 285);
  --acc: oklch(0.58 0.18 290);
  --c2: oklch(0.7 0.14 220);
  --c3: oklch(0.8 0.12 90);
  font-family: 'Segoe UI',system-ui,sans-serif;
  color: var(--ink);
}

.cdl-08__stage {
  width: 100%;
  height: 100vh;
  display: grid;
  gap: 16px;
  border: 1px solid var(--edge);
  background: linear-gradient(175deg,var(--bg),oklch(0.955 0.008 285));
  padding: 18px;
}

.cdl-08__row {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
}

.cdl-08__slot {
  container-type: inline-size;
  container-name: cdl08w;
  min-width: 0;
  display: grid;
  gap: 9px;
  align-content: start;
}

.cdl-08__slot--free {
  resize: horizontal;
  overflow: auto;
  min-width: 240px;
  max-width: 100%;
  padding-bottom: 6px;
  border-right: 2px dashed color-mix(in oklch,var(--acc) 40%,transparent);
  padding-right: 14px;
}

.cdl-08__cap {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--mut);
}

.cdl-08__slot--free .cdl-08__cap {
  color: var(--acc);
}

.cdl-08__widget {
  display: grid;
  gap: 14px;
  background: var(--panel);
  border: 1px solid var(--edge);
  border-radius: 16px;
  padding: 18px;
  box-shadow: 0 10px 26px -20px oklch(0.4 0.06 290 / .5);
}

.cdl-08__kpi h3 {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .11em;
  text-transform: uppercase;
  color: var(--mut);
}

.cdl-08__big {
  font-size: clamp(24px,10cqi,40px);
  font-weight: 700;
  letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
  margin: 4px 0 2px;
}

.cdl-08__big small {
  font-size: .5em;
  color: var(--mut);
  font-weight: 600;
  margin-left: 2px;
}

.cdl-08__delta {
  font-size: 11.5px;
  font-weight: 700;
  color: oklch(0.55 0.14 155);
}

.cdl-08__chart {
  display: flex;
  align-items: flex-end;
  gap: 6px;
  height: 64px;
  min-width: 0;
}

.cdl-08__chart i {
  flex: 1;
  height: var(--h);
  border-radius: 4px 4px 0 0;
  background: linear-gradient(to top,color-mix(in oklch,var(--acc) 30%,transparent),var(--acc));
}

.cdl-08__legend {
  list-style: none;
  display: none;
  gap: 8px;
  align-content: center;
}

.cdl-08__legend li {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  font-weight: 600;
  color: var(--mut);
  white-space: nowrap;
}

.cdl-08__legend i {
  width: 10px;
  height: 10px;
  border-radius: 3px;
}

.cdl-08__c1 {
  background: var(--acc);
}

.cdl-08__c2 {
  background: var(--c2);
}

.cdl-08__c3 {
  background: var(--c3);
}

@container cdl08w (min-width: 340px) {
  .cdl-08__widget {
    grid-template-columns: auto minmax(0,1fr);
    align-items: end;
  }

  .cdl-08__kpi {
    align-self: center;
    padding-right: 8px;
  }
}

@container cdl08w (min-width: 520px) {
  .cdl-08__widget {
    grid-template-columns: auto minmax(0,1fr) 132px;
  }

  .cdl-08__legend {
    display: grid;
  }
}

@media (prefers-reduced-motion: reduce) {
  .cdl-08 * {
    transition: none !important;
  }
}
```

How this works

Two declarations turn any wrapper into a queryable container, then the widget styles itself against its slot:

.slot{ container-type:inline-size; container-name:widget; }

.widget{ display:grid; gap:14px; }            /* base: stacked */
@container widget (min-width:340px){
  .widget{ grid-template-columns:auto minmax(0,1fr); } /* value beside chart */
}
@container widget (min-width:520px){
  .widget{ grid-template-columns:auto minmax(0,1fr) 130px; } /* + legend rail */
  .legend{ display:grid; }
}

Type scales with the container too — cqi units are percentages of the container's inline size, so the headline number grows with its slot, clamped to sane bounds:

.big{ font-size: clamp(24px, 10cqi, 40px); }

The third panel has resize:horizontal; overflow:auto — a desktop-only demo affordance that turns the panel into a live breakpoint scrubber. Drag its corner and watch the widget cross 340px and 520px. Nothing about the page's viewport ever mattered: drop this widget in a sidebar, a modal, a 4-up grid — it dresses for the slot it gets.

Make it yours

  • Breakpoints are the two tokens 340px/520px — tune them to where YOUR content breaks, not to device sizes.
  • container-name is optional but self-documenting; unnamed queries match the nearest ancestor container, which gets spooky in nested layouts.
  • The number's fluid range: clamp(24px,10cqi,40px) — raise 10cqi for more drama.
  • Style queries stack on top: @container style(--density:compact){…} lets a parent set a custom property and every widget below re-skin (Chrome/Safari today, behind the same @container syntax).

Gotchas — read before shipping

  • container-type:inline-size establishes size containment — the container's height can no longer be driven by wide-triggered content changes, and its children can't size IT horizontally. Give slots an explicit basis (grid tracks here) or they can collapse.
  • Query the WRAPPER, style the CHILD: an element cannot query itself. The .slot/.widget split is load-bearing, not decorative.
  • resize needs overflow other than visible and has no touch support — it is demo sugar; the queries are the production mechanism.

Browser support

ChromeSafariFirefoxEdge
111+16.2+113+111+

Size container queries + cqi units: Chrome 105, Safari 16, Firefox 110 — Baseline 2023. oklch sets the stated floor. Style queries (mentioned in customization) are Chrome 111+ / Safari 18+ only, non-blocking here.

Techniques used in this demo

Search CodeFronts

Loading…