Composition Bar

A single horizontal stacked bar showing how a total breaks down across categories, with an aligned legend listing each category's value and share. Hovering a segment or a legend row highlights both. Pure CSS — no charting library required.

Basic

Pass data, category and value. Percentages are computed against the sum of all values.

  • Equities$4,820,00047.4%
  • Fixed Income$3,140,00030.9%
  • Real Estate$1,260,00012.4%
  • Cash$640,0006.3%
  • Commodities$310,0003.0%

Sort Order

sortOrder reorders segments by value. Use "none" to preserve the input array order.

none

  • Organic Search18,42052.4%
  • Direct9,31026.5%
  • Referral4,20512.0%
  • Social2,1806.2%
  • Email1,0403.0%

descending

  • Organic Search18,42052.4%
  • Direct9,31026.5%
  • Referral4,20512.0%
  • Social2,1806.2%
  • Email1,0403.0%

ascending

  • Email1,0403.0%
  • Social2,1806.2%
  • Referral4,20512.0%
  • Direct9,31026.5%
  • Organic Search18,42052.4%

Bar Height

Control the thickness of the bar with barHeight (pixels).

6px

12px

24px

Custom Colors

Override the palette with any ChartColor[] — or raw hex strings for brand colors.

Palette names

  • Equities$4,820,00047.4%
  • Fixed Income$3,140,00030.9%
  • Real Estate$1,260,00012.4%
  • Cash$640,0006.3%
  • Commodities$310,0003.0%

Hex values

  • Equities$4,820,00047.4%
  • Fixed Income$3,140,00030.9%
  • Real Estate$1,260,00012.4%
  • Cash$640,0006.3%
  • Commodities$310,0003.0%

Formatters

valueFormatter formats the raw value; percentFormatter formats the share. Both apply to the legend and the tooltip.

  • Organic Search18.4k52%
  • Direct9.3k26%
  • Referral4.2k12%
  • Social2.2k6%
  • Email1.0k3%

Minimum Segment Width

minSegmentPercent inflates slices below the given percentage so they stay visible; the excess is reclaimed from the largest segment. The legend always shows the true percentage. Note the 0.0% Trial slice below.

0 (true widths)

  • Enterprise$9,800,00079.5%
  • Mid-Market$2,100,00017.0%
  • SMB$420,0003.4%
  • Trial$4,0000.0%

2 (floor applied)

  • Enterprise$9,800,00079.5%
  • Mid-Market$2,100,00017.0%
  • SMB$420,0003.4%
  • Trial$4,0000.0%

Legend & Tooltip

Turn either off with showLegend={false} or showTooltip={false}. With the tooltip off, hover dimming is disabled too.

Bar only (no legend)

Static (no tooltip)

  • Equities$4,820,00047.4%
  • Fixed Income$3,140,00030.9%
  • Real Estate$1,260,00012.4%
  • Cash$640,0006.3%
  • Commodities$310,0003.0%

Fill Parent

fillParent stretches the component to the parent's height and spreads the legend rows evenly — useful inside fixed-height cards so the chart balances with its siblings.

default

  • Equities$4,820,00047.4%
  • Fixed Income$3,140,00030.9%
  • Real Estate$1,260,00012.4%
  • Cash$640,0006.3%
  • Commodities$310,0003.0%

fillParent

  • Equities$4,820,00047.4%
  • Fixed Income$3,140,00030.9%
  • Real Estate$1,260,00012.4%
  • Cash$640,0006.3%
  • Commodities$310,0003.0%

Empty State

When the data is empty or all values sum to zero, a placeholder bar is rendered. Pass emptyLabel to explain why.

No allocation data for this period.

CompositionBar

A single horizontal stacked bar showing how a total breaks down across categories, with an aligned legend listing each category's value and share. Segments and legend rows highlight together on hover, and a minimum segment width keeps tiny slices visible.

Usage

import { CompositionBar } from "@/components/charts/composition-bar"

// Basic composition
<CompositionBar
  data={data}
  category="assetClass"
  value="amount"
  valueFormatter={(v) => `$${v.toLocaleString()}`}
/>

// Sorted, custom palette
<CompositionBar
  data={data}
  category="source"
  value="sessions"
  sortOrder="descending"
  colors={["violet", "amber", "rose", "teal", "cyan"]}
/>

// Bar only, no legend
<CompositionBar
  data={data}
  category="assetClass"
  value="amount"
  showLegend={false}
  barHeight={8}
/>

// Fill a fixed-height card
<div className="h-64">
  <CompositionBar
    data={data}
    category="assetClass"
    value="amount"
    fillParent
  />
</div>

CompositionBar Props

PropTypeDefaultDescription
data*Record<string, any>[]Array of data objects. Each object needs a key for the category label and a key for the numeric value.
category*stringKey in each data object used as the segment label (e.g. "assetClass", "source").
value*stringKey in each data object used as the segment's numeric value. Percentages are computed against the sum of all values.
colors(ChartColor | string)[]CHART_COLORSColor palette for the segments. Accepts palette names or raw hex strings, and cycles if there are fewer colors than categories.
valueFormatter(value: number) => stringv => v.toString()Formats the raw value in the legend and tooltip.
percentFormatter(percent: number) => stringp => `${p.toFixed(1)}%`Formats the share percentage in the legend and tooltip. Always receives the true percentage, never the inflated render width.
sortOrder"ascending" | "descending" | "none""none"Sort order applied to segments by value. Use "none" to keep the order of the input array.
barHeightnumber12Height of the bar in pixels.
minSegmentPercentnumber0.5Floor (in percent) applied to rendered segment widths so tiny slices stay visible. The inflation is reclaimed from the largest segment so widths still sum to 100.
showLegendbooleantrueShow the legend rows below the bar (color swatch, label, value, percentage).
showTooltipbooleantrueShow the hover tooltip and enable the hover dimming of non-hovered segments.
fillParentbooleanfalseStretch to fill the parent's height and distribute legend rows evenly across the available vertical space. Use inside fixed-height cards so the chart balances with siblings.
emptyLabelstringText rendered under the placeholder bar when data is empty or all values sum to zero.
classNamestringAdditional CSS classes on the outer wrapper.