data

<tc-chart>

Pure-SVG, themeable, responsive charts in five flavors — line, area, bar, sparkline, donut. ~11 KB minified; every element is a real DOM node screen readers can reach.

import "@ra9/tan-compose-kit/chart"

Props

NameTypeDefaultDescription
type"line" | "area" | "bar" | "sparkline" | "donut""line"Chart type. Unknown values fall back to `line`.
dataChartData{ series: [] }Data to plot. For line/area/bar/sparkline pass `{ labels, series:[{name, values}] }`; for donut pass `{ series:[{name, value}] }`.
heightstring"240px"Any CSS length. The chart fills the host width and uses this for its viewport height.
smoothbooleantrueCatmull-Rom curves for line and area. Set to `false` for jagged polylines.
stackedbooleanfalseStack series vertically. Applies to `area` and `bar`.
showLegendbooleantrueSeries legend below the chart.
showAxesbooleantrueRender axis chrome (Y labels, baseline). Ignored for sparkline / donut.
showGridbooleantrueHorizontal grid lines at Y-axis ticks.
showLabelsbooleantrueShow X-axis tick labels. Auto-strides when there are too many.
showValuesbooleanfalseRender the value next to each data point / bar / segment.
innerRadiusnumber0.6Donut only. `0` = pie. `0.9` = thin ring.
yMinnumber?nullForce the y-axis minimum. Auto when null.
yMaxnumber?nullForce the y-axis maximum. Auto when null.
ariaLabelstring"Chart"Accessible name for the chart.
colorsstring[] | nullnullOverride the default series palette. Pass any valid CSS color (hex, `rgb`, `var(--token)`, etc.).

CSS variables

VariableDefaultDescription
--tc-chart-bgtransparentChart background.
--tc-chart-fgvar(--tc-color-ink)Foreground text color.
--tc-chart-axisvar(--tc-color-rule-strong)Baseline / axis stroke.
--tc-chart-gridvar(--tc-color-rule)Gridline stroke.
--tc-chart-labelvar(--tc-color-ink-muted)Axis and value-label fill.
--tc-chart-color-1var(--tc-color-accent)First series color.
--tc-chart-color-2var(--tc-color-info)Second series color.
--tc-chart-color-3..8Up to 8 series colors, falling back to semantic tokens. Override per host to brand.

Examples

Why a custom chart component

Chart.js, Recharts, Apex, and ECharts all render to <canvas>, which means:

  • Series colors live in JS config, not CSS tokens — you can't theme them by importing your dark preset.
  • Canvas elements expose nothing to assistive tech beyond an alt-text guess. A screen reader gets "chart".
  • Each library is 100–400 KB before plugins.

tc-chart renders pure SVG, themes via CSS custom properties, exposes every point as a real DOM element with a <title> and structured aria description, and weighs ~11 KB minified.

Line — multi-series

<tc-chart type="line" data='{ "labels": ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug"], "series": [ {"name":"Sessions","values":[420,460,510,530,640,720,790,830]}, {"name":"Signups","values":[80,95,110,130,140,180,210,240]} ] }' ></tc-chart>

Area — stacked

<tc-chart type="area" stacked data='{ … }'></tc-chart>

Bar — grouped

<tc-chart type="bar" data='{ "labels": ["Mon","Tue","Wed","Thu","Fri","Sat","Sun"], "series": [ {"name":"Reads","values":[120,150,180,170,190,80,60]}, {"name":"Writes","values":[40,55,70,60,75,20,15]} ] }' ></tc-chart>

Sparkline — inline mini-trend

Sparklines drop the axes, grid, and legend so they sit inline with text.

Revenue this quarter +216%
<tc-chart type="sparkline" height="32px" showLegend="false" style="width: 140px;" data='{ "series": [{"name":"r","values":[12,18,15,22,28,24,32,38]}] }' ></tc-chart>

Donut — composition

<tc-chart type="donut" showValues data='{ "series": [ {"name":"Mobile","value":52}, {"name":"Desktop","value":31}, {"name":"Tablet","value":12}, {"name":"Other","value":5} ] }' ></tc-chart>

