Dither Chart

Open in v0

Last updated: September 20, 2026

A family of retro ordered-dithered micro-charts drawn on Canvas2D, where every fill is quantised through a Bayer matrix into a dot pattern.

Installation

npx smoothui-cli add dither-chart

Features

Eight chart variants from a single component and a single data shape. Ordered dithering through a Bayer matrix — every fill becomes a dot pattern instead of a solid.

Scroll the sections below — the panel shows one chart type at a time.

Variants

Line

Dithered area under a 1px stroke, one layer per series — weekly visitors and signups.

Bar

Grouped bars, one group per point index.

Bubbles

Circles positioned by value with value-driven radius.

Donut

One ring slice per point, sweeping in on draw-in — traffic share by channel.

Funnel

Centred rows whose width follows each value — conversion funnel, top to bottom.

Gauge

270° dial, value read as a 0–100 percentage — uptime as a dial.

Heatmap

Grid of cells whose dither density follows the value — activity per slot and day.

Stacked

Stacked bars normalised against the tallest stack.

Every variant is also exported as the DITHER_CHART_VARIANTS const array, so you can map over the whole family.

import DitherChart, {
  DITHER_CHART_VARIANTS,
} from "@repo/smoothui/components/dither-chart";

Accessibility

ARIA Attributes

AttributeElementPurpose
aria-hidden="true"<canvas>The canvas is purely decorative — its pixels carry no accessible information
sr-only text node<span> next to the canvasText alternative listing the variant, every series name and every point value
<figcaption>Caption elementAssociates the visible caption with the figure

Screen Reader

  • The chart is wrapped in a <figure>. The canvas itself is hidden from assistive technologies and a visually hidden sibling describes the chart in full: label, variant, series names and every value.
  • The optional caption is rendered as a real <figcaption> so it is announced as part of the figure.
  • Nothing inside the component is focusable, so it never interrupts the tab order.

Reduced Motion

This component respects prefers-reduced-motion via useReducedMotion from Motion. When reduced motion is preferred, the final frame is drawn immediately on mount — no requestAnimationFrame loop is started and no IntersectionObserver draw-in is scheduled. Setting animate={false} produces the same static result for everyone.

Props

Created by

Powered by

motion.dev

© 2026 SmoothUI. Built by Eduardo Calvo.