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 |
|---|---|
![]() |
![]() |
| Selected area + pinned bar · iPhone 17e | Pinned bar · iPhone 16e |
|---|---|
![]() |
![]() |
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.3Wrap the app once with GestureHandlerRootView:
import { GestureHandlerRootView } from "react-native-gesture-handler";
export default function App() {
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<Charts />
</GestureHandlerRootView>
);
}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.
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.
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.
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.
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:webAfter 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.
src/— publishable library sourceexample/— Expo 57 gallery and release smoke appdocs/images/— curated iOS and Android capturestests/— platform-independent chart math checkspatches/— exact temporary upstream compatibility patches (expo-modules-jsi@57.0.4for Sequoia Xcode 26.3 compatibility)
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.



