Chart style

Applies to every chart.

Palette

Theme

Appearance

Depth
Surface
Background

Reading & motion

Axis
Hover
Legend
Numbers
Loading
Empty
Using chart defaults
3,109npm
1stars

Charts

Every chart, by the job it does

Trends3

  • Area
  • Line
  • Combo

Comparison4

  • Bar
  • Horizontal bar
  • Slope
  • RangeNew

Part of a whole4

  • Radial
  • Treemap
  • Funnel
  • Sankey

KPIs3

  • Stat cards
  • Progress
  • Activity ring

Patterns4

  • Heatmap
  • Scatter
  • Radar
  • Box plotNew

Cool23

  • Chord loomNew
  • Rank ribbonsNew
  • Event helixNew
  • Contour islandsNew
  • Parallel ribbonsNew
  • Sunburst terracesNew
  • Cluster constellationNew
  • Ternary prismNew
  • Wind roseNew
  • Marimekko blocksNew
  • Intersection towersNew
  • Horizon foldsNew
  • Circle archipelagoNew
  • Helix ribbonsNew
  • Voxel cloudNew
  • Arc bridgesNew
  • TerrainNew
  • Hex cityNew
  • Voxel waffleNew
  • SkylineNew
  • Block cityNew
  • RidgelineNew
  • Spiral yearNew

Finance6

  • CandlestickNew
  • IndicatorsNew
  • PriceNew
  • DepthNew
  • Order bookNew
  • PortfolioNew

Horizontal bar

Revenue by channel

$129,200$129,200+12.4%
Default01 / 05

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"
/>
PropTypeDescription
titlestringOptional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
headerbooleanDefaults 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-labelstringAccessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
dataRow[]One row per observation. Omit when using ranges.
heightnumberMinimum plot height, default 260. Dense lanes expand to keep every mark visible.
depthbooleanLit tiles, solid bars, or spheres. Data positions remain exact; loading keeps the same depth treatment.
colorstringOverride the palette with one CSS color.
aggregate'sum' | 'mean' | 'max'Resting headline summary; Strip defaults to mean, the others to sum.
headlinenumberOverride the resting headline.
deltanumberFractional change shown alongside the headline.
deltaTone'default' | 'inverse' | 'neutral'Use inverse when a decrease is good.
rangestringStatic period label.
ranges{ id, label, data, headline?, delta? }[]Period choices with their own data.
defaultRangestringInitial period id.
localestringLocale for numbers and dates; defaults to en-US.
formatValue(value: number) => stringCustom value formatter.
badgeReactNodeContent for the glass tab above the card.
classNamestringClass on the card frame.
styleCSSProperties | ChartStyleInline styles and scoped chart variables.
onSelectionChange(selection | null) => voidReports id, original row (or null for an absent day), value, and pinned state.
renderReadout(selection | null) => ReactNodeConsumer-owned readout, including when the header is hidden.
valueFormatIntl.NumberFormatOptionsFormats 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.
loadingbooleanShows 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 | nullWhat 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.
legendfalse | 'tiles' | 'inline' | 'list' | 'pills' | 'bars'Legend layout; false hides it. Correlation defaults to false.
legendSwatch'square' | 'dot' | 'line'Legend marker, square by default.
categorytext key of RowUnique label between the two sides.
leftnumeric keys of RowNonnegative measurements on one common scale.
rightnumeric keys of RowNonnegative measurements on one common scale.
leftLabelstringNames for the two cohorts.
rightLabelstringNames for the two cohorts.
onKeyDownKeyboardEventHandler<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.

PropTypeDescription
titlestringOptional visible title. Omit to render no title. Also supplies the accessible name unless aria-label is set.
headerbooleanDefaults 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-labelstringAccessible chart name, independent of the visible title. Falls back to title, then a generic chart name.
dataRow[]One row per category. Omit when using ranges.
categorytext key of RowNames each row. Must be unique.
valuenumeric key of RowThe amount to rank by.
sort'descending' | 'ascending' | 'input'Largest first by default; input keeps your order.
limitnumberShow the first rows and add the rest together as one “Other” row.
otherLabelstringLabel of the combined row.
sharebooleanEach row’s share of the total. Defaults to true.
rankbooleanNumber 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.
headlinenumberResting headline. Defaults to the total of all rows.
deltanumberFractional change for the chip.
deltaTone'default' | 'inverse' | 'neutral'Use inverse when a decrease is good.
rangestringStatic period label in the header.
selectedstring | nullThe 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) => voidAsked 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.
colorstringAny CSS color for the bars.
depthbooleanShorthand for `barStyle="isometric"`: a solid block under each label with a lit roof and a shaded end. The front ends at the value.
valueFormatIntl.NumberFormatOptionsFormats 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.
loadingbooleanShows 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 | nullWhat 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.
defaultRangestringInitial range id; defaults to the first supplied range.
localestringLocale used for number formatting. Defaults to en-US.
formatValue(value: number) => stringCustom value text, taking precedence over valueFormat.
badgeReactNodeContent in the tab above the card. A comparison badge can replace this while a comparison is active.
classNamestringAdditional class on the card frame.
styleCSSProperties | ChartStyleInline styles and scoped --lilt-* chart variables.