Data-heavy operations
Comparison
A finished page under Kiln. Copy it and it is yours outright: unlike a brickwork component or shell, it never upgrades under semver.
Q2 2026 vs Q1 2026
Same metrics, two quarters, side by side.
Headline metrics
Every line improved quarter on quarter except refund rate, which is broken out separately below because it needs its own explanation rather than a single row.
| Metric | Q1 2026 | Q2 2026 | Change |
|---|---|---|---|
| Revenue billed | £559,900 | £612,400 | increased 9.4% |
| Invoices raised | 1,304 | 1,486 | increased 14.0% |
| Average order value | £429.30 | £412.10 | decreased 4.0% |
| Average days to pay | 20.8 days | 18.2 days | decreased 2.6 days lower, which is better |
| Overdue balance | £44,900 | £41,900 | decreased 6.7% lower, which is better |
| Refund rate | 1.8% | 2.3% | increased 0.5 points higher, which is worse |
Revenue by region
The North's growth rate fell behind the other three regions this quarter, worth a look alongside the account-level detail in the full report.
| Region | Q1 2026 | Q2 2026 | Change |
|---|---|---|---|
| South | £223,100 | £248,100 | increased 11.2% |
| Midlands | £174,700 | £189,700 | increased 8.6% |
| North | £123,900 | £132,400 | increased 6.9% |
| Wales and South West | £38,200 | £42,200 | increased 10.5% |
Every region grew. The North's 6.9% is the slowest of the four and the only one below the company-wide 9.4%, which is why it gets its own section in the full quarterly report rather than a footnote here.
Scroll inside the frame to inspect the full page.
{% extends "brickwork/shell/app.html" %}
{% comment %}
A this-versus-that DATA comparison: two measured periods (or regions, cohorts,
suppliers) set side by side on real quantitative metrics, with deltas.
COPY THIS FILE into your project and edit it. It is not on the template loader
path, so you cannot extend it (ADR-056).
What your view must supply:
nav_items / nav_active as in list.html
Everything else is typed straight into the template: the two columns being
compared, every metric row, and every delta. Replace the entities and the
figures; keep the structure.
HOW THIS DIFFERS FROM sections/pricing/comparison-table.html. That section is
a MARKETING pricing table: it sits under a pricing page's tier cards and
answers "what does the cheaper plan give up", a tick-or-dash reference the
reader consults once they have already decided between two products you are
selling. Its cells are inclusion/exclusion facts, not measurements, and it
owns the first-class bw-comparison-table* surface (#626) built for exactly
that job: a scrollable, capability-by-plan grid.
This page is different in kind, not just in content. It compares two MEASURED
ENTITIES (here, two quarters) on QUANTITATIVE metrics, where the reader's job
is analysis, not purchase: which one is bigger, by how much, and in which
direction. Reusing the marketing comparison table's bw-comparison-table*
classes here would be wrong even if the markup looked similar, because that
CSS is that component's own surface (the design bar's bespoke-CSS rule cuts the
other way too: do not repurpose one component's private classes as if they
were a second, general-purpose component). This page reaches its layout
through ordinary tables, bw-prose and _trend_indicator.html instead, nothing
that belongs to another component.
Use this page for: two accounting periods, two regions, two cohorts, two
suppliers, anywhere the comparison is numbers with a direction. Use the
pricing section instead for: plan tiers you are selling, where the answer to
each row is included or not included.
MEANING NEVER RIDES ON COLOUR ALONE. Every delta in this page renders through
_trend_indicator.html, which ALWAYS pairs a decorative glyph with visually
hidden "increased"/"decreased"/"unchanged" text, so the direction reaches a
screen reader in words regardless of whether the caller supplies a visible
label. Colour is reinforcement on top of that, never the only signal.
States: none: a static comparison, no sort/filter/select state.
Accessibility: inherits shell/app.html's skip link, sidebar/drawer nav and
page-header region. Each comparison table is a real <table> with
scope="col" per period and scope="row" per metric, so a cell mid-table
announces "Q2 2026, Average order value, up 6.4 per cent" rather than just
a number. Every delta cell carries visually hidden direction text via
_trend_indicator.html (never colour or an arrow glyph alone). Wide tables
sit in their own scrollable, keyboard-reachable region (role="region" plus
aria-label, tabindex="0") so a narrow viewport never scrolls the whole page
sideways.
Responsive: no breakpoint switch of its own; inherits shell/app.html's
sidebar-to-drawer collapse at --bw-breakpoint-md (48rem). Each table
scrolls horizontally within its own region rather than reflowing; it does
not collapse to one column, matching the pricing comparison section's own
reasoning that a comparison table cannot become one column without ceasing
to answer the question it exists to answer.
{% endcomment %}
{% load brickwork_components brickwork_nav %}
{% block page_title %}Q2 vs Q1 comparison - Northwind{% endblock %}
{% block sidebar %}{% bw_nav nav_items nav_active %}{% endblock %}
{% block sidebar_mobile %}{% bw_nav nav_items nav_active %}{% endblock %}
{% block brand_wordmark %}Northwind{% endblock %}
{% block page_header %}
{% include "brickwork/components/_page_header.html" with title="Q2 2026 vs Q1 2026" description="Same metrics, two quarters, side by side." %}
{% endblock %}
{% block page_actions %}
{% bw_button "Export CSV" variant="secondary" icon="download" href="/reports/comparison.csv" %}
{% endblock %}
{% block content %}
<div class="bw-section-stack">
{% comment %}
Headline comparison. A real table, not a pair of stat rows: putting both
periods in one table is what lets a reader compare a single cell against its
neighbour instead of holding two separate tiles in their head.
TRAP, and the reason several rows below read the way they do: trend states
the DIRECTION THE NUMBER MOVED, never whether that is good news.
_trend_indicator.html renders trend="up" as an up arrow AND the visually
hidden word "increased", with no way to override that word. So a
lower-is-better metric that improved (days to pay, overdue balance) still
takes trend="down", because the number went down; passing trend="up"
because the result pleased you makes the page announce "increased" over a
figure the reader can see has fallen. Judgement belongs in trend_label,
where you write it in words ("6.7% lower, which is better"). Get this
backwards and a screen reader reads the opposite of the table.
{% endcomment %}
<section class="bw-content-section">
<div class="bw-prose">
<h2>Headline metrics</h2>
<p>
Every line improved quarter on quarter except refund rate, which is
broken out separately below because it needs its own explanation
rather than a single row.
</p>
<div class="bw-prose__table-wrap" tabindex="0" role="region" aria-label="Headline metrics, Q1 2026 versus Q2 2026">
<table>
<caption>Headline metrics, Q1 2026 versus Q2 2026.</caption>
<thead>
<tr>
<th scope="col">Metric</th>
<th scope="col">Q1 2026</th>
<th scope="col">Q2 2026</th>
<th scope="col">Change</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Revenue billed</th>
<td>£559,900</td>
<td>£612,400</td>
<td>
{% include "brickwork/components/_trend_indicator.html" with trend="up" trend_label="9.4%" %}
</td>
</tr>
<tr>
<th scope="row">Invoices raised</th>
<td>1,304</td>
<td>1,486</td>
<td>
{% include "brickwork/components/_trend_indicator.html" with trend="up" trend_label="14.0%" %}
</td>
</tr>
<tr>
<th scope="row">Average order value</th>
<td>£429.30</td>
<td>£412.10</td>
<td>
{% include "brickwork/components/_trend_indicator.html" with trend="down" trend_label="4.0%" %}
</td>
</tr>
<tr>
<th scope="row">Average days to pay</th>
<td>20.8 days</td>
<td>18.2 days</td>
<td>
{% include "brickwork/components/_trend_indicator.html" with trend="down" trend_label="2.6 days lower, which is better" %}
</td>
</tr>
<tr>
<th scope="row">Overdue balance</th>
<td>£44,900</td>
<td>£41,900</td>
<td>
{% include "brickwork/components/_trend_indicator.html" with trend="down" trend_label="6.7% lower, which is better" %}
</td>
</tr>
<tr>
<th scope="row">Refund rate</th>
<td>1.8%</td>
<td>2.3%</td>
<td>
{% include "brickwork/components/_trend_indicator.html" with trend="up" trend_label="0.5 points higher, which is worse" %}
</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
{% comment %}
Regional split. Two entities compared per row (this quarter's revenue by
region against last quarter's), which is the shape a reader actually wants:
not two separate regional tables they have to line up themselves.
{% endcomment %}
<section class="bw-content-section">
<div class="bw-prose">
<h2>Revenue by region</h2>
<p>
The North's growth rate fell behind the other three regions this
quarter, worth a look alongside the account-level detail in the full
report.
</p>
<div class="bw-prose__table-wrap" tabindex="0" role="region" aria-label="Revenue by region, Q1 2026 versus Q2 2026">
<table>
<caption>Revenue billed by region, Q1 2026 versus Q2 2026.</caption>
<thead>
<tr>
<th scope="col">Region</th>
<th scope="col">Q1 2026</th>
<th scope="col">Q2 2026</th>
<th scope="col">Change</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">South</th>
<td>£223,100</td>
<td>£248,100</td>
<td>
{% include "brickwork/components/_trend_indicator.html" with trend="up" trend_label="11.2%" %}
</td>
</tr>
<tr>
<th scope="row">Midlands</th>
<td>£174,700</td>
<td>£189,700</td>
<td>
{% include "brickwork/components/_trend_indicator.html" with trend="up" trend_label="8.6%" %}
</td>
</tr>
<tr>
<th scope="row">North</th>
<td>£123,900</td>
<td>£132,400</td>
<td>
{% include "brickwork/components/_trend_indicator.html" with trend="up" trend_label="6.9%" %}
</td>
</tr>
<tr>
<th scope="row">Wales and South West</th>
<td>£38,200</td>
<td>£42,200</td>
<td>
{% include "brickwork/components/_trend_indicator.html" with trend="up" trend_label="10.5%" %}
</td>
</tr>
</tbody>
</table>
</div>
<p>
Every region grew. The North's 6.9% is the slowest of the four and the
only one below the company-wide 9.4%, which is why it gets its own
section in the full quarterly report rather than a footnote here.
</p>
</div>
</section>
</div>
{% endblock %}
Details
| Kind | Page example |
|---|---|
| Used in | Data-heavy operations |
Composed from
| Template | Description |
|---|---|
brickwork/components/_button.html |
A button or link styled as a button, in several variants. |
brickwork/components/_page_header.html |
A page's title, description, and action row. |
brickwork/components/_trend_indicator.html |
A standalone directional caption: a glyph, hidden direction text, and an optional label. |
brickwork/nav/_nav.html |
Not a catalogue component |
brickwork/shell/app.html |
The authenticated app shell: sidebar, topbar, and content region. |