Export Configuration
Export through a dialog instead of a one-click download: pick which statuses, regions, and dates to include, choose columns and format, and see how many rows match before anything downloads.
$ npx shadcn add https://www.shad-table.dev/r/export-config-table.json30 orders
| Order | Customer | Region | Status | Date | Amount |
|---|---|---|---|---|---|
| ORD-1025 | Lucas Martin | APAC | Failed | 2026-09-22 | $910.00 |
| ORD-1028 | Sofia Patel | LATAM | Refunded | 2026-09-20 | $988.79 |
| ORD-1006 | Liam Chen | LATAM | Refunded | 2026-09-16 | $46.58 |
| ORD-1011 | Isabella Rossi | APAC | Refunded | 2026-09-15 | $929.28 |
| ORD-1012 | Mason Lee | EU | Failed | 2026-09-13 | $154.55 |
| ORD-1013 | Ava Thompson | EU | Pending | 2026-09-10 | $619.68 |
| ORD-1029 | Liam Chen | APAC | Pending | 2026-09-04 | $406.76 |
| ORD-1007 | Amelia Novak | EU | Failed | 2026-09-03 | $333.07 |
1–8 of 30
How it works
1.The export settings are one plain object
Statuses, regions, date range, columns, and format all live in a single ExportConfig held by the table component. The dialog only edits it, so the settings survive closing and reopening the dialog, and Reset is just setting it back to defaultExportConfig().
export type ExportConfig = {statuses: Order['status'][]regions: Order['region'][]datePreset: DatePresetcolumns: string[]format: ExportFormat}
2.The live count and the file come from the same function
applyExportConfig() is the only place that decides which rows are exported. The "N of 30 rows" line in the dialog and the downloaded file both call it, so the number the user sees is always the number they get.
const matches = useMemo(() => applyExportConfig(data, config, today),[data, config, today],)
3.Column choices come from the table, not a second list
The dialog's column checkboxes are built from table.getAllLeafColumns(), using each column's header as its label. Add a column to columns.tsx and it shows up in the export dialog automatically. Picked columns are kept in table order, whatever order they were ticked in.
const exportColumns = table.getAllLeafColumns().map((column) => ({id: column.id,label: typeof column.columnDef.header === 'string'? column.columnDef.header: column.id,}))
4.Exports use raw values, not what the cell displays
The table renders amounts as "$129.50" and statuses as badges, but the file gets the underlying values (129.5, "Paid") so spreadsheets can sort and sum them. Export is disabled when nothing matches or no column is selected, so an empty file is never downloaded.
const rows = matches.map((order) =>chosen.map((c) => String(order[c.id as keyof Order])),)