ComponentsBar List
Bar List
The fastest way to answer “which ones matter most?”. Labels sit on the bars, values align on the right, and long lists fold behind Show more.
On this page
Install component source from the public registry, or use the local workspace package. Follow the setup guide first. The npm package is not published yet.
View registry filesImplemented with React and browser APIs, without an additional behavior or rendering library.
Shared foundation: React, clsx for conditional classes, tailwind-merge for resolving utility-class conflicts. Styles use Tailwind CSS and Dethink CSS variables.
Based on this component’s source and registry composition. Libraries used only in showcase examples are excluded.
Import the component into your page or component file.
import { BarList } from "@dethink/components";Linked top pages with a limit, clickable sources on a shared percent scale, and currency values with icons.
Top pages
Rows link to detail views. Long paths truncate with the full text available on hover and to assistive technology.
Show sourceexamples/bar-list/top-pages.tsx
"use client";
import { BarList } from "@dethink/components";
const pages = [
{ label: "/", value: 12_940, href: "#home" },
{ label: "/pricing", value: 5_320, href: "#pricing" },
{ label: "/docs/getting-started", value: 4_870, href: "#docs" },
{
label: "/blog/launching-dethink-charts-without-a-chart-library",
value: 2_310,
href: "#blog",
},
{ label: "/changelog", value: 1_420, href: "#changelog" },
{ label: "/careers", value: 640, href: "#careers" },
{ label: "/legal/privacy", value: 210, href: "#privacy" },
];
export function BarListTopPages() {
return (
<div className="w-full max-w-xl">
<h3 id="top-pages-heading" className="mb-3 text-sm font-medium">
Top pages
</h3>
<BarList
aria-labelledby="top-pages-heading"
data={pages}
labelHeader="Page"
valueHeader="Visitors"
limit={5}
/>
</div>
);
}Filter by source
onItemClick turns rows into buttons. The selected source takes its own palette slot, and max={1} puts shares on a common scale.
Filtering by Organic search. Bars share a 0–100% scale.
Show sourceexamples/bar-list/sources.tsx
"use client";
import { BarList, type BarListItem } from "@dethink/components";
import { Globe, Mail, MessageCircle, Search } from "lucide-react";
import { useState } from "react";
const sources: BarListItem[] = [
{ key: "search", label: "Organic search", value: 0.412, icon: <Search /> },
{ key: "direct", label: "Direct", value: 0.268, icon: <Globe /> },
{ key: "social", label: "Social", value: 0.174, icon: <MessageCircle /> },
{ key: "email", label: "Email", value: 0.146, icon: <Mail /> },
];
export function BarListSources() {
const [selected, setSelected] = useState("search");
return (
<div className="grid w-full max-w-xl gap-4">
<BarList
aria-label="Traffic by source"
data={sources.map((item) => ({
...item,
color: item.key === selected ? "chart-3" : undefined,
}))}
color="chart-1"
max={1}
formatValue={(value) => `${(value * 100).toFixed(1)}%`}
onItemClick={(item) => setSelected(item.key!)}
size="sm"
/>
<p className="text-muted-foreground text-xs" aria-live="polite">
Filtering by{" "}
<span className="text-foreground font-medium">
{sources.find((item) => item.key === selected)?.label}
</span>
. Bars share a 0–100% scale.
</p>
</div>
);
}Currency, icons and sort order
Values format compactly as currency. Ascending sort surfaces the smallest markets first.
- United States$48.2K
- Germany$21.4K
- India$19.9K
- United Kingdom$14.1K
- Brazil$9,310
- Brazil$9,310
- United Kingdom$14.1K
- India$19.9K
- Germany$21.4K
- United States$48.2K
Show sourceexamples/bar-list/countries.tsx
"use client";
import { BarList } from "@dethink/components";
const countries = [
{ label: "United States", value: 48_210, icon: "🇺🇸" },
{ label: "Germany", value: 21_430, icon: "🇩🇪" },
{ label: "India", value: 19_880, icon: "🇮🇳" },
{ label: "United Kingdom", value: 14_050, icon: "🇬🇧" },
{ label: "Brazil", value: 9_310, icon: "🇧🇷" },
];
export function BarListCountries() {
return (
<div className="grid w-full gap-8 sm:grid-cols-2">
<BarList
aria-label="Revenue by country"
data={countries}
color="chart-6"
formatOptions={{ style: "currency", currency: "USD" }}
labelHeader="Country"
valueHeader="Revenue"
/>
<BarList
aria-label="Revenue by country, ascending"
data={countries}
color="chart-7"
sort="ascending"
formatOptions={{ style: "currency", currency: "USD" }}
labelHeader="Country"
valueHeader="Revenue"
/>
</div>
);
}| Prop | What it does | Default |
|---|---|---|
dataArray<{ key?, label, value, href?, icon?, color? }> | Rows to rank. href makes a row a link; color overrides the bar for that row. | Not set |
sort"descending" | "ascending" | "none" | Ties always keep their input order. | "descending" |
limitnumber | Rows shown before a Show more toggle. | Not set |
expanded / defaultExpanded / onExpandedChangeboolean / boolean / (expanded) => void | Controlled or uncontrolled expansion of limited lists. | — / false / — |
color"chart-1" … "chart-8" | string | One color for every bar. A single series stays one color. | "chart-1" |
maxnumber | Value that fills the track, for shares (1) or comparing lists on one scale. | Largest value |
formatValue / formatOptions(value) => string / Intl.NumberFormatOptions & { locale } | Replace or tune the value formatter. | compact |
labelHeader / valueHeaderReactNode | Column headings, such as "Page" and "Visitors". | Not set |
onItemClick(item, index) => void | Turns rows without an href into buttons, for drill-down or filtering. | Not set |
emptyLabel / showMoreLabel / showLessLabelReactNode / (hidden) => ReactNode / ReactNode | Localize the empty state and toggle text. | "No data" / "Show N more" / "Show less" |
size"sm" | "md" | Row and bar height. Bars never exceed 24px. | "md" |
animateboolean | Bars grow from the start edge. Always off under reduced motion. | true |
BarList is a list: each row reads its label and value, and the bar is decorative because the value is always visible as text. Name the list with aria-label or aria-labelledby. Link and button rows are single tab stops with a visible focus ring. The Show more button reports its state with aria-expanded and controls the list. Values stay left-to-right in right-to-left layouts, and bars grow from the start edge.