Components · Charts
BarList
A ranked list with an inline bar per row: top pages, referrers, rivals by score.
Top pages with links
import { BarList } from '@rookcom/monarch-react/charts';
const pages = [
{ id: 'home', label: '/', value: 4820, href: '#/components/bar-list' },
{ id: 'pricing', label: '/pricing', value: 2310, href: '#/components/bar-list' },
{ id: 'docs', label: '/docs/getting-started', value: 1640, href: '#/components/bar-list' },
{ id: 'blog', label: '/blog/release-notes', value: 920, href: '#/components/bar-list' },
{ id: 'contact', label: '/contact', value: 310, href: '#/components/bar-list' },
];
<div style={{ width: '100%', maxWidth: '28rem' }}>
<BarList label="Top pages" items={pages} unit="views" locale="en-US" />
</div>Usage examples
Ranked comparison, inline layout
import { BarList } from '@rookcom/monarch-react/charts';
<div style={{ width: '100%', maxWidth: '36rem' }}>
<BarList
label="Visibility score"
ranked
layout="inline"
max={100}
limit={4}
items={[
{ id: 'a', label: 'Northfield', value: 82 },
{ id: 'you', label: 'Your site (you)', value: 71, highlighted: true },
{ id: 'b', label: 'Cobalt', value: 64 },
{ id: 'c', label: 'Fernway', value: null },
{ id: 'd', label: 'Tidewater', value: 38 },
]}
/>
</div>Rates with a description and display value
import { BarList } from '@rookcom/monarch-react/charts';
<div style={{ width: '100%', maxWidth: '28rem' }}>
<BarList
label="Reply rate by channel"
format="percent"
max={1}
items={[
{
id: 'e',
label: 'Email',
description: 'Spring outreach',
value: 0.12,
displayValue: '12% · 4 of 33',
},
{
id: 'l',
label: 'LinkedIn',
description: 'Founders list',
value: 0.21,
displayValue: '21% · 9 of 43',
},
{ id: 'c', label: 'Calls', description: 'Renewals', value: 0.05 },
]}
locale="en-US"
/>
</div>Loading and empty
import { BarList } from '@rookcom/monarch-react/charts';
<div style={{ display: 'grid', gap: '1.5rem', width: '100%', maxWidth: '28rem' }}>
<BarList label="Top referrers" items={[]} loading loadingRows={3} />
<BarList label="Top referrers" items={[]} emptyState="No referrers in this period" />
</div>Purpose
Compares a handful of named values at a glance. Each row keeps its label and value as text, so the list reads correctly without the bars.
Use when
- Top-N breakdowns: pages, referrers, campaigns, countries, engines.
- Comparing your entity against others (
highlighted), with missing values shown honestly.
Avoid when
- Values over time: use a line or bar chart.
- Parts of one whole that should add to 100%: use StackedProportionBar or a donut.
- More than about 10 rows or several columns of numbers: use a DataTable.
Design principles
- Text first: labels and values are real list text; bars are decorative (
aria-hidden). - Largest first by default; missing values sort last and read as "No value", never as zero.
- One series colour (the first data palette colour); a highlighted row keeps it and the others fade.
- Values are formatted with Intl.NumberFormat (or Money for currency) in the viewer’s locale.
API reference
import { BarList } from '@rookcom/monarch-react/charts';| Export | Kind | Rendering | Root class |
|---|---|---|---|
BarList | component | server-safe | .mn-bar-list |
The ref and native attributes go to the root <div>; the list is a <ul>, or an <ol> when ranked.
Exported from @rookcom/monarch-react/charts, with the BarListItem type.
Generated from the TypeScript declarations of packages/react/src/components/charts/bar-list.
Properties
Bars are scaled to the largest value unless max is set. For ratios of a whole, pass max={1}.
BarList
A ranked list with an inline bar per row (top pages, top referrers, rivals by score). Labels and values are real text; the bars are decorative.
| Prop | Type | Description |
|---|---|---|
items required | BarListItem[] | |
className | string | |
currency | string | ISO 4217 code for `format="currency"`. |
emptyState | ReactNode | Shown when there are no items. Default "No data yet". |
format | "number" | "currency" | "percent" | How values are written: `number` (default), `percent` (a ratio: 0.12 is 12%) or `currency`. |
formatOptions | Intl.NumberFormatOptions | Extra `Intl.NumberFormat` options. |
formatValue | ((value: number, item: BarListItem) => ReactNode) | Writes a value yourself; replaces `format`. |
id | string | |
label | string | Names the list for assistive technology, e.g. "Top pages". |
layout | "inline" | "stacked" | `stacked` (default): bar under the label. `inline`: label, bar and value in one row on wide screens. |
limit | number | Shows only the first `limit` rows, with a "Top 5 of 12" footer. |
linkComponent | ElementType | Component used for `href` rows, e.g. a router link. Default `a`. |
loading | boolean | Shows placeholder rows and sets `aria-busy`. |
loadingRows | number | Placeholder rows while loading. Default 5. |
locale | string | BCP 47 locale. Default: the runtime locale. |
max | number | The value of a full bar. Default: the largest value. Pass `1` for ratios of a whole. |
missingLabel | string | Spoken for a missing value. Default "No value". |
notation | "compact" | "standard" | `compact` writes 1.2K. Default `standard`. |
overflowLabel | ReactNode | Replaces the default "Top {shown} of {total}" footer when rows are cut by `limit`. |
ranked | boolean | Numbers the rows and renders an ordered list. Default `false`. |
sort | "desc" | "none" | "asc" | Row order. `desc` (default) puts the largest first; `none` keeps the given order. Missing values go last. |
unit | string | Unit after a `number` value, e.g. `visits`. |
Variants
| Prop | Values | Description |
|---|---|---|
layout | 'stacked''inline' | stacked (default) puts a thin bar under each label; inline puts label, bar and value on one row from 30rem up (data-layout). |
format | 'number''percent''currency' | How values are written; notation="compact", unit and formatOptions refine it, formatValue replaces it. |
sort | 'desc''asc''none' | Row order; none keeps the given order. |
ranked | 'false''true' | Shows rank numbers and renders an ordered list (data-ranked). |
States
| State | Exposed as | Behaviour |
|---|---|---|
| Highlighted row | data-highlighted | Bold label; the other rows’ bars fade. Put "you" in the label too. |
| Missing value | data-missing | A dash read as missingLabel ("No value"), no bar, sorted last. |
| Linked row | data-linked | The label is a link and the whole row is its click target. |
| Overflow | – | With limit, a "Top 5 of 12" footer (or overflowLabel). |
| Loading | data-loading | Placeholder rows, aria-busy, and a hidden "Loading {label}". |
| Empty | data-empty | emptyState text instead of a list. |
Interaction behaviour
- Rows with
hrefare links; clicking anywhere on the row follows the link. - Hovering a linked row tints it and underlines the label.
Keyboard support
| Keys | Action |
|---|---|
| Tab / Shift+Tab | Moves between linked rows. |
| Enter | Follows the focused row’s link. |
Rows without href are not focusable.
Accessibility
- Role
- list (
<ul>or<ol>, with an explicit role so Safari keeps it) - Accessible name
label, e.g. "Top pages".
- Each row reads its label, description and value; the bar is hidden from assistive technology.
- A missing value is announced as "No value", not only shown in a tooltip.
- Rank numbers are hidden because an ordered list already announces positions.
- Linked rows have a focus ring around the whole row and are named by their label.
- In forced-colours mode bars are drawn in CanvasText with an outlined track.
Responsive behaviour
- Labels and descriptions truncate with an ellipsis; values never wrap.
- The inline layout falls back to stacked below 30rem, so it works at 320px.
Theme support
- Bars use
--mn-color-data-1on a--mn-color-bg-mutedtrack, which are defined for light, dark and high-contrast themes. - Values use the default text colour; rank and descriptions are muted.
Do and don't
Do
- Name the list with
labeland keep labels short; usedescriptionfor the second detail. - Pass
nullfor an unknown value so it reads as "No value" instead of a misleading zero. - Use
limitwith an honest "Top 5 of 12" footer, and link to the full list.
Don't
- Do not put information only in the bar length; the value text is what everyone reads.
- Do not colour rows with status colours to rank them.
- Do not use a BarList for shares that must add to 100%.
Related components
- BarChart: Values over time or many categories with axes.
- StackedProportionBar: Parts of one whole in a single bar.
- DataTable: Many rows or several numeric columns.
- Progress: One value against a target or quota.
Dependencies
| Kind | Depends on |
|---|---|
| npm packages | react |
| Monarch components | Money, Skeleton, VisuallyHidden |
Testing coverage
- Named list, largest first, text values and decorative bars scaled to the largest value.
- sort none/asc, ranked ordered list.
- Percent, currency, compact, unit and custom formatting.
- Missing values announced and sorted last; display values.
- Linked rows reachable with Tab, custom router link component.
- limit with default and custom overflow footer; highlighted rows.
- Empty and loading states; zero values; ref and layout.
| Check | Covered |
|---|---|
| Axe in jsdom | Yes |
| Server rendering | Yes |
| Browser suites | Visual baselines: /__gallery/bar-list; Cross-browser axe: /components/bar-list |
Tests: packages/react/src/components/charts/bar-list