Skip to content
txbrendan/ui

Sparkline

beta

A tiny trend line, inline with text or in a table cell. Plain SVG, with no Recharts.

Preview

Texture

tone

neutralbranddangersuccesswarning

area

size

in text

Revenue grew this quarter and reached $23.9K a week.

in a table

MetricLast 9 weeksNow
Revenue$23.9K
Churn5.6%
Latency201 ms

loading

one value

empty

Install

  1. 1. Add the registry to components.json, once per app. Without it, the shadcn CLI looks up @txbrendan in a public list that txbrendan/ui does not control.

    npx shadcn@latest registry add "@txbrendan=https://txbrendan.dev/r/{name}.json"
  2. 2. Add the theme, once per app. It replaces your color tokens with ones checked for contrast.

    npx shadcn@latest add @txbrendan/theme
  3. 3. Add the component.

    npx shadcn@latest add @txbrendan/sparkline

Use it for

  • Showing the shape of a trend next to a number, in a stat card, or in a table row.
  • Name it with aria-label, like "Revenue, last 30 days". Screen readers hear the name with the first and last values.
  • Use tone for meaning: success for a good trend, danger for a bad one, neutral when it is neither.
  • Pass the numbers oldest first.

Avoid it for

  • When people need to read exact values or dates. Use LineChart, which has axes and a tooltip.
  • Comparing two or more series. Use LineChart.
  • As the only place a number appears. Show the current value in text next to it.

Props

  • data

    The numbers to draw, oldest first. Values that are not finite numbers are skipped.

    number[]

  • aria-label

    Required. Names the trend. Screen readers hear it with the first and last values.

    string

  • tone

    The line's color role.

    "neutral" | "brand" | "danger" | "success" | "warning" · default "neutral"

  • size

    Height and width, from --control-h-sm, so density scales it. Small fits a line of text.

    "sm" | "md" | "lg" · default "md"

  • area

    Fills the space under the line with the tone at 15%.

    boolean · default false

  • loading

    Shows a skeleton at the same size.

    boolean · default false

  • valueFormat

    Formats the first and last values that screen readers hear.

    Intl.NumberFormatOptions

  • locale

    The locale for those numbers.

    string · default "en-US"

  • texture

    dither draws the area as dots, gradient fades it from the top, and grain speckles it. The line glows on dark pages. Hover fills gradient and grain in. Left out, the line follows the Texture around it.

    "flat" | "dither" | "gradient" | "grain"

  • className

    Extra classes. Later classes win, so className='w-full' stretches it.

    string

Accessibility

  • Renders a <span role="img">. Its name is your aria-label plus the first and last values, like "Revenue: 12.4 to 23.9". TypeScript requires aria-label.
  • The words it adds, "to", "loading", and "no data", are English.
  • The SVG inside is hidden from screen readers, so they hear the name once.
  • The line takes the tone's solid color, which the theme tests hold to 3:1 against the page and cards, in light and dark.
  • It has no tab stop, because it has nothing to interact with. Put exact values in text nearby.
  • It draws on the server and never animates, so its space and shape are in the static HTML.

Examples

Next to a number

<p className="flex items-center gap-2">
  $23.9K
  <Sparkline data={[12.4, 14.1, 13.2, 16.8, 18.7, 23.9]} tone="success" aria-label="Revenue, last 6 weeks" />
</p>

In a table cell, filled

<td>
  <Sparkline data={row.history} area tone="brand" aria-label={`${row.name}, last 30 days`} />
</td>

While it loads

<Sparkline data={data ?? []} loading={isLoading} aria-label="Revenue, last 6 weeks" />

A grain area that fills in on hover

<Sparkline area tone="success" data={[4, 6, 5, 8, 7, 9]} texture="grain" aria-label="Revenue, last 6 weeks" />