motion-sparkline

A small trend line that fits inside a sentence, a table cell or a stat tile. It draws itself in when it scrolls into view, and springs to new values when the data changes. It takes the text color, so it matches the text around it.

Preview

Signups this week are up 38%.

Response time fell to 240 ms.

<p>Signups this week <motion-sparkline values="3, 5, 4, 8, 7, 11"></motion-sparkline> are up 38%.</p>

Quick start

Save this as index.html and open it in a browser. No install, no build step.

<!doctype html>
<html>
  <head>
    <script type="module" src="https://cdn.jsdelivr.net/npm/motion-components@1/dist/motion-sparkline.js/+esm"></script>
  </head>
  <body>
    <p>Signups this week <motion-sparkline values="3, 5, 4, 8, 7, 11"></motion-sparkline></p>
  </body>
</html>

In a project with a bundler, install the package and import the component once:

npm install motion-components
import 'motion-components/motion-sparkline'

In a table

Put a sparkline in a table cell to show the trend next to the latest value.

ProductSalesLast 8 weeks
Starter1,240
Pro860
Team310
<td>
  <motion-sparkline values="5, 7, 6, 8, 9, 11, 10, 14"></motion-sparkline>
</td>

Stat tile

Combine it with motion-counter for a number that counts up above its trend. area adds a light wash under the line.

Revenue
<div class="stat">
  <span class="stat-label">Revenue</span>
  <motion-counter to="48.2" decimals="1" duration="1.4" prefix="€" suffix="K"></motion-counter>
  <motion-sparkline values="31, 35, 33, 38, 41, 39, 45, 48" area></motion-sparkline>
</div>
.stat {
  display: grid;
  gap: 0.25rem;
  font-size: 2rem;
  font-weight: 700;
}

.stat-label {
  font-size: 0.85rem;
  font-weight: 500;
}

.stat motion-sparkline {
  --mc-sparkline-width: 100%;
  --mc-sparkline-height: 2.5rem;
}

Live data

Change values and the line springs to the new shape. From JavaScript you can also set data to an array of numbers, such as spark.data = [12, 14, 13]. It takes precedence over values.

Active users

<motion-sparkline id="users" values="12, 14, 13, 15, 17, 16, 18, 20"></motion-sparkline>

<script type="module">
  const spark = document.querySelector('#users')

  setInterval(() => {
    const values = spark.values.split(',').map(Number)
    const next = Math.max(0, values.at(-1) + Math.round(Math.random() * 6 - 3))
    spark.values = [...values.slice(1), next].join(', ')
  }, 1500)
</script>

More patterns, such as a period switcher, a chart from a form and data from a JSON file, are on the Chart Recipes page.

Properties

Attribute Property Type Default Description
values values string '' Comma-separated numbers. At least two
data data number[] null Property only: the numbers as an array, set from JavaScript. Takes precedence over values
area area boolean false Fills the area under the line with a light wash
label label string '' Accessible name. Without it, the name describes the trend
trigger trigger string 'view' When the draw-in runs: 'view' or 'mount'
duration duration number 1 Spring duration in seconds
bounce bounce number 0.2 Spring bounciness when the values change

CSS custom properties

Property Type Default Description
--mc-sparkline-width length 6em Width
--mc-sparkline-height length 1.5em Height
--mc-sparkline-color color currentColor Line color
--mc-sparkline-accent color line color Color of the dot on the last value

JavaScript API

replay() draws the line in again. It also has play(), pause(), finish(), cancel() and playState. See the JavaScript API.

Accessibility

The sparkline has role="img" and a name that describes the trend, for example "from 3 to 11, low 3, high 11". Set label to give it your own name. With prefers-reduced-motion, the line shows at once and changes without animation.