Build / Molecules
BreakdownList
A ranked breakdown: one row per value of a dimension, each with a bar showing how it compares.
This is the workhorse of the analytics screen — traffic sources, locations, devices, browsers, link performance all answer the same question, so they are one component rather than five layouts.
The figure is written beside every row, so the bar is a second reading of a number that is already there rather than the only way to get it. That also makes the list its own table view: nothing is locked inside the chart.
Rows are rendered in the order given. Sorting is the caller's call, because "top locations" and "the funnel in order" are both legitimate.
import { BreakdownList } from '@meetcard/deck'Example
<BreakdownList label="Where engagement comes from" items={[ { label: 'QR', value: 631, meta: '37%' }, { label: 'LinkedIn', value: 388, meta: '23%' }, ]} />Stories
Source
const Default = () => <Card style={{ maxWidth: 420 }}>
<BreakdownList
label="Where engagement comes from"
items={[
{ label: 'QR', value: 631, meta: '37%' },
{ label: 'LinkedIn', value: 388, meta: '23%' },
{ label: 'Link', value: 273, meta: '16%' },
{ label: 'Email', value: 222, meta: '13%' },
{ label: 'Direct', value: 191, meta: '11%' },
]} />
</Card>;A leading mark helps when the labels are a category people scan for.
Source
const WithIcons = () => <Card style={{ maxWidth: 420 }}>
<BreakdownList
label="Top locations"
items={[
{ label: 'United States', value: 1067, meta: '63%', icon: <Globe /> },
{ label: 'Canada', value: 218, meta: '13%', icon: <Globe /> },
{ label: 'United Kingdom', value: 172, meta: '10%', icon: <Globe /> },
{ label: 'Germany', value: 121, meta: '7%', icon: <Globe /> },
{ label: 'Other', value: 106, meta: '6%', icon: <Globe /> },
]} />
</Card>;The figure can carry its own unit when the number alone is ambiguous.
Source
const CustomValueLabels = () => <Card style={{ maxWidth: 420 }}>
<BreakdownList
label="Link performance"
items={[
{ label: 'Book a time', value: 298, valueLabel: '298 clicks', meta: '17% CTR' },
{ label: 'Save contact', value: 254, valueLabel: '254 clicks', meta: '15% CTR' },
{ label: 'LinkedIn profile', value: 128, valueLabel: '128 clicks', meta: '8% CTR' },
{ label: 'Company site', value: 62, valueLabel: '62 clicks', meta: '4% CTR' },
]} />
</Card>;A card shared today, nothing measured yet. Flat bars are the honest rendering — the rows exist, the numbers are genuinely zero.
Source
const NothingMeasuredYet = () => <Card style={{ maxWidth: 420 }}>
<BreakdownList
label="Where engagement comes from"
items={[
{ label: 'QR', value: 0, meta: '0%' },
{ label: 'LinkedIn', value: 0, meta: '0%' },
{ label: 'Link', value: 0, meta: '0%' },
]} />
</Card>;Long labels truncate rather than pushing the figures off the row.
Source
const LongLabels = () => <Card style={{ maxWidth: 420 }}>
<BreakdownList
label="Where engagement comes from"
items={[
{ label: 'Conference badge QR code — RevOps Summit', value: 631, meta: '37%' },
{ label: 'LinkedIn profile featured section', value: 388, meta: '23%' },
{ label: 'Direct', value: 88, meta: '5%' },
]} />
</Card>;Props
| Prop | Type | Default | Description |
|---|---|---|---|
itemsrequired | BreakdownItem[] | — | Rows, in the order they should read. Not sorted for you. |
labelrequired | string | — | Names the list for assistive tech, e.g. "Where engagement comes from". |
formatValue | (value: number) => string | (value: number) => value.toLocaleString() | Formats value. Defaults to the viewer's locale grouping. |
scale | 'max' | 'total' | 'max' | What the bars are drawn against. max scales to the largest row, so the
leader always fills the track and differences between the rest are easy
to see. total scales to the sum, so a bar's length is its share of
the whole. Use total only when the rows genuinely partition something. |
Also accepts everything from Omit, so id, data-* and event handlers pass straight through.