Skip to content

Top-down funnel layout

2 min read · Updated 8 Oct 2026

A top-down funnel page goes one level deeper with each row: KPIs, then the charts that break them down, then a table of the records behind them. Reflow rules, grid traps and the shared tokens are in Layout and responsiveness.

Top-down funnel layout: Read totals, then breakdowns, then supporting records.

Illustrative example with synthetic data. Read totals, then breakdowns, then supporting records.

Use it when readers start from totals and end at the records, such as shelter intake to outcomes to individual animals.

The page is mainly Use instead
Headline numbers and charts, with no records KPI-led
One item at a time, picked from a list Master–detail
Rows of records, with charts only as context Table-first
  1. Do readers read more than about eight table rows at once, or is there a row below the table? Use scrolling.
  2. Otherwise, use fixed height.
Variant Layout Use cases
Fixed height KPIs, three breakdown charts and the table fit the window Help desk: open tickets and breaches, then by priority, team and week, then the ticket list
Scrolling KPIs and charts in the first window, the table a full window below Recruitment: applicants and offers, then by role, source and stage, then the candidate table
  • Order the rows from general to specific, with every chart that narrows the table above it.
  • Put every object in the page’s one selection group; see Filters and selections. An applied selection filters every connected object, including the rows above the one the reader selected in.
  • Above the table, show the applied selections in one line, for example Showing: Dog · Adopted · 2024, or Showing all records. Build it from the same applied state as the apply bar, and truncate it at a fixed height.
<section class="table-panel" aria-labelledby="table-title">
<h2 id="table-title">Animals</h2>
<p class="drill-path">Showing: Dog · Adopted · 2024</p>
<div class="table-host"><!-- table object --></div>
</section>
:root {
--path-h: 24px;
/* Title and padding, drill path, 40px header row, 36px rows. */
/* 8 rows: 52 + 24 + 40 + 8 × 36 = 404 */
--table-min: 404px;
/* 20 rows: 52 + 24 + 40 + 20 × 36 = 836 */
--table-floor: 836px;
}
.board {
display: grid;
gap: var(--gap);
}
.band {
display: grid;
gap: var(--gap);
min-height: 0;
}
.band--kpis {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
.band--three {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.table-panel {
display: grid;
grid-template-rows: auto var(--path-h) minmax(0, 1fr);
min-height: 0;
}
.drill-path {
margin: 0;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
/* Three 320px charts, 15 for a classic scrollbar: 2 × 16 + 3 × 320 + 2 × 16 + 15 = 1039 */
@media (width < 1039px) {
.band--three {
grid-template-columns: repeat(2, minmax(0, 1fr));
grid-auto-rows: minmax(var(--chart-min), auto);
}
/* Three charts in two columns: the first spans the row, so no row is incomplete. */
.band--three > :first-child {
grid-column: 1 / -1;
}
}
@media (width < 700px) {
.band--kpis {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.band--three {
grid-template-columns: minmax(0, 1fr);
}
}
┌───────┬───────┬───────┬───────┐
│ KPI │ KPI │ KPI │ KPI │
├───────┴──┬────┴─────┬─┴───────┤
│ Chart A │ Chart B │ Chart C │
├──────────┴──────────┴─────────┤
│ Showing: Dog · Adopted │
│ Table │
└───────────────────────────────┘

.board takes its fixed height from Bands above the board.

.board--funnel {
/* Charts and table share the height 2 : 3, and neither goes below its floor. */
grid-template-rows: auto minmax(var(--chart-min), 2fr) minmax(var(--table-min), 3fr);
}
/* 64 + 2 × 16 + 96 + 16 + 252 + 16 + 404 = 880 */
@media (width < 1039px), (height < 880px) {
.board--funnel {
height: auto;
grid-template-rows: none;
}
.board--funnel .band--three {
grid-auto-rows: minmax(var(--chart-min), auto);
}
.board--funnel .table-panel {
min-height: var(--table-floor);
}
}
Width KPIs Charts Table Height
1039px and wider 4 across 3 across At least 8 rows Fits the window from 880px tall
700–1038px 4 across 2 across; the first spans the row At least 20 rows Scrolls
Under 700px 2 across 1 across At least 20 rows Scrolls
┌───────┬───────┬───────┬───────┐
│ KPI │ KPI │ KPI │ KPI │
├───────┴──┬────┴─────┬─┴───────┤
│ Chart A │ Chart B │ Chart C │
├──────────┴──────────┴─────────┤ ← window bottom
│ Showing: Dog · Adopted │
│ Table, one window tall │
└───────────────────────────────┘

The table is at least one window tall, so once the reader scrolls to it, it fills the window and its rows scroll inside it. A row below the table, such as permissions for the selected item, takes its own floor and stays in the same selection group.

.board--funnel-scroll {
height: auto;
/* At 900px tall the table starts at 64 + 16 + 96 + 16 + 324 + 16 = 532, in the first window. */
grid-template-rows: auto minmax(var(--chart-min), 36svh) auto;
}
.board--funnel-scroll .table-panel {
min-height: max(var(--table-floor), calc(100svh - var(--header-h) - var(--above-board, 0px) - 2 * var(--gap)));
}
@media (width < 1039px) {
.board--funnel-scroll {
grid-template-rows: none;
}
}
Width Charts Table
1039px and wider 3 across, 36% of the window tall, at least 252px One window tall, at least 20 rows
700–1038px 2 across; the first spans the row As above
Under 700px 1 across As above