Skip to content

Repository files navigation

react-native-dither-kit

High-performance dithered charts and pixel surfaces for React Native. The API tracks Dither Kit's composable chart vocabulary while replacing the browser canvas and SVG layers with React Native Skia and Reanimated 4.

  • Area, line, bar, pie/donut, radar, and sparkline charts
  • Ordered-dither gradients, dots, hatching, bloom, and deterministic sparkles
  • Tap-to-pin, long-press scrubbing, pointer hover, clickable legends, and adjustable screen-reader actions
  • No SVG, Tailwind, or JavaScript animation loop
  • Installable Expo 57 development example in example/
iPhone 17e · iOS 26.3 development build Android Medium Phone
React Native Dither Kit development build React Native Dither Kit on Android
Selected area + pinned bar · iPhone 17e Pinned bar · iPhone 16e
Selected chart series and bar tooltip Compact bar tooltip

Install

npx expo install react-native-dither-kit \
  @shopify/react-native-skia@2.10.0 \
  react@19.2.8 \
  react-dom@19.2.8 \
  react-native@0.86.2 \
  react-native-gesture-handler@3.1.0 \
  react-native-reanimated@4.5.3 \
  react-native-worklets@0.11.3

Wrap the app once with GestureHandlerRootView:

import { GestureHandlerRootView } from "react-native-gesture-handler";

export default function App() {
  return (
    <GestureHandlerRootView style={{ flex: 1 }}>
      <Charts />
    </GestureHandlerRootView>
  );
}

Area chart

import {
  Area,
  AreaChart,
  Grid,
  Legend,
  Tooltip,
  XAxis,
  YAxis,
  type ChartConfig,
} from "react-native-dither-kit";

const data = [
  { month: "Jan", desktop: 186, mobile: 120 },
  { month: "Feb", desktop: 205, mobile: 98 },
];

const config: ChartConfig = {
  desktop: { label: "Desktop", color: "blue" },
  mobile: { label: "Mobile", color: 280 },
};

<AreaChart
  data={data}
  config={config}
  stackType="stacked"
  style={{ height: 300 }}
>
  <Grid />
  <XAxis dataKey="month" />
  <YAxis />
  <Area dataKey="desktop" variant="gradient" isClickable />
  <Area dataKey="mobile" variant="hatched" isClickable />
  <Legend isClickable />
  <Tooltip labelKey="month" />
</AreaChart>;

Descriptors may be grouped in React fragments. Keep them as direct children or fragment descendants; wrapper components are not rendered by the chart parser.

Theming

Chart chrome — axes, legend, tooltip, markers — uses a small token set. Pass theme on any chart, wrap your app in ChartThemeProvider, or use the built-in presets:

import {
  AreaChart,
  ChartThemeProvider,
  LIGHT_CHART_THEME,
} from "react-native-dither-kit";

<ChartThemeProvider theme={LIGHT_CHART_THEME}>
  <AreaChart data={data} config={config} style={{ height: 300 }}></AreaChart>
</ChartThemeProvider>

// Or override a single chart:
<AreaChart theme={{ foreground: "#111", muted: "#666", border: "#ddd" }}  />

ChartTheme fields: foreground, muted, card, border, borderActive, popover, popoverBorder, popoverFrosted, popoverFrostedBorder, fontFamily. Series dither colors stay on config.color (palette name or hue).

Use variant="gradient" | "dotted" | "hatched" | "solid" and bloom="off" | "low" | "high" | "aura" across chart families. Series colors are a palette name ("blue", "purple", …) or a hue in degrees (280 for brand accents). Bloom defaults to "off"; "low", "high", and "aura" are opt-in offscreen-blur effects. Profile those presets on the Android devices you support before enabling them across a scrolling gallery or long list.

Expo and native setup

The package is JavaScript-only, but its peer dependencies include native code. The included Expo 57 example intentionally carries newer native dependency versions than Expo Go, so it must run as a development build.

The example release-smoke app verifies this exact matrix:

Expo React Native React Skia Reanimated Worklets Gesture Handler
57.0.8 0.86.2 19.2.8 2.10.0 4.5.3 0.11.3 3.1.0

Other versions within the package's peer ranges may work, but Reanimated and Worklets must be an upstream-supported pair. Treat the table above as the verified baseline rather than a promise that every peer-range combination has been device-tested.

Expo configuration

The Expo 57 example uses the standard babel-preset-expo and default Expo Metro config. The preset detects react-native-worklets and adds its transform, so no library-specific Babel or Metro setup is required.

Development and release

From the repository root:

bun install
bun run check
bun run pack:check
bun run pack:consumer
bun run example:ios
# or: bun run example:android
bun run example:export:web

After the development build is installed, bun run example starts Metro for that client.

Before publishing, inspect the dry-run tarball, update the version, and write the GitHub Release notes, then publish with npm provenance from GitHub Actions. The release workflow uses an npm trusted publisher; no long-lived npm token belongs in the repository.

The example's deployment guide covers the static web gallery and native preview options.

Repository layout

  • src/ — publishable library source
  • example/ — Expo 57 gallery and release smoke app
  • docs/images/ — curated iOS and Android captures
  • tests/ — platform-independent chart math checks
  • patches/ — exact temporary upstream compatibility patches (expo-modules-jsi@57.0.4 for Sequoia Xcode 26.3 compatibility)

Credit

Inspired by Dither Kit, created by Boring Software Inc. and released under the MIT License. This is an independent React Native reimplementation of Dither Kit using Skia and Reanimated.

About

High-performance dithered charts and pixel surfaces for React Native, powered by Skia and Reanimated.

Topics

Resources

Contributing

Security policy

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages