# 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 ``` ```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 ``` ```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