CompositionBar
A single horizontal stacked bar with a legend that shows how parts make up a total, such as a budget breakdown, a token allocation, or a storage split.
Playground
| Share | Value | Percent |
|---|---|---|
| Anteil A | 60 | 60.0 % |
| Anteil B | 30 | 30.0 % |
| Anteil C | 10 | 10.0 % |
<script lang="ts">
import { CompositionBar } from '@urbicon-ui/blocks';
const items = [
{ label: 'Anteil A', value: 60, intent: 'primary' },
{ label: 'Anteil B', value: 30, intent: 'success' },
{ label: 'Anteil C', value: 10, intent: 'warning' }
];
</script>
<CompositionBar
{items}
/>01 Examples
Heating Cost Pot
| Share | Value | Percent |
|---|---|---|
| Gas bill | 2.206,09 € | 57.7 % |
| Heat pump electricity | 1.127,31 € | 29.5 % |
| Heating system maintenance | 361,02 € | 9.4 % |
| Chimney sweep levy | 128,00 € | 3.3 % |
<div class="w-full max-w-xl">
<CompositionBar
items={heatingItems}
formatValue={formatEur}
size="lg"
legendPlacement="bottom"
showTotal
totalLabel="Heating cost pot 2024"
/>
</div>Tiny Segments
| Share | Value | Percent |
|---|---|---|
| Main share | 950 | 98.3 % |
| Mini A | 8 | 0.8 % |
| Mini B | 3 | 0.3 % |
| Mini C | 5 | 0.5 % |
<div class="w-full max-w-xl">
<CompositionBar items={tinyItems} formatValue={(v) => `${v}`} size="lg" />
</div>Total Override (Remainder)
| Share | Value | Percent |
|---|---|---|
| Gas bill | 2.206,09 € | 44.1 % |
| Heat pump electricity | 1.127,31 € | 22.5 % |
| Heating system maintenance | 361,02 € | 7.2 % |
| Chimney sweep levy | 128,00 € | 2.6 % |
| Expected 5.000,00 € (remaining) | 1.177,58 € | 23.6 % |
<div class="w-full max-w-xl">
<CompositionBar
items={heatingItems}
total={500000}
formatValue={formatEur}
size="lg"
showTotal
totalLabel="Expected 5.000,00 €"
/>
</div>Raw Color Overrides
| Share | Value | Percent |
|---|---|---|
| Treasury | 40 % | 40 % |
| Liquidity | 30 % | 30 % |
| Team | 15 % | 15 % |
| Community | 15 % | 15 % |
<div class="w-full max-w-xl">
<CompositionBar
items={tokenItems}
formatValue={(v) => `${v} %`}
formatPercent={(p) => `${Math.round(p)} %`}
size="lg"
legendPlacement="bottom"
/>
</div>02 Customization
Custom Tooltip Snippet
| Share | Value | Percent |
|---|---|---|
| Gas bill | 2.206,09 € | 57.7 % |
| Heat pump electricity | 1.127,31 € | 29.5 % |
| Heating system maintenance | 361,02 € | 9.4 % |
| Chimney sweep levy | 128,00 € | 3.3 % |
<div class="w-full max-w-xl">
<CompositionBar items={heatingItems} formatValue={formatEur} size="lg">
{#snippet tooltip(item, percent)}
<span class="block font-medium">{item.label}</span>
<span class="text-text-tertiary text-2xs block tabular-nums">
{formatEur(item.value)} · {Math.round(percent)} %
</span>
{#if item.intent === 'warning'}
<span class="text-warning text-3xs mt-1 block tracking-wide uppercase">
statutory levy
</span>
{/if}
{/snippet}
</CompositionBar>
</div>Compact Card Embedding
Treasury Allocation
Q1 2026| Share | Value | Percent |
|---|---|---|
| Treasury | 40 % | 40 % |
| Liquidity | 30 % | 30 % |
| Team | 15 % | 15 % |
| Community | 15 % | 15 % |
<div class="border-border-subtle bg-surface-elevated w-full max-w-md rounded-2xl border p-5">
<header class="mb-3 flex items-baseline justify-between">
<h3 class="text-text-primary text-sm font-semibold">Treasury Allocation</h3>
<span class="text-text-tertiary text-xs">Q1 2026</span>
</header>
<CompositionBar
items={tokenItems}
formatValue={(v) => `${v} %`}
formatPercent={(p) => `${Math.round(p)} %`}
size="sm"
legendPlacement="bottom"
/>
</div>03 Accessibility
ARIA Image Role + Summary
The bar container has role="img" with a combined aria-label summary (total plus each share with value and
percent), so screen readers can grasp the bar as a whole.
Table Fallback
An sr-only table duplicates the data in tabular form (share / value / percent) for screen readers that prefer tables over images.
Keyboard Navigation
Tab focuses the next segment, Arrow keys move between segments, Home /End jump to the first/last, Enter/Space triggers onItemSelect.
Bidirectional Highlight
Hovering or focusing a bar segment dims the other segments and highlights the matching
legend entry, and the reverse holds too. The link runs through the shared item.id (or the index as a fallback).
04 API Reference
25 propsProp | Type | Default | Description | |
|---|---|---|---|---|
items required | CompositionItem[] | — | Composition shares in the order they should appear in the bar. | |
class | string | — | Extra classes merged onto the wrapper. | |
dimmed variant | falsetrue | — | Controls the dimmed behavior and appearance of the CompositionBar component. Available options: false, true. | |
fill variant | dangerneutralprimarysecondary +2 more | — | Controls the fill behavior and appearance of the CompositionBar component. Available options: danger, neutral, primary, and 3 more. | |
formatPercent | (percent: number) => string | — | Format function for percentages. Default: 1 fraction digit, formatted with the active
locale (e.g. 12.3 %). | |
formatValue | (value: number) => string | — | Format function for values (tooltip, legend, total). | |
intent | CompositionBarIntent | 'primary' | Default intent for items without their own intent/color. | |
legendItem | Snippet<[item: CompositionItem, percent: number]> | — | Custom rendering of a legend entry. Receives the item and its percentage. Fully replaces the default rendering (dot + label + value/percent). | |
legendPlacement variant | bottomleftrighttop | bottom | Controls the legendPlacement behavior and appearance of the CompositionBar component. Available options: bottom, left, right, top. | |
minSegmentPercent | number | 1.5 | Minimum segment width in percent. Values below it are raised to this width so small shares stay visible. Larger segments are shrunk proportionally so the total still adds up to 100%. | |
onItemSelect | (item: CompositionItem, index: number) => void | — | Selection callback fired when a bar segment or legend entry is clicked. Receives the item and its index. Providing it makes the segments interactive (pointer cursor and click handling). | |
orientation variant | horizontalvertical | horizontal | Controls the orientation behavior and appearance of the CompositionBar component. Available options: horizontal, vertical. | |
preset | string | — | Preset name (registered via <BlocksProvider presets={{ CompositionBar: {...} }}>). | |
showLegend | boolean | true | Show the legend. Position it with legendPlacement. | |
showPercentages | boolean | true | Show percentages in legend and tooltip. | |
showTotal | boolean | false | Render the total value after the legend. | |
showValues | boolean | false | Render the value directly inside the bar segment, in addition to the legend. Only segments wide enough (≥ 8% or ~40 px) show their value, so narrow ones do not overflow. Handy for print or PDF export, where there is no hover tooltip. | |
size variant | lgmdsm | md | Controls the dimensions, padding, and text size of the CompositionBar. Affects the component's physical footprint. Available options: lg, md, sm. | |
slotClasses | Partial<Record<CompositionBarSlots, string>> | — | Per-slot class overrides. | |
tooltip | Snippet<[item: CompositionItem, percent: number]> | — | Custom tooltip content. Replaces the default layout (label, value, percent). | |
total | number | — | Optional fixed total value. Default: the sum of the item values. If the explicit total exceeds the sum, the remaining area is rendered neutrally ("unaccounted share"). If it is below the sum, segments are scaled to 100% and a console warning is emitted. | |
totalLabel | string | — | Label rendered before the total. Defaults to the localized "Total" label from the blocks i18n bundle. | |
unstyled | boolean | — | Remove all default classes; only the layout structure remains. | |
...CompositionBarVariants variant | VariantProps | — | Styling variants from CompositionBarVariants | |
...HTMLAttributes<HTMLDivElement> inherited | HTMLAttributes | — | HTML attributes (excluding: 'children') |
05 Types
Local type definitions used by this component.
Name | Kind | Category | Used by | Description | |
|---|---|---|---|---|---|
CompositionBarIntent | type | helper | 1 | — | |
CompositionItem | interface | helper | 1 | A single share in the stacked bar. | |
CompositionBarProps | interface | props | 0 | — | |
CompositionBarSlots | type | variant | 0 | Slot names derived from the tv() config above — single source of truth for slotClasses. | |
CompositionBarVariants | type | variant | 0 | — | |
SlotNames | type | helper | 0 | Extracts the slot-name union from a slotted tv() config function — the
companion to VariantProps. The slot-mode overload returns
(props?) => { [K in keyof S]: SlotFn }, so keyof ReturnType<T> is exactly
the set of slot names a component declares in tv({ slots: … }).
Use it to type a component's slotClasses prop from the single source of
truth (its *.variants.ts) instead of hand-maintaining a parallel union
that silently drifts when a slot is added or renamed: | |
VariantProps | type | helper | 1 | — |
06 Installation
Import
import { CompositionBar } from '@urbicon-ui/blocks';