Pie (innerRadius=0)

<tc-chart type="donut" innerRadius="0" data='{ … }'></tc-chart>

Driven from JavaScript

The data prop is just JSON — set the property directly for live updates.

<tc-chart id="live" type="line" height="240px"></tc-chart> <script> const chart = document.getElementById("live"); chart.data = { labels: ["10:00","10:05","10:10","10:15","10:20"], series: [{ name: "Requests/s", values: [320, 410, 380, 520, 470] }], }; // Hot-swap a series later: setInterval(() => { const next = Array.from({ length: 5 }, () => Math.round(300 + Math.random() * 300)); chart.data = { labels: chart.data.labels, series: [{ name: "Requests/s", values: next }] }; }, 2000); </script>

Brand colors

Three layers to bring the chart in line with brand:

  1. Override series colors per chart via the colors prop.
  2. Override the series palette tokens (--tc-chart-color-18) on the host so every chart that doesn't pass colors picks them up.
  3. Restyle the chart chrome with --tc-chart-axis, --tc-chart-grid, --tc-chart-label.
<tc-chart type="bar" style=" --tc-chart-color-1: #5b6cf0; --tc-chart-color-2: #f25c5c; --tc-chart-grid: rgba(91, 108, 240, 0.12); --tc-chart-axis: #5b6cf0; " data='{ … }' ></tc-chart>

…or pass a specific palette inline:

<tc-chart type="donut" colors='["#0ea5e9","#22c55e","#eab308","#ef4444"]' data='{ "series": [ {"name":"Up","value":92}, {"name":"Warn","value":5}, {"name":"Down","value":2}, {"name":"Maint","value":1} ] }' ></tc-chart>

Manual y-axis bounds

Force the y-axis to a known range with yMin and yMax — useful for KPI dashboards where the relative magnitude matters more than the auto-fit.

<tc-chart type="line" yMin="0" yMax="100" data='{ "labels": ["Mon","Tue","Wed","Thu","Fri"], "series": [{"name":"Uptime %","values":[99.2, 99.7, 99.9, 99.4, 99.6]}] }' ></tc-chart>

Accessibility

  • The chart container has role="img" and the ariaLabel prop becomes its accessible name. Pass something meaningful like "Weekly request volume by region".
  • A visually-hidden description below the chart enumerates the series and point count for screen readers ("Line chart with 2 series (Sessions, Signups) and 8 data points.").
  • Every data point, bar, and donut segment is a real SVG element with a <title> child — desktop screen readers and tooltips both pick this up.
  • prefers-reduced-motion: reduce disables the hover scale on segments and points.

Responsiveness

The host is display: block; width: 100% by default, so the chart fills its container. The SVG uses a fixed internal viewBox (0 0 800 400 for cartesian, 0 0 320 320 for donut) and scales to the host. Set the visual height with the height prop or a wrapper.

For a chart inside a grid card:

<tc-card title="Active users"> <tc-chart type="line" height="200px" data='{ … }'></tc-chart> </tc-card>

Theming

The default palette resolves through semantic tokens, so loading a theme preset (light, dark, bootstrap, tailwind, material, shadcn) re-skins every chart automatically. To bake a chart-specific palette into your design system, set the chart tokens at :root:

:root { --tc-chart-color-1: #0ea5e9; --tc-chart-color-2: #22c55e; --tc-chart-color-3: #eab308; --tc-chart-color-4: #ef4444; --tc-chart-grid: rgba(11, 11, 12, 0.06); --tc-chart-axis: rgba(11, 11, 12, 0.18); }

Limits, by design

  • One chart type per element. Multi-axis / combined line+bar isn't supported; compose two charts side-by-side instead.
  • No hover crosshair / shared tooltip yet — the per-element <title> covers most use cases.
  • No animations on data swap (yet). A data change re-renders immediately; users get an instant update rather than a transition.
  • Donut data shape is single-series. For nested donuts, stack two <tc-chart> instances.