- Accordion
- Action Bar
- Action Toast
- Alert Banner
- Alert Dialog
- Alert
- Alphabet Index
- Amount Field
- Aspect Ratio
- Attachment
- Availability List
- Avatar
- Badge
- Bank Card
- Breadcrumb
- Bubble
- Button Group
- Button
- Calendar
- Camera Frame
- Card Design Picker
- Card Details
- Card Peek
- Card Stack
- Card
- Carousel
- Chart
- Chat Thread
- Checkbox
- Chip Group
- Choice Tile
- Code Block
- Code Dots
- Collapsible
- Combobox
- Command
- Context Menu
- Copy Field
- Countdown
- Country Select
- Data Table
- Date Field
- Date Picker
- Date Range Picker
- Dialog
- Direction
- Document Paper
- Drawer
- Dropdown Menu
- Empty
- Entity Avatar
- Field
- File Trigger
- File Upload Item
- Hover Card
- Input Group
- Input OTP
- Input
- Item
- Kbd
- Key Value
- Keypad
- Label
- Live Region
- Marker
- Message Scroller
- Message
- Money Amount
- Native Select
- Number Field
- Pagination
- Percent Split Editor
- Phone Field
- Popover
- Progress
- QR Code
- Questionnaire
- Radio Group
- Range Histogram
- Rating
- Resizable
- Scroll Area
- Search Field
- Select
- Separator
- Share Bar
- Sheet
- Sidebar
- Skeleton
- Slider
- Sonner
- Sortable List
- Spinner
- Status Timeline
- Step Header
- Steps List
- Swipe Row
- Switch
- Table
- Tabs
- Text Field
- Textarea
- Tier Ladder
- Toggle Group
- Toggle
- Token Search Field
- Tooltip
- Trace
- Transaction Row
- Usage Meter
- Shopping$772.90$772.9042%
- Food$515.30$515.3028%
- Transport$331.20$331.2018%
- Other$220.80$220.8012%
import { Card, CardContent } from "@/components/ui/card"
import { ShareBar, type ShareBarItem } from "@/components/ui/share-bar"
Use a share bar to show how a total splits into parts, such as spending by category or who paid what on a shared bill. It draws one color at falling density, never several hues, and keeps at most four segments so the bar stays readable. Pick a chart when the parts change over time, and a key-value list when the exact amounts matter more than the proportions.
Installation#
pnpm dlx shadcn@latest add @dots/share-bar
Usage#
import { ShareBar } from "@/components/ui/share-bar"<ShareBar
currency="USD"
items={[
{ label: "Shopping", value: 772.9 },
{ label: "Food", value: 515.3 },
{ label: "Transport", value: 331.2 },
]}
/>Composition#
ShareBar renders the bar and its legend on its own. Pass children to choose the parts yourself:
ShareBar
├── ShareBarTrack
└── ShareBarLegend
└── ShareBarSwatchFeatures#
- One color at falling density, in the order you pass the items
- At most four segments; the tail is merged into one "Other" segment
- Whole percents that always add up to 100, with
<1%for a small non-zero share - Legend values as money when
currencyis set, or as plain numbers - The bar is read by screen readers as one image that lists every share
- A custom legend row through a render function
Merged tail#
Pass the items largest first. When there are more items than maxSegments, the rest are added up into one segment named by otherLabel. The demo at the top passes five categories, so the last two become "Other".
<ShareBar items={spending} maxSegments={3} otherLabel="Everything else" />Custom legend#
Pass a function as the child of ShareBarLegend to render each row yourself. Use ShareBarSwatch with the segment's tone to keep the color key.
- You paid$820.00$820.00
- Sam paid$410.00$410.00
- Jordan paid$186.00$186.00
"use client"
import { MoneyAmount } from "@/components/ui/money-amount"Counts#
Leave out currency to show plain numbers, such as payments by method.
- Card4264%
- Transfer1828%
- Cash58%
import { ShareBar, type ShareBarItem } from "@/components/ui/share-bar"
const payments: ShareBarItem[] = [Bar only#
Render only ShareBarTrack for a compact summary under a heading. Its aria-label is put before the generated list of shares.
import {
ShareBar,
ShareBarTrack,Empty#
When every value is 0, the track renders empty, the legend shows 0% for each item and screen readers hear "No data".
- You$0.00$0.000%
- Sam$0.00$0.000%
import { ShareBar } from "@/components/ui/share-bar"
export function ShareBarEmpty() {Accessibility#
ShareBarTrack has role="img" and a name built from the segments, for example "Shopping 42%, Food 28%". The segments themselves are hidden from screen readers. ShareBarLegend is a real list, and ShareBarSwatch is decorative.
Name the bar#
Give the track an aria-label that says what is split. It is put before the shares.
<ShareBarTrack aria-label="Spent in November" />This is read as "Spent in November: Shopping 44%, Food 29%, …".
Meaning beyond color#
Segments differ only by density. Keep the legend, or a nearby label with the amounts, so the split is not conveyed by color alone.
API Reference#
ShareBar#
The root. Works out the segments and shares them with its parts. Renders a div and accepts all of its props.
| Prop | Type | Default | Description |
|---|---|---|---|
items | ShareBarItem[] | - | The parts, largest first. Color density follows this order. Required. |
maxSegments | number | 4 | Number of segments, from 1 to 4. Past that the tail is merged. |
otherLabel | string | "Other" | Label of the merged segment. |
currency | string | - | ISO 4217 code. Legend values are shown as money. |
locale | string | "en-US" | Locale for numbers and money. |
children | React.ReactNode | - | Your own parts. Defaults to ShareBarTrack and ShareBarLegend. |
className | string | - | Additional classes to apply to the root. |
ShareBarTrack#
The bar. Renders a div with role="img" and accepts all of its props except children.
| Prop | Type | Default | Description |
|---|---|---|---|
aria-label | string | - | What is split. Put before the generated share list. |
className | string | - | Additional classes to apply to the track. |
ShareBarLegend#
The parts in bar order: swatch, label, value and share. Renders a ul and accepts all of its props.
| Prop | Type | Default | Description |
|---|---|---|---|
children | (segment: ShareBarSegment) => React.ReactNode | - | Renders each row yourself. Each result is wrapped in an li. |
className | string | - | Additional classes to apply to the legend. |
ShareBarSwatch#
The color key of one segment, for custom legend rows. Renders a decorative span.
| Prop | Type | Default | Description |
|---|---|---|---|
tone | number | - | The segment's tone. 0 is the densest. Required. |
className | string | - | Additional classes to apply to the swatch. |
ShareBarItem#
One part you pass in items.
| Field | Type | Default | Description |
|---|---|---|---|
id | string | label and position | Stable, unique key. Do not use "__other". |
label | string | - | The part's name. Required. |
value | number | - | The part's size in any unit. Negative counts as 0. |
valueLabel | React.ReactNode | - | Shown instead of the formatted value in the legend. |
ShareBarSegment#
What a custom legend row receives.
| Field | Type | Description |
|---|---|---|
id | string | The item's key, or "__other" for the merged segment. |
label | string | The segment's name. |
value | number | The segment's size. |
valueLabel | React.ReactNode | The item's valueLabel, if any. |
percent | number | Whole percent. All segments add up to 100 when total > 0. |
tone | number | 0 is the densest; each next segment is lighter. |
isOther | boolean | True for the merged tail segment. |
useShareBar#
Reads segments, total, currency and locale inside a ShareBar. Throws outside of one.
formatSharePercent#
Formats a segment's share as text: "42%", or "<1%" for a small non-zero share.
formatSharePercent(segment) // "42%"