# TinyPivot — Developer Reference
> Reference generated from TinyPivot v1.0.82 (June 2026).
TinyPivot is a lightweight, batteries-included analytics grid for Vue 3 and React. It ships as two separate framework packages that share a common core.
**When to use TinyPivot:**
- You need an Excel-like data grid with built-in pivot table support, not just a raw table
- You want pivot tables, aggregations, CSV export, and clipboard without assembling a headless library
- You need charts or an AI-powered natural-language data analyst in the same component
- You want a lifetime commercial license without per-seat or annual fees
- Bundle size matters (~40 KB gzipped (React) / ~50 KB gzipped (Vue) vs 500 KB+ for AG Grid)
**When NOT to use TinyPivot:**
- You need full spreadsheet editing (cell-level write-back, formulas in cells)
- You need virtual scrolling for millions of rows
- You need tree/master-detail row grouping (not yet supported)
---
## Installation
### Vue 3
```bash
pnpm add @smallwebco/tinypivot-vue
# or
npm install @smallwebco/tinypivot-vue
```
### React
```bash
pnpm add @smallwebco/tinypivot-react
# or
npm install @smallwebco/tinypivot-react
```
---
## Quick Start
### Vue 3
```vue
```
### React
```tsx
import { DataGrid } from '@smallwebco/tinypivot-react'
import '@smallwebco/tinypivot-react/style.css'
const data = [
{ id: 1, region: 'North', product: 'Widget A', sales: 12500, units: 150 },
{ id: 2, region: 'North', product: 'Widget B', sales: 8300, units: 95 },
{ id: 3, region: 'South', product: 'Widget A', sales: 15200, units: 180 },
{ id: 4, region: 'South', product: 'Widget B', sales: 9800, units: 110 },
]
export default function App() {
return (
)
}
```
### Activate Pro License (both frameworks)
Call once at app startup, before rendering:
```typescript
// Vue
import { setLicenseKey } from '@smallwebco/tinypivot-vue'
setLicenseKey('YOUR_LICENSE_KEY')
// React
import { setLicenseKey } from '@smallwebco/tinypivot-react'
setLicenseKey('YOUR_LICENSE_KEY')
```
---
## DataGrid Props
All props are identical between Vue and React except for naming convention (Vue: kebab-case in template; React: camelCase).
| Prop (Vue / React) | Type | Default | Description |
|---|---|---|---|
| `data` | `Record[]` | **required** | Array of flat row objects |
| `loading` | `boolean` | `false` | Show loading spinner |
| `fontSize` | `'xs' \| 'sm' \| 'base'` | `'xs'` | Font size preset |
| `show-pivot` / `showPivot` | `boolean` | `true` | Show pivot toggle button |
| `enable-export` / `enableExport` | `boolean` | `true` | Show the Export dropdown menu (CSV free / Excel .xlsx Pro) |
| `enable-search` / `enableSearch` | `boolean` | `true` | Show global search input |
| `enable-pagination` / `enablePagination` | `boolean` | `false` | Enable pagination |
| `page-size` / `pageSize` | `number` | `50` | Rows per page |
| `enable-column-resize` / `enableColumnResize` | `boolean` | `true` | Drag-to-resize columns |
| `enable-clipboard` / `enableClipboard` | `boolean` | `true` | Ctrl+C to copy selected cells |
| `theme` | `string` | `'light'` | Color theme — 22 built-in presets (see Theming) |
| `number-format` / `numberFormat` | `'us' \| 'eu' \| 'plain'` | `'us'` | Number display: US (1,234.56), EU (1.234,56), plain |
| `date-format` / `dateFormat` | `'us' \| 'eu' \| 'iso'` | `'iso'` | Date display: US (MM/DD/YYYY), EU (DD/MM/YYYY), ISO |
| `field-role-overrides` / `fieldRoleOverrides` | `FieldRoleOverrides` | `undefined` | Override chart field role per column (`'dimension'` \| `'measure'` \| `'temporal'`) |
| `striped-rows` / `stripedRows` | `boolean` | `true` | Alternating row background color |
| `export-filename` / `exportFilename` | `string` | `'data-export.csv'` | Filename for CSV download |
| `ai-analyst` / `aiAnalyst` | `AIAnalystConfig` | `undefined` | Pro: AI Data Analyst configuration object |
| `enable-drill-down` / `enableDrillDown` | `boolean` | `true` | Enable pivot row group expand/collapse chevrons (Free) |
| `enable-drill-through` / `enableDrillThrough` | `boolean` | `true` | Enable double-click drill-through on pivot value cells (Pro feature) |
| `pivot-layout` / `pivotLayout` | `'grouped' \| 'tabular'` | `'grouped'` | Row layout for multi-field pivots: `'grouped'` merges repeated parent values into a spanning cell; `'tabular'` repeats every value on each row. |
| `row-height` / `rowHeight` | `number` | — | Row height in pixels |
| `header-height` / `headerHeight` | `number` | — | Header row height in pixels |
| `enable-row-selection` / `enableRowSelection` | `boolean` | `false` | Enable row selection (adds a checkbox column) |
| `enable-vertical-resize` / `enableVerticalResize` | `boolean` | — | Allow dragging the bottom edge to resize the grid height |
| `initial-height` / `initialHeight` | `number` | — | Initial height of the grid in pixels |
| `min-height` / `minHeight` | `number` | — | Minimum grid height in pixels |
| `max-height` / `maxHeight` | `number` | — | Maximum grid height in pixels |
### Data Shape
TinyPivot accepts an array of flat objects. Each object is a row; keys become column headers.
```typescript
// Correct — flat objects with consistent keys
const data = [
{ id: 1, name: 'Alice', sales: 1500, region: 'North' },
{ id: 2, name: 'Bob', sales: 2300, region: 'South' },
]
// Avoid — nested objects won't display correctly
const bad = [{ id: 1, user: { name: 'Alice' } }]
```
Supported value types: `string`, `number`, `boolean`, `null`/`undefined` (empty cell), `Date`.
### Vue Events
| Event | Payload | Description |
|---|---|---|
| `@cell-click` | `{ row, col, value, rowData }` | Cell clicked |
| `@selection-change` | `{ cells, values }` | Selection changed |
| `@export` | `{ rowCount, filename }` | CSV exported |
| `@copy` | `{ text, cellCount }` | Cells copied to clipboard |
| `@collapse-change` | `string[]` | Pivot row groups collapsed/expanded (array of collapsed path keys) |
| `@drill-through` | `DrillThroughResult` | Pivot cell double-clicked; drill-through modal opened (Pro) |
### React Callbacks
| Prop | Description |
|---|---|
| `onCellClick` | Cell clicked |
| `onSelectionChange` | Selection changed |
| `onExport` | CSV exported |
| `onCopy` | Cells copied to clipboard |
| `onCollapseChange` | Pivot row groups collapsed/expanded — receives `string[]` of collapsed path keys |
| `onDrillThrough` | Pivot cell double-clicked; drill-through modal opened — receives `DrillThroughResult` (Pro) |
---
## Free vs Pro Feature Matrix
| Feature | Free | Pro |
|---|:---:|:---:|
| Excel-like data grid | yes | yes |
| Column filtering and sorting | yes | yes |
| Global search | yes | yes |
| CSV export | yes | yes |
| Pagination | yes | yes |
| Column resizing | yes | yes |
| Clipboard (Ctrl+C) | yes | yes |
| Dark mode | yes | yes |
| Keyboard navigation | yes | yes |
| Pivot table with Sum aggregation | yes | yes |
| Row/column totals | yes | yes |
| Calculated fields with formulas | yes | yes |
| Pivot row group expand/collapse | yes | yes |
| Pivot drill-through (double-click to inspect source rows) | no | yes |
| Excel (XLSX) Export (styled, multi-level pivot headers, lazy-loaded) | no | yes |
| AI Data Analyst (natural language, BYOK) | no | yes |
| Chart Builder (6 chart types, drag-and-drop) | no | yes |
| All aggregations (Count, Avg, Min, Max, Unique, Median, Std Dev, %) | no | yes |
| No watermark | no | yes |
---
## Pricing
Lifetime license — one-time purchase, no subscription, no per-seat fees.
| Plan | Price | Use Case |
|---|---|---|
| Single Project | $49 | One application |
| Unlimited Projects | $149 | All your personal/company projects |
| Team License | $399 | Up to 10 developers |
Purchase at: https://tiny-pivot.com/#pricing
---
## Aggregation Functions
TinyPivot includes 9 built-in aggregation functions. Sum is available in the free tier; all others require Pro.
| Function | Description |
|---|---|
| Sum | Total of all values |
| Count | Number of values |
| Average | Mean of all values |
| Min | Minimum value |
| Max | Maximum value |
| Unique | Count of distinct values |
| Median | Middle value (outlier-resistant) |
| Std Dev | Standard deviation |
| % of Total | Percentage contribution to grand total |
Custom aggregation functions are also supported via the `customFn` property on a value field:
```typescript
// Vue (ref) / React (plain object)
const valueFields = [
{
field: 'sales',
aggregation: 'custom',
customFn: (values: number[]) => {
const sorted = [...values].sort((a, b) => a - b)
return sorted[Math.floor(sorted.length * 0.9)] // 90th percentile
},
customLabel: '90th Percentile',
customSymbol: 'P90',
},
]
```
---
## Theming
Set the `theme` prop on `DataGrid`. TinyPivot ships 22 built-in themes.
```vue
```
```tsx
{/* React */}
```
`theme="auto"` follows the user's system preference (`prefers-color-scheme`).
### Built-in Themes
| Theme names | Accent | Vibe |
|---|---|---|
| `light` / `dark` / `auto` | indigo / violet | Default — neutral cool grays |
| `slate` / `slate-dark` | indigo #4f46e5 | Linear / Stripe — cool neutral |
| `zinc` / `zinc-dark` | near-mono | Vercel / Anthropic — minimalist |
| `indigo` / `indigo-dark` | indigo #6366f1 | Premium SaaS |
| `violet` / `violet-dark` | purple #8b5cf6 | Data viz / AI tools |
| `emerald` / `emerald-dark` | green #10b981 | Fintech / finance |
| `sky` / `sky-dark` | light blue #0ea5e9 | Productivity / airy |
| `rose` / `rose-dark` | warm pink #f43f5e | Friendly / creator |
| `amber` / `amber-dark` | warm orange #f59e0b | Energy / wellness |
| `solar` / `solar-dark` | mustard #b58900 | Solarized — warm cream + dark teal |
| `mono` / `mono-dark` | black / white | Editorial — pure grayscale |
### Custom Themes
Override CSS custom properties on the grid root class:
```css
.vpg-data-grid.my-brand {
--vpg-accent: #ff6b35;
--vpg-accent-hover: #e55426;
--vpg-surface-bg: #fafaf7;
--vpg-surface-panel: #f0eee7;
}
```
```vue
```
```tsx
{/* React */}
```
Key CSS tokens: `--vpg-accent`, `--vpg-accent-hover`, `--vpg-surface-bg`, `--vpg-surface-panel`, `--vpg-surface-elevated`, `--vpg-surface-hover`, `--vpg-surface-selected`, `--vpg-text-primary`, `--vpg-text-secondary`, `--vpg-text-muted`, `--vpg-border-default`, `--vpg-border-strong`, `--vpg-focus-ring`.
---
## Export
When `enableExport` is `true` (the default), the toolbar shows a single **Export** dropdown button. Clicking it opens a two-item menu:
- **CSV** — always available (free). Downloads a `.csv` file of the current view (grid or pivot).
- **Excel (.xlsx)** — Pro only. Free users see this item disabled with a **Pro** badge. Pro users get a styled `.xlsx` download. `exceljs` (~250 KB) loads lazily via dynamic import and is never part of the main bundle.
### CSV Export (Free)
Programmatic API:
```typescript
// Vue
import { exportToCSV, exportPivotToCSV } from '@smallwebco/tinypivot-vue'
// React
import { exportToCSV, exportPivotToCSV } from '@smallwebco/tinypivot-react'
// exportToCSV(data: T[], columns: string[], options?: ExportOptions): void
exportToCSV(data, Object.keys(data[0] ?? {}), { filename: 'my-data.csv' })
```
### Excel (XLSX) Export (Pro)
Styled `.xlsx` downloads for the flat grid and pivot table. Both functions are `async` and trigger a browser download:
```typescript
// Vue
import { exportToXLSX, exportPivotToXLSX } from '@smallwebco/tinypivot-vue'
import type { XlsxExportOptions } from '@smallwebco/tinypivot-vue'
// React
import { exportToXLSX, exportPivotToXLSX } from '@smallwebco/tinypivot-react'
// Flat grid
// exportToXLSX(data: T[], columns: string[], options?: XlsxExportOptions): Promise
await exportToXLSX(data, columns, {
filename: 'report.xlsx',
sheetName: 'Sales',
numberFormats: { revenue: '#,##0.00', units: '#,##0' },
})
// Pivot table
// exportPivotToXLSX(pivotData, rowFields, columnFields, valueFields, options?): Promise
await exportPivotToXLSX(pivotData, rowFields, columnFields, valueFields, {
filename: 'pivot-report.xlsx',
sheetName: 'Pivot',
})
```
`XlsxExportOptions` extends `ExportOptions` and adds:
- `sheetName?: string` — worksheet name (default: `'Sheet1'`)
- `numberFormats?: Record` — custom Excel number format strings per column key
#### Pivot XLSX: two-sheet workbook
Pivot XLSX export produces a **two-sheet workbook**:
1. **Pivot** — the styled pivot summary (merged column headers, bold totals row, frozen header, auto-sized columns).
2. **Source Data** — the underlying source rows written as an **interactive Excel Table** (`TableStyleMedium2` with filter/sort dropdowns on every column). In Excel, select any cell in this table and choose **Insert → PivotTable** to build a native Excel PivotTable in two clicks.
Note: TinyPivot does not generate a native Excel PivotTable object — exceljs does not support writing pivot table XML. The Source Data sheet is the practical alternative.
---
## Pivot Drill-Down
### Row Group Expand/Collapse (Free)
When a pivot table has two or more row fields, group rows display a `▸`/`▾` chevron. Click to collapse or expand the group. Alt-click collapses/expands every group at that depth. Collapsed groups show correct aggregated values (sum, avg, median, stdDev, etc.) recomputed over all underlying source rows.
Controlled by `enableDrillDown` (default `true`). Fires `@collapse-change` / `onCollapseChange` with the current array of collapsed path keys.
```vue
console.log(collapsedPaths)"
/>
```
```tsx
// React
console.log(collapsedPaths)}
/>
```
### Drill-Through to Source Rows (Pro)
Double-click any pivot value cell (including row/column totals and grand total) to open a modal listing the underlying source rows that contributed to that cell. The modal shows a slice description header, a paginated plain table (50 rows/page), and a CSV export button.
Controlled by `enableDrillThrough` (default `true`). Requires a Pro license — without one a console warning is shown and the modal does not open. Fires `@drill-through` / `onDrillThrough` with a `DrillThroughResult` payload.
```vue
console.log(descriptor.rowCount, 'rows')"
/>
```
```tsx
// React
console.log(descriptor.rowCount, 'rows')}
/>
```
Key types (exported from both packages):
```typescript
interface DrillThroughResult {
rows: Record[] // Source rows matching the cell slice
descriptor: DrillThroughDescriptor
}
interface DrillThroughDescriptor {
rowPath: string[] // e.g. ['West', 'Widgets']
columnPath: string[] // e.g. ['Q3']
valueField: string // e.g. 'sales'
aggregation: AggregationFunction
formattedValue: string // Pre-formatted result, e.g. '1,234'
rowCount: number
}
```
---
## Clipboard
Clipboard copy is free and enabled by default (`enableClipboard: true`). Users can select a cell range and press Ctrl+C (or Cmd+C on Mac) to copy tab-separated values. The `@copy` / `onCopy` event fires with `{ text, cellCount }`.
**Clipboard:**
- `Ctrl+C` / `Cmd+C` — Copy selected cells
**Keyboard Navigation:**
- Arrow keys — Navigate cells
- `Shift+Arrow` — Extend selection
- `Ctrl+F` / `Cmd+F` — Focus search
- `Escape` — Clear selection / search
---
## AI Data Analyst (Pro)
The AI Data Analyst lets users ask natural-language questions about their data. It generates SQL, executes it, and displays results in the grid — ready for further pivot or chart analysis. Requires a Pro license.
**BYOK**: Supply your own OpenAI, Anthropic, or OpenRouter API key. Data never passes through TinyPivot servers.
The AI provider is auto-detected from the API key format:
- `sk-ant-...` — Anthropic (default model: `claude-3-haiku-20240307`)
- `sk-or-...` — OpenRouter (default model: `anthropic/claude-3-haiku`)
- `sk-...` — OpenAI (default model: `gpt-4o-mini`)
Set `AI_MODEL` environment variable to override the default model. Default model names are point-in-time and may become outdated; check your provider's current model list for available options.
### Option A: PostgreSQL backend (recommended)
```typescript
// Backend: app/api/tinypivot/route.ts (Next.js App Router example)
import { createTinyPivotHandler } from '@smallwebco/tinypivot-server'
export const POST = createTinyPivotHandler({
tables: {
include: ['sales', 'customers', 'products'],
descriptions: {
sales: 'Sales transactions with revenue data',
},
},
})
```
```vue
```
```tsx
// Frontend: React
import { DataGrid, setLicenseKey } from '@smallwebco/tinypivot-react'
import '@smallwebco/tinypivot-react/style.css'
setLicenseKey('YOUR_LICENSE_KEY')
export default function App() {
return (
)
}
```
### Option B: Client-side data (in-memory)
```vue
```
```tsx
// React
import { useState } from 'react'
import { DataGrid, setLicenseKey } from '@smallwebco/tinypivot-react'
import '@smallwebco/tinypivot-react/style.css'
setLicenseKey('YOUR_LICENSE_KEY')
function inferSchema(data: Record[]) {
if (!data.length) return []
return Object.entries(data[0]).map(([name, value]) => ({
name,
type: typeof value === 'number' ? 'number' : typeof value === 'boolean' ? 'boolean' : 'string',
}))
}
export default function App() {
const [salesData] = useState([
{ id: 1, region: 'North', product: 'Widget A', sales: 12500, units: 150 },
])
const aiConfig = {
enabled: true,
endpoint: '/api/ai-chat',
dataSources: [
{ id: 'sales', table: 'sales', name: 'Sales Data', description: 'Sales transactions' },
],
dataSourceLoader: async (id: string) => {
if (id === 'sales')
return { data: salesData, schema: inferSchema(salesData) }
throw new Error(`Unknown data source: ${id}`)
},
}
return
}
```
### AIAnalystConfig options
| Option | Type | Description |
|---|---|---|
| `enabled` | `boolean` | Enable the AI Analyst tab |
| `endpoint` | `string` | Unified backend endpoint (handles discovery, schema, query, and AI chat) |
| `dataSources` | `AIDataSource[]` | Available data sources (demo/client-side mode only) |
| `dataSourceLoader` | `function` | Custom data source loader (for client-side DuckDB demos) |
| `queryExecutor` | `function` | Custom query executor (for client-side DuckDB demos) |
| `demoMode` | `boolean` | Use canned responses — no real AI calls |
| `maxRows` | `number` | Max rows returned per query (default 10000) |
| `sessionId` | `string` | Session ID for conversation continuity |
| `persistToLocalStorage` | `boolean` | Persist conversations to localStorage (default false) |
| `aiModelName` | `string` | Display name for the AI model in the UI (cosmetic only) |
### Server-side security
The `@smallwebco/tinypivot-server` handler enforces: SELECT-only SQL, table whitelisting, and error sanitization (connection strings stripped).
---
## TypeScript
Full TypeScript support. Key types exported from both packages:
```typescript
import type {
AggregationFunction,
AIAnalystConfig,
DataGridProps,
PivotConfigType,
PivotField,
PivotValueField,
} from '@smallwebco/tinypivot-react'
// Most types also available from '@smallwebco/tinypivot-vue'
import type {
AggregationFunction,
AIAnalystConfig,
DataGridProps,
PivotConfigType,
PivotField,
PivotValueField,
} from '@smallwebco/tinypivot-vue'
```
---
## Browser Support
Chrome 80+, Firefox 75+, Safari 14+, Edge 80+
---
## License
- Free tier: MIT — core grid, pivot (Sum only), pivot row group expand/collapse, export, clipboard
- Pro features: Commercial license required (pivot drill-through, charts, advanced aggregations, AI Data Analyst, no watermark)
Purchase: https://tiny-pivot.com/#pricing
GitHub: https://github.com/Small-Web-Co/tinypivot
npm (Vue): https://www.npmjs.com/package/@smallwebco/tinypivot-vue
npm (React): https://www.npmjs.com/package/@smallwebco/tinypivot-react