Patterns Data storytelling
Results summary
Explain a result with contextual statistics, a zero-baseline chart, and transparent measurement notes.
On this page
Complete pattern
Illustrative weekly manual-work hours at four checkpoints. Both headline metrics are calculated from the same complete dataset used by the chart.
Preview setting only: fitting scales the 800 px wide composition, including its 736 × 280 px chart. Actual size allows contained scrolling. The copied layout has content-driven height.
Preview only: surrounding canvas and spacing. All metrics are illustrative.
'use client';
import { useId } from 'react';
import { BarChart, EyebrowLabel, StatBlock } from '@coreux/ui';
const categories = [
{ id: 'jan', label: 'Jan' },
{ id: 'feb', label: 'Feb' },
{ id: 'mar', label: 'Mar' },
{ id: 'apr', label: 'Apr' },
];
const weeklyHours = [50, 46, 42, 38];
const hoursSaved = weeklyHours[0] - weeklyHours[weeklyHours.length - 1];
const reduction = Math.round((hoursSaved / weeklyHours[0]) * 100);
export default function ResultsSummary() {
const notesId = useId();
return (
<div style={{ width: 800, padding: 32, background: '#F4F1E9', color: '#0B1221' }}>
<EyebrowLabel>Illustrative pilot · January–April</EyebrowLabel>
<h2 style={{ margin: '16px 0', fontFamily: '"The Seasons", serif', fontSize: 36, fontWeight: 700, lineHeight: 1.15 }}>Less time spent on manual work.</h2>
<p style={{ margin: '0 0 24px', fontSize: 16, lineHeight: 1.6, color: '#596579' }}>One fictional team tracked weekly manual work at four monthly checkpoints.</p>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 32, marginBottom: 32 }}>
<StatBlock value={String(reduction)} unit="%" label="Reduction in weekly hours" caption="April compared with January." />
<StatBlock value={String(hoursSaved)} unit="h" label="Weekly hours saved" caption="From 50 hours to 38 hours per week." />
</div>
<figure style={{ margin: 0 }}>
<BarChart width={736} height={280} categories={categories} series={[{ id: 'manual', label: 'Weekly hours', values: weeklyHours }]} domain={{ min: 0, max: 60 }} showLegend={false} showValueLabels />
<figcaption style={{ marginTop: 16, fontSize: 14, lineHeight: 1.6, color: '#596579' }}>Illustrative weekly manual-work hours: January 50, February 46, March 42, April 38. The vertical scale starts at zero.</figcaption>
</figure>
<a href={`#${notesId}`} style={{ display: 'inline-block', marginTop: 20, color: '#2457F5', textDecoration: 'underline', textUnderlineOffset: 4, fontSize: 14 }}>Read measurement notes</a>
<section id={notesId} tabIndex={-1} aria-label="Measurement notes" style={{ marginTop: 20, paddingTop: 20, borderTop: '1px solid #C7CDD6', scrollMarginTop: 96 }}>
<p style={{ margin: 0, fontSize: 14, lineHeight: 1.6, color: '#596579' }}>All values are invented for this example. Each point is a weekly total at that checkpoint, not a monthly total. The 24% reduction is (50 − 38) ÷ 50; four observations alone do not establish causation.</p>
</section>
</div>
);
}
Component selection & hierarchy
EyebrowLabel establishes the observation window, a plain heading states the outcome, and two StatBlocks quantify it. BarChart provides the four underlying checkpoints. This is one measure shown as a relative change, an absolute change, and the observed series—not three independent claims.
The first and last values in the chart dataset calculate both stats. Keeping one source for these values prevents the headline from drifting away from the evidence. The full array and calculation are part of the copied file.
Content & color
The dataset is illustrative weekly manual-work hours for one fictional team: January 50, February 46, March 42, and April 38. These are weekly totals observed at monthly checkpoints, not monthly totals. Twelve fewer weekly hours divided by the January baseline of 50 gives a 24% reduction. The labels and notes explain that distinction.
Use a concise outcome headline, spell out units, and keep a visible data caption alongside the chart. The installed chart also exposes its categories and values through an accessible description. Four observations do not demonstrate causation; avoid turning this example into an unsupported business claim.
The ivory field and ink text keep attention on the values. BarChart’s first series color supplies cobalt bars. The explicit zero-to-60 domain avoids exaggerating the reduction. Cobalt on the nearby link marks its navigational role; the same hue inside a chart is a data encoding, not an action.
Sizing & navigation
The copied wrapper is 800 px wide including 32 px padding, leaving 736 px for the chart. BarChart is explicitly 736 × 280 px, has one series with four values matching its four unique categories, and hides its unnecessary one-item legend. Value labels, the visible caption, and measurement notes retain the numerical context.
The wrapper’s height follows its content. Fit to canvas scales the full composition without changing the chart’s geometry. Actual size preserves it with contained scrolling. Consumers should contain this fixed-width composition or deliberately change the wrapper and chart dimensions together; a utility width class does not override the chart’s inline dimensions.
“Read measurement notes” is a real same-page anchor with a unique destination in this complete file. The two sections use readable text and native links; no click handler, chart interaction, hidden dataset, or remote asset is required. The copied client directive follows the installed public-barrel requirement.
Constituent components
- EyebrowLabel — Introduce a headline with a short context label and an optional decorative dot.
- StatBlock — Give a meaningful number the context it deserves. Pair a value with a unit, label, and optional caption.
- BarChart — Compare categories, show the parts of a total, or follow one measure. Start with valid data and give the chart enough room to be read.
These are documentation compositions of the installed library. They do not add new library APIs. Follow the one-time consumer setup, including the repository-access and font-use requirements, before copying a complete file into your app.