PivotGrid
Cross-tabulation pivot grid with multi-dimension rows and columns, aggregation, conditional cell coloring, expand and collapse, pinned value columns, a drilldown action sheet, a toolbar, and CSV, Excel and PDF export.
Installation
pnpm dlx @docyrus/cli add @docyrus/rn-pivot-gridpnpm add jsonata @shopify/flash-list expo-file-system (optional) expo-sharing (optional) expo-print (optional)The export modules are optional peers and are loaded lazily. CSV and Excel exports need expo-file-system (SDK 54+ File API) and expo-sharing. PDF export needs expo-print and expo-sharing. When a module is missing, the export does nothing.
For a server-backed pivot, see useDocyrusPivotGrid.
Usage
import { Badge } from '@/components/docyrus-native/badge';
import {
PivotGrid,
PivotGridView,
PivotGridToolbar,
PivotGridDrilldownModal,
usePivotGrid,
type PivotGridDimension,
type PivotGridMeasure,
} from '@/components/docyrus-native/pivot-grid';
interface SalesRow {
region: string;
product: string;
revenue: number;
}
const data: SalesRow[] = [
{ region: 'North', product: 'Widget A', revenue: 1200 },
{ region: 'North', product: 'Widget B', revenue: 850 },
{ region: 'South', product: 'Widget A', revenue: 960 },
{ region: 'South', product: 'Widget B', revenue: 1100 },
];
const rowDimensions: PivotGridDimension<SalesRow>[] = [
{ id: 'region', label: 'Region', getValue: (row) => row.region },
];
const columnDimensions: PivotGridDimension<SalesRow>[] = [
{ id: 'product', label: 'Product', getValue: (row) => row.product },
];
const measures: PivotGridMeasure<SalesRow>[] = [
{
id: 'revenue',
label: 'Revenue',
getValue: (row) => row.revenue,
aggregate: 'sum',
formatValue: (v) => `$${v.toLocaleString()}`,
},
];
function SalesPivot() {
const controller = usePivotGrid({
data,
rowDimensions,
columnDimensions,
measures,
height: 400,
initialState: { columnPinning: { right: [] } },
exportFileName: 'sales-report'
});
return (
<>
<PivotGridToolbar
controller={controller}
startContent={<Badge>{data.length} rows</Badge>} />
<PivotGridView controller={controller} />
<PivotGridDrilldownModal controller={controller} />
</>
);
}
// Or self-contained (creates its own controller):
<PivotGrid data={data} rowDimensions={rowDimensions} columnDimensions={columnDimensions} measures={measures} height={400} />Features
- Multi-dimension pivoting — 1-3 row/column dimensions with nested grouping
- Aggregation — sum, count, avg, min, max
- Expand/collapse — toggle individual rows/columns or expand/collapse all
- Conditional coloring — JSONata-based cell color rules with Tailwind color support
- Drilldown — tap a leaf cell to see contributing source rows in an action sheet
- Toolbar — expand / collapse buttons, the export menu, and
startContent/endContentslots - Export — CSV, a real
.xlsxworkbook (merged multi-level headers, frozen panes, styled subtotal and total rows, written by a zero-dependency OOXML writer) and PDF (expo-print). Each export opens the native share sheet. - Pinned value columns —
pinColumns(ids, 'left' | 'right')keeps columns sticky while you scroll horizontally. Row headers are always pinned. - Virtualized scrolling — FlashList windowing for large datasets
- Synchronized scroll — row headers and column headers stay in sync with the data grid
API Reference
PivotGrid / usePivotGrid props
PivotGrid takes the same props as usePivotGrid (PivotGridProps = UsePivotGridProps) and creates its own controller.
| Prop | Type | Default | Description |
|---|---|---|---|
data | TData[] | — | Source rows. Required. |
rowDimensions | PivotGridDimension<TData>[] | — | Row grouping dimensions (outermost → innermost). Required. |
columnDimensions | PivotGridDimension<TData>[] | — | Column grouping dimensions. Required. |
measures | PivotGridMeasure<TData>[] | — | Aggregation measures. Required. |
getRowId | (row: TData, index: number) => string | — | Stable row id. |
initialState | Partial<PivotGridState> | — | Initial expanded rows and columns, column pinning and column sizing. |
cellColorRules | PivotGridCellColorRule[] | — | JSONata-based conditional cell colors. |
drilldown | PivotGridDrilldown<TData> | — | Drilldown columns and title getter. |
height | number | 480 | Grid height in px. |
rowHeaderWidth | number | 140 | Width of the first row-header column. |
childRowHeaderWidth | number | 110 | Width of the other row-header columns. |
valueColumnWidth | number | 100 | Leaf value column width. |
subtotalColumnWidth | number | 108 | Subtotal column width. |
grandTotalColumnWidth | number | 120 | Grand-total column width. |
rowHeight | number | 40 | Data row height. |
headerRowHeight | number | 40 | Header row height. |
exportFileName | string | 'pivot-grid' | Base file name for CSV, Excel and PDF exports. |
className | string | — | Container classes. |
style | ViewStyle | — | Deprecated. Use className. |
PivotGridView
Renders a controller from usePivotGrid. Use it to share one controller with the toolbar and the drilldown modal.
| Prop | Type | Default | Description |
|---|---|---|---|
controller | PivotGridController<TData> | — | Controller instance. Required. |
className | string | controller.className | Container classes. |
style | ViewStyle | — | Deprecated. Use className. |
PivotGridToolbar
A horizontally scrolling toolbar with expand rows, collapse rows, expand columns, collapse columns and the export menu.
| Prop | Type | Default | Description |
|---|---|---|---|
controller | PivotGridController<TData> | — | Controller instance. Required. |
startContent | ReactNode | — | Rendered before the built-in buttons. |
endContent | ReactNode | — | Rendered after the export button. |
showExport | boolean | true | Show the export menu button. |
className | string | — | Classes for the scroll container. |
PivotGridExportMenu
An export button that opens an action sheet with Export CSV, Export Excel and Export PDF. It replaces the web dropdown.
| Prop | Type | Default | Description |
|---|---|---|---|
controller | PivotGridController<TData> | — | Controller instance. Required. |
className | string | — | Button classes. |
PivotGridDrilldownModal
An action sheet that lists the source rows behind a tapped leaf cell.
| Prop | Type | Default | Description |
|---|---|---|---|
controller | PivotGridController<TData> | — | Controller instance. Required. |
columns | NativeDrilldownColumn<TData>[] | controller.drilldownColumns | Columns shown for each row. |
PivotGridController
Returned by usePivotGrid.
| Field | Type | Description |
|---|---|---|
className | string | undefined | Container classes forwarded from props. |
rowHeaderColumnIds | string[] | Synthetic row-header ids (__pivot_row_header_<index>). |
valueColumnIds | string[] | Visible value-column ids in render order: left-pinned, center, right-pinned. |
visibleLeafColumns | PivotGridLeafColumn<TData>[] | Visible value columns in render order. |
headerRows | PivotGridHeaderRow[] | Column header rows (cells carry pinPosition). |
headerDepth | number | Number of header rows. |
visibleRows | PivotGridRenderedRow<TData>[] | Rendered rows (group, leaf, subtotal, grand-total). |
rowDimensions | PivotGridDimension<TData>[] | Row dimensions. |
cellColorMap | Map<string, string> | Cell id → background color from the color rules. |
drilldownColumns | NativeDrilldownColumn<TData>[] | undefined | drilldown.columns, or columns derived from the first row's keys. |
drilldownState | PivotGridDrilldownState<TData> | { open, cell }. |
columnWidths | PivotGridColumnWidths | { rowHeaders: number[]; valueColumns: Map<string, number> }. |
columnPinning | PivotGridColumnPinningState | Current value-column pinning. |
getColumnPinPosition | (columnId: string) => PivotGridPinPosition | 'left', 'right' or false. |
rowHeight / headerRowHeight / height | number | Resolved sizes. |
toggleRow / toggleColumn | (nodeId: string) => void | Expand or collapse one group. |
expandAllRows / collapseAllRows / expandAllColumns / collapseAllColumns | () => void | Bulk expand or collapse. |
pinColumns | (columnIds: string[], position: 'left' | 'right') => void | Pin value columns (sticky while scrolling horizontally). |
unpinColumns | (columnIds: string[]) => void | Unpin value columns. |
openDrilldown / closeDrilldown | (cell) => void / () => void | Drilldown sheet control. |
getDrilldownRows | (cell: PivotGridRenderedCell<TData>) => TData[] | Source rows of a cell. |
getDrilldownTitle | (cell: PivotGridRenderedCell<TData>) => string | Title (custom drilldown.getTitle, or row path x column path). |
exportCsv | () => Promise<void> | Shares a CSV file. |
exportExcel | () => Promise<void> | Shares an .xlsx workbook. |
exportPdf | () => Promise<void> | Shares a PDF rendered by expo-print. |
PivotGridState
| Field | Type | Description |
|---|---|---|
expandedRowIds | Record<string, boolean> | Expanded row group ids (default: all expanded). |
expandedColumnIds | Record<string, boolean> | Expanded column group ids. |
columnPinning | PivotGridColumnPinningState | { left?: string[]; right?: string[] }. Value-column ids only; row headers are always pinned. |
columnSizing | PivotGridColumnSizingState | Record<columnId, px> width overrides. Row headers use __pivot_row_header_<index>. |
PivotGridDimension
| Field | Type | Description |
|---|---|---|
id | string | Unique dimension id. |
label | string | Display label. |
getValue | (row: TData) => unknown | Extracts the dimension value. |
formatValue | (value: unknown) => string | Optional value formatter. |
sort | (a: unknown, b: unknown) => number | Optional sort comparator. |
emptyLabel | string | Label for empty or null values. |
PivotGridMeasure
| Field | Type | Description |
|---|---|---|
id | string | Unique measure id. |
label | string | Display label. |
getValue | (row: TData) => number | null | undefined | Value accessor (omit to count rows). |
aggregate | PivotGridAggregate | 'sum' | 'count' | 'avg' | 'min' | 'max'. |
formatValue | (value: number) => string | Output formatter. |
PivotGridCellColorRule
| Field | Type | Description |
|---|---|---|
formula | string | JSONata expression (receives value, measureId, rowPath, columnPath, …). |
color | string | Tailwind color name (for example 'green-100') or a hex value. |
scope | PivotGridColorScope | Optional: 'leaf' | 'subtotal' | 'total' | 'grand-total'. |
PivotGridDrilldown / NativeDrilldownColumn
| Field | Type | Description |
|---|---|---|
columns | NativeDrilldownColumn<TData>[] | { id: string; header: string; getValue: (row: TData) => string }[]. |
getTitle | (cell: PivotGridRenderedCell<TData>) => string | Custom drilldown title. |
Translations
| Key | English fallback |
|---|---|
ui.pivotGrid.expandRows / collapseRows / expandColumns / collapseColumns | Expand rows / Collapse rows / Expand columns / Collapse columns |
ui.pivotGrid.export / exportCsv / exportExcel / exportPdf | Export / Export CSV / Export Excel / Export PDF |
ui.pivotGrid.noData | No data to pivot |
ui.pivotGrid.grandTotal | Grand Total (drilldown title) |
ui.pivotGrid.contributingRows / rowNumber / noRows | {count} contributing row(s) / Row {index} / No rows to display |
Hooks
usePivotGrid
const controller = usePivotGrid<TData>(props: UsePivotGridProps<TData>);Returns a PivotGridController with the full view model and every action callback. Use it when PivotGridView, PivotGridToolbar and PivotGridDrilldownModal need to share one controller.
Components
| Component | Description |
|---|---|
PivotGrid | Self-contained grid. |
PivotGridView | Grid for an external controller. |
PivotGridToolbar | Expand / collapse / export toolbar. |
PivotGridExportMenu | Export action sheet. |
PivotGridDrilldownModal | Drilldown action sheet. |
Type Exports
| Type | Description |
|---|---|
PivotGridProps | Props for PivotGrid (alias of UsePivotGridProps). |
UsePivotGridProps | Props accepted by usePivotGrid. |
PivotGridController | Controller returned by usePivotGrid. |
PivotGridToolbarProps | Props for PivotGridToolbar. |
PivotGridExportMenuProps | Props for PivotGridExportMenu. |
PivotGridDimension | Dimension definition (row or column). |
PivotGridMeasure | Measure definition. |
PivotGridAggregate | 'sum' | 'count' | 'avg' | 'min' | 'max'. |
PivotGridCellColorRule | Conditional cell color rule. |
PivotGridColorScope | 'leaf' | 'subtotal' | 'total' | 'grand-total'. |
PivotGridState | Expanded, pinning and sizing state. |
PivotGridColumnPinningState | { left?: string[]; right?: string[] }. |
PivotGridColumnSizingState | Record<string, number>. |
PivotGridPinPosition | 'left' | 'right' | false. |
PivotGridDrilldown | Drilldown configuration. |
PivotGridDrilldownState | Drilldown open and cell state. |
PivotGridHeaderRow / PivotGridHeaderCell | Header structures. |
PivotGridLeafColumn | Leaf column structure. |
PivotGridRenderedRow / PivotGridRenderedCell | Rendered row and cell. |
PivotGridColumnWidths | Row-header and value-column widths. |
NativeDrilldownColumn | Drilldown column definition. |
PivotGridDemoRow | Demo row shape (with createPivotGridDemoRows and the pivotGridDemo* presets). |
PivotFilter
Horizontal or vertical strip of count-tagged pills used as a one-dimension quick filter above a grid, calendar or map, with refresh and a settings bottom sheet. API-aligned with the web PivotFilter.
PlaceAutocomplete
A location search input with autocomplete suggestions powered by the Photon geocoding API, with location bias, bounding boxes and web-parity address formatting.