Export a collection: scope (selected / current view / all), columns (searchable, reorderable, personal data maskable), format (CSV, XLSX, JSON) with locale CSV conventions, a reason for personal-data exports, and background jobs with a focusable download link. exportToBlob writes the file; XLSX loads write-excel-file only when chosen.
Installation
The whole kit as one package — get updates by bumping the version. Add the styles to globals.css: @import "@vamos-ui/react/styles.css";
Usage
import { ExportDialog, exportToBlob } from "@vamos-ui/react/business";
<ExportDialog
resource="contacts"
columns={columns}
listState={listState}
selectedCount={selection.length}
filteredCount={total}
totalCount={allContacts}
trigger={<Button><Download /> Export</Button>}
onExport={async (r) => r.scope === "all" ? api.exports.start(r) /* → { jobId } */ : { blob: await exportToBlob({ rows, columns: pick(r.columns), format: r.format, masked: r.masked }) }}
pollJob={api.exports.status}
/>Scope and format are radio groups, columns a checkbox list with select-all and drag or keyboard reordering. File names carry the local date: contacts-2026-11-10.csv. Writing the audit entry is the app's job — onExport receives the reason.
Examples
Excel with typed cells
XLSX first: numbers and dates stay typed, the header row is bold. JSON for developers.
Large export as a job
Above syncLimit the dialog says it runs in the background; onExport returns { jobId } and pollJob drives the progress bar until a download link appears (and takes focus).
Personal data (KVKK / GDPR)
Sensitive columns are flagged and masked by default. Unmasking shows a notice and requires a reason, passed to onExport for your audit log. Shown as a Sheet.
Locale CSV conventions
tr-TR writes ; with decimal commas and a BOM so Turkish Excel splits columns; en-US writes , and points. QuickExportButton exports the current view in one click.
API
ExportDialog
| Prop | Type | Default |
|---|---|---|
columns{ id, label, personalData?, maskByDefault?, defaultSelected?, accessor?, type? }. | ExportColumn[] | — |
onExportr = { scope, columns (ordered), masked, format, reason?, csv, filename }. A blob downloads at once; a jobId starts polling. | (r: ExportRequest) => Promise<{ blob; filename? } | { jobId }> | — |
pollJobPolled every 1.5 s until done or failed (retry). | (jobId) => Promise<{ status; progress?; url?; error? }> | — |
listStateDescribes the current view ("2 filters · search “northpoint”"). | ListState | — |
selectedCount / filteredCount / totalCountRow counts per scope; selected is disabled at 0. | number | — |
resourcePlural noun for the title and file name. | string | "records" |
formatsOffered formats, first is the default. | ("csv" | "xlsx" | "json")[] | ["csv", "xlsx"] |
csvCSV conventions. | { delimiter?: "," | ";" | "\t"; bom?: boolean; decimal?: "locale" | "." } | from the locale |
requireReasonAsk for a reason always, or only when unmasked personal columns are included. | boolean | "personal-data" | "personal-data" |
syncLimitRows above this are announced as a background export. | number | 10000 |
presentationContainer. | "dialog" | "sheet" | "dialog" |
trigger / open / defaultOpen / onOpenChangeOpening, controlled or not. | ReactElement / boolean / fn | — |
defaultScope / defaultFormatInitial choices. | ExportScope / ExportFormat | — |
labelsBuilt-in strings (export namespace). | Partial<ExportLabels> | — |
exportToBlob(options)
| Prop | Type | Default |
|---|---|---|
rows / columns / formatData in, a file Blob out. | object[] / ExportColumn[] / ExportFormat | — |
maskedColumn ids written masked (a••••@domain.com). | string[] | — |
locale / csv / sheetNameCSV conventions and the XLSX sheet name. | string / CsvExportOptions / string | — |
QuickExportButton
| Prop | Type | Default |
|---|---|---|
onExportOne click: current view, default columns. | () => Promise<{ blob; filename }> | — |
ExportJobStatus
| Prop | Type | Default |
|---|---|---|
job / filename / onRetryThe job panel on its own (an exports page). | ExportJobState / string / fn | — |