Bar
A grouped or stacked bar chart, colored from a theme-derived series palette, with an interactive value readout and opt-in clickable bars.
Live demo
Bar plots one or more numeric series across a set of categories as an SVG chart that renders from data alone. Each series takes its color from a scheme resolved off the live theme (the accents fan, the skittles hue ring, a thermal cold-to-hot scale, or the status roster), so a chart is coherent with the rest of the UI out of the box; pass an explicit color array for full control, and reverse to flip any scheme.
Bars sit side by side by default or stack with stacked, and run vertically or horizontally (orientation) for long category labels. It's interactive: hovering or focusing a bar dims the rest and floats a value readout, and the whole chart is mirrored into a visually-hidden data table so assistive tech reads the numbers, not the pixels. Set selectable to make it a drill-in surface: each bar becomes a button that fires a select event with its series, category, and value, so a click filters, navigates, or drills into that data. A value axis with gridlines and category labels come derived; a legend appears for multi-series data. Set height for the plot area; the chart fills its container's width. With no categories or series to plot, it shows a muted No data message in place of the axes.
When to use
How this component composes with the rest of the set.
Props
12 props, straight from the manifest.
| Prop | Type | Default | Bindings | Description |
|---|---|---|---|---|
Appearance
States
bar-hover
Pointer over or keyboard focus on a bar: the rest dim and a value readout floats above it.
bar-focus
Keyboard focus on a bar draws a token ring; each bar is a tab stop that announces its series, category, and value.
Anatomy
The named parts that make up the component, with their selectors.
chart
The <figure> root holding the SVG plot, legend, tooltip, and the accessible data table.
bar
A single value bar, filled with its series color; the focus/hover target.
grid
The value gridlines, axis baseline, and tick labels.
legend
The series key, shown for multi-series charts; each item pairs a color dot with the series name.
tooltip
The floating value readout shown on hover or focus of a bar.
Tokens & coverage
What the component consumes, checked live against what the algorithm produces.
Live coverage check against the xtyle-default register
(derive(xtyleDefault, { anchors }) →
coverComponent(manifest, register)). Every token this component
consumes must be a key the algorithm produces.
--border-thick
--border-thin
--duration-fast
--ease-standard
--elevation-3
--fg-0
--fg-1
--fg-2
--fg-3
--font-sans
--leading-normal
--line
--line-2
--radius-md
--radius-sm
--ring
--space-1
--space-2
--space-3
--surface-overlay
--surface-overlay-border
--text-sm
--text-xs
--weight-semibold
Accessibility
Code
Grouped series
Two series across four categories, colored from the accents scheme, with an interactive readout.
<xtyle-bar
categories='["Q1","Q2","Q3","Q4"]'
scheme="accents"
label="Revenue by quarter"
height="280"></xtyle-bar>
<script>
document.querySelector("xtyle-bar").series = [
{ name: "Web", values: [12, 19, 15, 22] },
{ name: "Mobile", values: [8, 14, 18, 25] },
];
</script>
<script lang="ts">
import { Bar } from "@xtyle/svelte";
const categories = ["Q1", "Q2", "Q3", "Q4"];
const series = [
{ name: "Web", values: [12, 19, 15, 22] },
{ name: "Mobile", values: [8, 14, 18, 25] },
];
</script>
<Bar {categories} {series} scheme="accents" label="Revenue by quarter" height={280} />
---
import { Bar } from "@xtyle/astro";
const categories = ["Q1", "Q2", "Q3", "Q4"];
const series = [
{ name: "Web", values: [12, 19, 15, 22] },
{ name: "Mobile", values: [8, 14, 18, 25] },
];
---
<Bar categories={categories} series={series} scheme="accents" label="Revenue by quarter" height={280} />
Stacked
stacked folds each category's series into one bar; here on the thermal scale.
<xtyle-bar
categories='["Mon","Tue","Wed","Thu","Fri"]'
scheme="thermal"
stacked
label="Load by tier"></xtyle-bar>
<script>
document.querySelector("xtyle-bar").series = [
{ name: "CPU", values: [30, 45, 28, 52, 40] },
{ name: "IO", values: [20, 18, 34, 22, 30] },
{ name: "Net", values: [12, 22, 16, 28, 18] },
];
</script>
<script lang="ts">
import { Bar } from "@xtyle/svelte";
const categories = ["Mon", "Tue", "Wed", "Thu", "Fri"];
const series = [
{ name: "CPU", values: [30, 45, 28, 52, 40] },
{ name: "IO", values: [20, 18, 34, 22, 30] },
{ name: "Net", values: [12, 22, 16, 28, 18] },
];
</script>
<Bar {categories} {series} scheme="thermal" stacked label="Load by tier" />
---
import { Bar } from "@xtyle/astro";
const categories = ["Mon", "Tue", "Wed", "Thu", "Fri"];
const series = [
{ name: "CPU", values: [30, 45, 28, 52, 40] },
{ name: "IO", values: [20, 18, 34, 22, 30] },
{ name: "Net", values: [12, 22, 16, 28, 18] },
];
---
<Bar categories={categories} series={series} scheme="thermal" stacked label="Load by tier" />
Horizontal
orientation="horizontal" runs bars rightward with the categories down the side. A single series colors by category, so each bar takes its own skittles hue.
<xtyle-bar
categories='["Rust","TypeScript","Svelte","Astro","CSS"]'
orientation="horizontal"
scheme="skittles"
label="Lines by language"
height="240"></xtyle-bar>
<script>
document.querySelector("xtyle-bar").series = [
{ name: "Lines", values: [4200, 3800, 1500, 900, 2100] },
];
</script>
<script lang="ts">
import { Bar } from "@xtyle/svelte";
const categories = ["Rust", "TypeScript", "Svelte", "Astro", "CSS"];
const series = [{ name: "Lines", values: [4200, 3800, 1500, 900, 2100] }];
</script>
<Bar {categories} {series} orientation="horizontal" scheme="skittles" label="Lines by language" height={240} />
---
import { Bar } from "@xtyle/astro";
const categories = ["Rust", "TypeScript", "Svelte", "Astro", "CSS"];
const series = [{ name: "Lines", values: [4200, 3800, 1500, 900, 2100] }];
---
<Bar categories={categories} series={series} orientation="horizontal" scheme="skittles" label="Lines by language" height={240} />
Actionable bars
selectable makes each bar a button that fires select on click or Enter/Space, so a chart can drive a drill-in. The detail carries the series, category, value, and both indices.
<xtyle-bar
categories='["Alpha","Bravo","Charlie","Delta"]'
label="Runs by workflow"
selectable
height="240"></xtyle-bar>
<script>
const bar = document.querySelector("xtyle-bar");
bar.series = [{ name: "Runs", values: [42, 30, 18, 9] }];
bar.addEventListener("select", (e) => {
openWorkflow(e.detail.category);
});
</script>
<script lang="ts">
import { Bar } from "@xtyle/svelte";
const categories = ["Alpha", "Bravo", "Charlie", "Delta"];
const series = [{ name: "Runs", values: [42, 30, 18, 9] }];
</script>
<Bar
{categories}
{series}
label="Runs by workflow"
selectable
height={240}
onselect={(e) => openWorkflow(e.detail.category)}
/>
---
import { Bar } from "@xtyle/astro";
const categories = ["Alpha", "Bravo", "Charlie", "Delta"];
const series = [{ name: "Runs", values: [42, 30, 18, 9] }];
---
<Bar categories={categories} series={series} label="Runs by workflow" selectable height={240} />
<script>
document.querySelector("xtyle-bar").addEventListener("select", (e) => {
openWorkflow(e.detail.category);
});
</script>