# Sparkline

> A small line or area chart that draws itself in and morphs to new data; press and drag to scrub, and a dot rides the curve while the line beyond your finger dims and every point ticks.

- Type: Component (data)
- Access: Free, open source (MIT)
- Page: https://goodui.dev/native/components/sparkline
- Markdown: https://goodui.dev/native/components/sparkline.md
- Registry item: https://goodui.dev/native/r/sparkline.json
- Dependencies: react-native-gesture-handler, react-native-reanimated, react-native-svg
- Keywords: react native sparkline, mini line chart, stock chart scrub, svg line chart expo, interactive chart react native, price chart, trend line

## When to use

- A trend next to a number: portfolio value, revenue this week, heart rate, a stock row.
- Places where the exact value at a point matters now and then: scrubbing reveals it without an axis.
- Switching ranges (1D, 1W, 1M) with the same number of points: the line morphs instead of redrawing.

## When not to use

- Charts that need axes, gridlines, legends or several series: use a full charting library.
- Progress toward a goal: use progress-ring.
- A single changing number: use rolling-number.

## Installation

With the shadcn CLI (needs a components.json in the Expo app), then `npx expo install --fix` so native dependencies match your Expo SDK. The foundation comes along the first time.

```bash
npx shadcn@latest add https://goodui.dev/native/r/sparkline.json
npx expo install --fix
```

The component lands in `components/goodui-native/sparkline/` and imports the foundation from `components/goodui-native/foundation/` with relative paths; it also installs locale.

Built-in strings follow `<GooduiLocaleProvider>` (one [language pack](https://goodui.dev/native/r/locale-tr.json) translates the whole kit); the `labels` prop overrides them for one instance.

## Usage

```tsx
import { useState } from "react";
import { Sparkline } from "@/components/goodui-native/sparkline/sparkline";
import { RollingNumber } from "@/components/goodui-native/rolling-number/rolling-number";

export function Balance({ history, dates }: { history: number[]; dates: string[] }) {
  const [point, setPoint] = useState<number | null>(null);
  const shown = point ?? history[history.length - 1];
  return (
    <>
      <RollingNumber value={shown} size="title1" format={{ style: "currency", currency: "EUR" }} />
      <Sparkline
        data={history}
        labels={dates}
        height={96}
        accessibilityLabel="Balance, last 30 days"
        formatValue={(v) => `€${v.toFixed(2)}`}
        onScrub={(p) => setPoint(p?.value ?? null)}
      />
    </>
  );
}
```

## Examples

### Line only, fixed tone, baseline

```tsx
<Sparkline data={heartRate} variant="line" tone="accent" showBaseline height={48} />
```

### Static row chart

```tsx
<Sparkline data={prices} height={32} scrub={false} showEndDot={false} />
```

## API reference

### Sparkline

`import { Sparkline } from "@/components/goodui-native/sparkline/sparkline";`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `data` (required) | `number[]` | – | Values, oldest first. Two or more points draw a line. |
| `height` | `number` | `64` | Height in points. The width fills the parent. Default 64. |
| `variant` | `"line" \| "area"` | `"area"` | `area` adds a soft fill under the line; `line` is the stroke alone. |
| `tone` | `"success" \| "danger" \| "accent" \| "neutral" \| "trend"` | `"trend"` | `trend` is green when the last value is at or above the first and red when below. |
| `strokeWidth` | `number` | `2` | Stroke width. Default 2. |
| `scrub` | `boolean` | `true` | Press and drag (or hover with a mouse) to read values. Default `true`. |
| `formatValue` | `(value: number, index: number) => string` | – | Formats a value for the scrub label and screen readers. Defaults to the locale number format. |
| `labels` | `string[]` | – | One label per point, for example dates, shown under the value while scrubbing. |
| `onScrub` | `(point: SparklinePoint \| null) => void` | – | Called when the scrubbed point changes, and with `null` when scrubbing ends. |
| `showBaseline` | `boolean` | `false` | A dashed line at the first value, so gains and losses read at a glance. |
| `showEndDot` | `boolean` | `true` | A dot on the latest value. Default `true`. |
| `haptic` | `HapticName \| false` | `"select"` | Haptic for every point the scrub crosses. `false` turns it off. |
| `animateOnMount` | `boolean` | `true` | Draw the line in when it first appears. Default `true`. |
| `accessibilityLabel` | `string` | – | What the chart shows, for example "Portfolio, last 7 days". Same as the pack's `chart` string. |
| `style` | `StyleProp<ViewStyle>` | – | Style for the outer container. |
| `testID` | `string` | – | Identifier for end-to-end tests. |

## Accessibility

- One adjustable element: the label summarises the range (from, to, high, low).
- Swiping up or down with a screen reader steps through the points and announces each value and label.
- The scrub label is hidden from screen readers; the value is exposed through accessibilityValue.
- On the web it is a focusable slider whose value is the scrubbed point (else the latest); arrow keys step through the points.

## Motion

- On first appearance the line draws itself in over 720 ms and the area fades in behind it.
- New data with the same number of points morphs on the smooth spring; a different count draws in again.
- While scrubbing a dot rides the curve under the finger, a guide line follows it, and the line beyond the finger dims to a muted copy.
- Reduced motion: no drawing or morphing; the chart fades in and changes at once.

## Haptics

- select for every point the finger crosses while scrubbing (configurable with the haptic prop); none on hover or mount

## Performance

- Path, dot, guide and dimming are animated props on the UI thread; the finger never causes a React render per frame.
- React renders once each time the scrub crosses into a new point, to update the label.
- Built for tens to a few hundred points; downsample longer series first.

## Notes for AI

- data is plain numbers, oldest first; pass labels for dates instead of objects.
- Use onScrub to drive a headline number (rolling-number) and fall back to the latest value on null.
- The width fills its parent; set height only.
- Wrap it in a scroll view freely: vertical drags scroll, horizontal drags scrub.

## Related

- [Rolling number](https://goodui.dev/native/components/rolling-number.md): A number whose digits roll in the direction of change, with digits that open and close in place and currency signs that glide instead of jumping.
- [Progress ring](https://goodui.dev/native/components/progress-ring.md): A circular progress ring that fills on a spring, laps itself past 100 % with a gap that lifts the lap off the ring, and bounces once with a success haptic when it completes.
- [Segmented control](https://goodui.dev/native/components/segmented-control.md): Two to five views of the same thing with an elastic highlight that stretches toward the new segment, can be dragged, and ticks at every boundary. Includes a billing toggle.

## Guidance for AI tools

Sparkline: A small line or area chart that draws itself in and morphs to new data; press and drag to scrub, and a dot rides the curve while the line beyond your finger dims and every point ticks. Use only the documented props. Keep accessibility, reduced motion and both color schemes intact when adapting it.

Full library index: https://goodui.dev/native/llms.txt
