Horizontal bar
Revenue by channel
Usage
Import the component and the stylesheet once. See Getting started to install the package.
import { HorizontalBarChartCard } from '@lilt-ui/charts';
import '@lilt-ui/charts/styles.css';<HorizontalBarChartCard
title="Revenue by channel"
data={channelRevenue}
category="channel"
value="revenue"
/>Omit title to leave out the visible title. Set header={false} to remove the whole header, and use aria-label to name a chart inside your own card. surface="ghost" controls only the visual frame. See Card composition.
Data
category names a text field and value a numeric one; TypeScript rejects anything else. The headline is the total, and each share is a row’s part of it. null rows say “No data”, sort last, and stay out of the total. When values go negative, shares are hidden, because a share of a total that mixes gains and losses means nothing.
// One row per category, in any order. Names must be unique.
const channelRevenue = [
{ channel: 'Organic search', revenue: 42800 },
{ channel: 'Direct', revenue: 24100 },
{ channel: 'Referral', revenue: null }, // still reporting
];
<HorizontalBarChartCard
title="Revenue by channel"
data={channelRevenue}
category="channel" // a text field
value="revenue" // a numeric field
limit={5} // top five, the rest as "Other"
/>For a working period select, pass ranges. Each range brings its own data and delta.
<HorizontalBarChartCard
title="Revenue by channel"
category="channel"
value="revenue"
ranges={[
{ id: 'month', label: 'This month', data: thisMonth, delta: 0.124 },
{ id: 'last-month', label: 'Last month', data: lastMonth, delta: 0.038 },
]}
/>Mirrored bars
Two audience profiles face one another around shared category labels. Both sides use one absolute scale; left-facing bars still represent positive counts. All three loading styles share the skeleton exit, entrance, pointer/keyboard pinning, touch glide, reduced motion, and accessible readings table. Aggregate marks report null as their original datum.
import { MirroredBarCard } from '@lilt-ui/charts';
<MirroredBarCard
title="Audience by age"
data={audienceAge}
category="age"
left="previous"
right="current"
leftLabel="Previous"
rightLabel="Current"
/>| Prop | Type | Description |
|---|---|---|
title | string | Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set. |
header | boolean | Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection. |
aria-label | string | Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name. |
data | Row[] | One row per observation. Omit when using ranges. |
height | number | Minimum plot height, default 260. Dense lanes expand to keep every mark visible. |
depth | boolean | Lit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment. |
color | string | Override the palette with one CSS color. |
aggregate | 'sum' | 'mean' | 'max' | Resting headline summary; Strip defaults to mean, the others to sum. |
headline | number | Override the resting headline. |
delta | number | Fractional change shown alongside the headline. |
deltaTone | 'default' | 'inverse' | 'neutral' | Use inverse when a decrease is good. |
range | string | Static period label. |
ranges | { id, label, data, headline?, delta? }[] | Period choices with their own data. |
defaultRange | string | Initial period id. |
locale | string | Locale for numbers and dates; defaults to en-US. |
formatValue | (value: number) => string | Custom value formatter. |
badge | ReactNode | Content for the glass tab above the card. |
className | string | Class on the card frame. |
style | CSSProperties | ChartStyle | Inline styles and scoped chart variables. |
onSelectionChange | (selection | null) => void | Reports id, original row (or null for an absent day), value, and pinned state. |
renderReadout | (selection | null) => ReactNode | Consumer-owned readout, including when the header is hidden. |
valueFormat | Intl.NumberFormatOptions | Formats the headline, tiles, and axis, e.g. currency. |
surface | 'elevated' | 'outline' | 'ghost' | Card treatment. Ghost removes the visual frame only; header and legend are independent controls. |
palette | 'iris' | 'cobalt' | 'emerald' | Series colors. Iris by default; explicit series colors still win. |
numberStyle | 'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble' | How the headline animates when its value changes. Count (default) counts to the new value. |
loading | boolean | Shows a neutral loading skeleton, not data. |
loadingStyle | 'shimmer' | 'draw' | 'breathe' | Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion. |
empty | 'dots' | 'shape' | ReactElement | null | What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `<ChartEmpty>` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero. |
motion | 'auto' | 'none' | None turns off decorative motion; reduced motion does this automatically. |
legend | false | 'tiles' | 'inline' | 'list' | 'pills' | 'bars' | Legend layout; false hides it. Correlation defaults to false. |
legendSwatch | 'square' | 'dot' | 'line' | Legend marker, square by default. |
category | text key of Row | Unique label between the two sides. |
left | numeric keys of Row | Nonnegative measurements on one common scale. |
right | numeric keys of Row | Nonnegative measurements on one common scale. |
leftLabel | string | Names for the two cohorts. |
rightLabel | string | Names for the two cohorts. |
onKeyDown | KeyboardEventHandler<HTMLElement> | Keyboard handler on the card frame. Chart inspection also has its own keyboard handling. |
Props
Every prop HorizontalBarChartCard accepts, in the order you are likely to reach for them.
| Prop | Type | Description |
|---|---|---|
title | string | Optional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set. |
header | boolean | Defaults to true. False removes the whole header: title, headline, delta and period controls, with no reserved space. Pass data directly when your app owns period selection. |
aria-label | string | Accessible chart name, independent of the visible title. Falls back to title, then a generic chart name. |
data | Row[] | One row per category. Omit when using ranges. |
category | text key of Row | Names each row. Must be unique. |
value | numeric key of Row | The amount to rank by. |
sort | 'descending' | 'ascending' | 'input' | Largest first by default; input keeps your order. |
limit | number | Show the first rows and add the rest together as one “Other” row. |
otherLabel | string | Label of the combined row. |
share | boolean | Each row’s share of the total. Defaults to true. |
rank | boolean | Number each row by rank. |
barStyle | 'inline' | 'track' | 'lollipop' | 'isometric' | Inline puts the label on a soft bar (default); track draws a slim bar below it; lollipop uses a stem and dot; isometric adds depth. |
headline | number | Resting headline. Defaults to the total of all rows. |
delta | number | Fractional change for the chip. |
deltaTone | 'default' | 'inverse' | 'neutral' | Use inverse when a decrease is good. |
range | string | Static period label in the header. |
selected | string | null | The pinned category, by name, when you own the selection, so outside filters and a click on the chart share it. `null` pins nothing; omit it and the card keeps its own pin. |
onSelectedChange | (category: string | null) => void | Asked when a click, tap, or Escape pins or releases a category. |
ranges | { id, label, data, delta?, headline? }[] | Turns the period label into a select. Each range swaps the rows. |
color | string | Any CSS color for the bars. |
depth | boolean | Shorthand for `barStyle="isometric"`: a solid block under each label with a lit roof and a shaded end. The front ends at the value. |
valueFormat | Intl.NumberFormatOptions | Formats the headline, tiles, and axis, e.g. currency. |
surface | 'elevated' | 'outline' | 'ghost' | Card treatment. Ghost removes the visual frame only; header and legend are independent controls. |
palette | 'iris' | 'cobalt' | 'emerald' | Series colors. Iris by default; explicit series colors still win. |
numberStyle | 'count' | 'pop' | 'slide' | 'roll' | 'flow' | 'scramble' | How the headline animates when its value changes. Count (default) counts to the new value. |
loading | boolean | Shows a neutral loading skeleton, not data. |
loadingStyle | 'shimmer' | 'draw' | 'breathe' | Shimmer sweeps a highlight over still shapes; draw reveals them in order; breathe lets them settle. Follows the selected look, including depth, and respects reduced motion. |
empty | 'dots' | 'shape' | ReactElement | null | What the card shows when the period has no data. Dots (default) gathers a quiet dot field around the message; shape lays the chart’s own outline behind it. Pass `<ChartEmpty>` with your own words, any element of your own, or null for nothing. Both looks stay still, so empty never reads as loading, and the headline reads a dash, never zero. |
motion | 'auto' | 'none' | None turns off decorative motion; reduced motion does this automatically. |
defaultRange | string | Initial range id; defaults to the first supplied range. |
locale | string | Locale used for number formatting. Defaults to en-US. |
formatValue | (value: number) => string | Custom value text, taking precedence over valueFormat. |
badge | ReactNode | Content in the tab above the card. A comparison badge can replace this while a comparison is active. |
className | string | Additional class on the card frame. |
style | CSSProperties | ChartStyle | Inline styles and scoped --lilt-* chart variables. |