react-native-canvas-grid
v0.1.0
Published
Canvas-rendered data grid for React Native — virtualized rows and columns, live updates, sort, filter, search, pinned columns, themes, and a server-side data adapter.
Maintainers
Readme
react-native-canvas-grid
A canvas-rendered data grid for React Native. Built on React Native Skia for hardware-accelerated cell drawing, Reanimated for scroll physics, and Gesture Handler for pan, tap, and long-press interactions.
Highlights
- Canvas rendering — every cell is drawn with Skia; no per-row native view hierarchy.
- Two-axis virtualization — only rows and columns in the viewport + overscan are drawn each frame.
- Scroll momentum — fling-and-decay on both axes; runs entirely on the UI thread.
- Sort, filter, and search — client-side and server-side modes; advanced query string grammar.
- Live data —
useGridRowStorewithpatchCell/enqueuePatchand optional batch coalescing. - Pinned columns — fixed left columns that stay visible during horizontal scroll.
- Column resize — drag the right border of any column header.
- Column reorder — long-press a column header and drag to a new position.
- Themes — built-in
defaultGridThemeanddarkGridTheme; fully customizable viamergeGridTheme. - Custom cells — Skia
drawCellpainter per column, or a React NativerenderCelloverlay. - Server pagination —
GridDataSourceadapter with abort-signal support. - Accessibility —
accessibilityLabelon the grid container; screen-reader announcements for selection and edits. - TypeScript-first — fully typed generics for row shape, column definitions, and models.
Requirements
New Architecture (Fabric + JSI) is required. Old Architecture is not supported.
| Peer dependency | Tested version |
|---|---|
| react | 19.3.0 |
| react-native | 0.88.0 |
| react-native-skia | 3.7.4 |
| react-native-reanimated | 4.7.1 |
| react-native-worklets | 0.13.0 |
| react-native-gesture-handler | 3.3.0 |
Expo Go is not supported — use a custom development build. React Native Web and SSR are not tested and not advertised.
Installation
npm install react-native-canvas-gridInstall all peer dependencies. In an Expo project use npx expo install to resolve compatible native versions, then rebuild your development client:
npx expo install react-native-skia react-native-reanimated react-native-worklets react-native-gesture-handlerWrap your root component with GestureHandlerRootView:
import { GestureHandlerRootView } from 'react-native-gesture-handler';
export default function App() {
return (
<GestureHandlerRootView style={{ flex: 1 }}>
{/* your app */}
</GestureHandlerRootView>
);
}Quick start
import { DataGrid, type GridColDef } from 'react-native-canvas-grid';
import { View } from 'react-native';
type Trade = {
id: string;
symbol: string;
price: number;
quantity: number;
};
const columns: GridColDef<Trade>[] = [
{ field: 'id', headerName: 'ID', width: 80 },
{ field: 'symbol', headerName: 'Symbol', width: 120 },
{ field: 'price', headerName: 'Price', width: 120, type: 'number' },
{ field: 'quantity', headerName: 'Quantity', width: 120, type: 'number' },
];
const rows: Trade[] = [
{ id: 't-1', symbol: 'AAPL', price: 230.18, quantity: 100 },
{ id: 't-2', symbol: 'MSFT', price: 510.20, quantity: 25 },
];
export function TradesScreen() {
return (
<View style={{ flex: 1 }}>
<DataGrid
rows={rows}
columns={columns}
getRowId={(row) => row.id}
style={{ flex: 1 }}
/>
</View>
);
}Mount <DataGrid /> inside a container that provides a finite width and height (e.g. style={{ flex: 1 }}).
Live data
import { DataGrid, useGridRowStore } from 'react-native-canvas-grid';
const { rows, dataRevision, patchCell } = useGridRowStore(initialRows, {
getRowId: (row) => row.id,
columns,
batchUpdates: true,
});
// Later — patch a single cell without recreating the row array:
patchCell(rowId, 'price', 231.04);
<DataGrid rows={rows} dataRevision={dataRevision} columns={columns} ... />Sorting and filtering
const [sortModel, setSortModel] = useState<GridSortModel>([]);
const [filterModel, setFilterModel] = useState<GridFilterModel>({ items: [] });
<DataGrid
rows={rows}
columns={columns}
sortModel={sortModel}
onSortModelChange={setSortModel}
filterModel={filterModel}
searchQuery="price > 100"
searchDebounceMs={200}
/>Server-side data
const dataSource: GridDataSource<Row> = {
getRows: async ({ paginationModel, sortModel, filterModel, searchQuery, signal }) => {
const data = await fetchFromApi({ ...paginationModel, sort: sortModel, signal });
return { rows: data.items, totalRowCount: data.total };
},
};
<DataGrid
processingMode="server"
dataSource={dataSource}
paginationModel={paginationModel}
onPaginationModelChange={setPaginationModel}
columns={columns}
/>Theming
import { mergeGridTheme, defaultGridTheme, darkGridTheme } from 'react-native-canvas-grid';
const myTheme = mergeGridTheme(defaultGridTheme, {
colors: { headerBackground: '#1e293b', text: '#f8fafc' },
});
<DataGrid theme={myTheme} ... />Documentation
Full docs are in the repository under npm-docs/:
- Getting started
- API reference
- Columns and renderers
- Sorting, filtering and search
- Server data and pagination
- Theming and customization
- Performance and virtualization
- Compatibility
- Troubleshooting
Known limitations
- Old Architecture is not supported (Fabric + JSI required).
- Expo Go is not supported — requires a custom development build.
- React Native Web is not tested and not supported.
- SSR (Node server rendering) is not supported. "Server-side data mode" (
processingMode="server") is a client-side adapter that fetches data from a backend — it is not Node-side HTML rendering. - Row heights are fixed (
rowHeightprop). Variable row heights are not supported. - Accessibility is partial — canvas content is not natively traversable by screen readers. A summary label and selection/edit announcements are provided via a hidden
Viewoverlay.
Contributing
See CONTRIBUTING.md. Bug reports must include versions, platform, New Architecture mode, a minimal reproduction, and expected vs actual behavior. Do not include secrets or customer data.
License
MIT
