Chart
An SVG chart component for dashboards with line, area, bar, and donut types. Data-driven from a series array, with automatic nice-tick scales, a legend, hover crosshair and tooltips, and a visually-hidden data table for assistive technology.
<arc-chart> Overview
>
Chart renders line, area, grouped/stacked bar, and donut charts from plain JavaScript data — no external charting library. Pass a `series` array of `{ label, data }` objects and a `labels` array of x-axis categories, and the component computes a nice 1/2/5-step y scale, recessive horizontal gridlines, abbreviated axis numbers (1.2k, 3.4M), and thin marks in the fixed ARC chart palette.
Series colors are assigned in fixed order from `--chart-1` through `--chart-6` and are never cycled. When more than six series are provided, the extras are summed into an "Other" series and flagged in the legend, so identity stays readable. The legend renders automatically for two or more series and is omitted for a single series.
A hover layer ships by default: line and area charts show a vertical crosshair with a tooltip listing every series value at the hovered category, while bar and donut charts show per-mark tooltips. Hit targets are invisible full-height columns per category, so users never have to hit a 2px line. Clicking a mark emits `arc-mark-click` with the series index, category index, and value. For assistive technology, the chart container carries a generated `role="img"` summary and a visually-hidden `<table>` exposes the real values.Guidelines
When to use
- Keep charts to 6 or fewer series — beyond that, pre-aggregate or split into small multiples
- Use type="area" for a single dominant series and type="line" when comparing trends
- Use stacked only when the total is meaningful; use grouped bars to compare series per category
- Set value-format="percent" with fractional data (0.24 renders as 24%)
- Provide a label for every series — labels drive the legend, tooltip, and data table
- Listen to arc-mark-click to drive drill-down navigation or detail panels
When not to use
- Do not plot two measures of different scale on one chart — there is one y-axis, never dual axes
- Do not use donut charts for more than ~6 segments or for precise comparisons — use bars instead
- Do not hide the legend on multi-series charts unless the series are directly labeled nearby
- Do not encode meaning in custom mark colors — the fixed palette keeps series identity consistent
- Do not use hide-axis on charts where readers need to look up values — it is for compact trend panels
- Do not feed stacked bars negative values; stacking assumes non-negative data
Features
- Four chart types: line, area, grouped bar, stacked bar, and donut
- Fixed-order series colors `--chart-1` through `--chart-6`, never cycled
- More than 6 series automatically fold into a summed "Other" series
- Nice-tick y scale (1/2/5 steps) with abbreviated axis numbers (1.2k, 3.4M)
- Single y-axis with recessive 1px horizontal gridlines only
- Hover crosshair + all-series tooltip on line/area; per-mark tooltips on bar/donut
- Full-plot-height invisible hover columns — no pixel-hunting thin marks
- `arc-mark-click` event with seriesIndex, index, and value
- Intl.NumberFormat value formatting: number, percent, or currency
- Legend with 8px color chips, rendered automatically for 2+ series
- `role="img"` summary label plus a visually-hidden data table for AT users
- ResizeObserver-driven responsive width; respects `prefers-reduced-motion`
- Styleable via ::part(chart), ::part(legend), ::part(tooltip), ::part(axis)
Preview
No data
No data
Usage
This component requires JavaScript. No pure HTML/CSS version is available — use the Web Component directly or a framework wrapper.
<arc-chart id="revenue-chart" type="bar" stacked value-format="currency" height="280"></arc-chart>
<script type="module">
import '@arclux/arc-ui/chart';
const chart = document.querySelector('#revenue-chart');
chart.labels = ['Q1', 'Q2', 'Q3', 'Q4'];
chart.series = [
{ label: 'Subscriptions', data: [42000, 48000, 51000, 62000] },
{ label: 'Services', data: [18000, 16500, 21000, 24000] },
{ label: 'Licensing', data: [9000, 11000, 10500, 14000] }
];
chart.addEventListener('arc-mark-click', (e) => {
const { seriesIndex, index, value } = e.detail;
console.log('clicked', seriesIndex, index, value);
});
</script> import { Chart } from '@arclux/arc-ui-react';
const labels = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'];
const series = [
{ label: 'Sessions', data: [1200, 1850, 1640, 2100, 2400, 1980] },
{ label: 'Signups', data: [180, 240, 210, 320, 380, 300] }
];
export function TrafficChart() {
return (
<Chart
type="line"
labels={labels}
series={series}
height={280}
onArcMarkClick={(e) => console.log(e.detail)}
/>
);
} <script setup>
import { Chart } from '@arclux/arc-ui-vue';
const labels = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'];
const series = [
{ label: 'Sessions', data: [1200, 1850, 1640, 2100, 2400, 1980] },
{ label: 'Signups', data: [180, 240, 210, 320, 380, 300] }
];
</script>
<template>
<Chart type="line" :labels="labels" :series="series" :height="280" />
</template> <script>
import { Chart } from '@arclux/arc-ui-svelte';
const labels = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'];
const series = [
{ label: 'Sessions', data: [1200, 1850, 1640, 2100, 2400, 1980] },
{ label: 'Signups', data: [180, 240, 210, 320, 380, 300] }
];
</script>
<Chart type="line" {labels} {series} height={280} on:arc-mark-click={(e) => console.log(e.detail)} /> import { Component } from '@angular/core';
import { Chart } from '@arclux/arc-ui-angular';
@Component({
imports: [Chart],
template: `
<arc-chart
type="line"
[labels]="labels"
[series]="series"
[height]="280"
(arcMarkClick)="onMarkClick($event)"
></arc-chart>
`,
})
export class TrafficChartComponent {
labels = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'];
series = [
{ label: 'Sessions', data: [1200, 1850, 1640, 2100, 2400, 1980] },
{ label: 'Signups', data: [180, 240, 210, 320, 380, 300] }
];
onMarkClick(e: CustomEvent) {
console.log(e.detail);
}
} API
-
type'line' | 'area' | 'bar' | 'donut''line' - The chart form. Line and area share the x axis across all series; bar renders grouped columns (or stacked with the `stacked` attribute); donut renders one segment per series (or per category when a single series is given).
-
seriesArray<{label:string,data:number[]}>[] - The data that drives the chart. Each entry is one series; all series share the x axis defined by `labels`. Set via JavaScript property, not an attribute. Colors are assigned in fixed order from --chart-1 to --chart-6; series beyond six are summed into an "Other" series noted in the legend.
-
labelsstring[][] - Category labels for the x axis (or donut segment names when a single series is given). Labels that would collide are automatically thinned — every Nth label renders based on available width.
-
stackedbooleanfalse - Bar type only. Stacks series segments on a shared baseline with 2px surface gaps between segments; only the outermost segment gets the rounded value end. Assumes non-negative data.
-
hide-legendbooleanfalse - Suppresses the legend. By default the legend renders for two or more series and is omitted for a single series.
-
hide-axisbooleanfalse - Removes the axis layer — gridlines, y tick labels, and x category labels — for compact trend panels where exact values are read from the tooltip.
-
heightnumber260 - Chart height in pixels. Width is fluid and tracked with a ResizeObserver.
-
value-format'number' | 'percent' | 'currency''number' - How values are formatted in tooltips, the axis, and the accessible data table, via Intl.NumberFormat. Percent expects fractional data (0.24 → 24%). Axis numbers are abbreviated (1.2k, 3.4M).
-
currencystring'USD' - ISO 4217 currency code used when value-format="currency".
Events
-
arc-mark-click - Fired when a mark (bar, stacked segment, line point column, or donut segment) is clicked. detail: { seriesIndex, index, value }. Indices refer to displayed series after any "Other" folding; a folded donut segment reports seriesIndex -1.
See Also
- Sparkline Tiny inline SVG chart for embedding lightweight line or bar visualizations inside tables, stat cards, and dashboards. Renders from a simple comma-separated data string with no external charting dependencies.
- Stat Numeric statistic display with gradient value and label.
- Data Table A data-driven table component that renders rows from a JavaScript array. Declarative column definitions via `arc-column` children control which fields appear, their headers, widths, and sort behavior. Built-in support for column sorting, row selection with checkboxes, and an empty-state fallback.
- Meter Semantic gauge display with color-coded fill zones (success, warning, error) based on configurable low/high/optimum thresholds.