Export - Multiple sheets
One xlsx with 5 tabs - All orders + per-region splits - independent of the current grid filter. (requires @svgrid/enterprise)
A live, editable Svelte 5 data grid example from the SvGrid gallery (Data Export & Import). See the SvGrid documentation for the full API.
About this example
A multi-sheet Excel export from the Svelte 5 data grid: one xlsx with an All orders tab and one tab per region, written independently of the current grid filter. The user can filter the grid to a single region while exportData({ format: 'xlsx', sheets: [{ label, rows }, ...] }) writes every region on its own sheet, because the export is a snapshot of the data you hand it.
One xlsx, three tabs: a per-region split + an "All orders" overview. The user picks a region in the grid; the export writes ALL regions regardless of the current filter, each on its own sheet.
await pro.exportData({ format: 'xlsx', sheets: [ { label: 'All', rows: allOrders }, { label: 'EMEA', rows: orders.filter(...) }, { label: 'APAC', rows: orders.filter(...) }, { label: 'AMER', rows: orders.filter(...) }, ], })
The grid keeps showing the filtered view. The export is a pure snapshot of the data you hand it.
Imports, features and API used
Imports: @svgrid/grid, @svgrid/enterprise, ../shared/seed
Table features registered: rowSortingFeature, columnFilteringFeature
Columns: orderId (Order ID), company (Company), product (Product), country (Country), quantity (Qty), price (Price)
SvGridApi methods called: api.exportData()
Frequently asked questions
How do I write several sheets?
Pass a sheets array to exportData, each entry with a label and its rows, and optionally its own columns. The workbook gets one tab per entry in that order.
Does the export follow the grid's filter?
Not when you pass rows explicitly. The sheets here are built from the full orders array, so the file is complete even while the grid shows one region; omit rows to export the current view instead.
Can each sheet have different columns?
Yes. A sheet entry may carry its own columns array, which is how a summary tab and a detail tab can differ in the same file.
Related documentation
Related articles
- What's New in SvGrid Enterprise - Export, Pivot, Import, Print, and AI - A practical look at @svgrid/enterprise - pivot tables, Excel and PDF export, data import, printing, and an AI assistant. Covers when each feature earns its place and what to watch out for in production.
- Importing CSV into a Svelte Data Grid - Parse a user-uploaded CSV file into objects, map its headers to grid columns, validate rows before committing, and handle the edge cases that actually bite you in production.
- CSV vs XLSX vs TSV - Which Export Format? - A practical breakdown of CSV, XLSX, and TSV for data grid exports - when each format earns its keep, what each one silently loses, and how to wire all three in SvGrid.
Source code (59-export-multi-sheet.svelte)
<script lang="ts">
/**
* 59. Export - multiple sheets (Pro)
* ---------------------------------
* One xlsx, three tabs: a per-region split + an "All orders" overview.
* The user picks a region in the grid; the export writes ALL regions
* regardless of the current filter, each on its own sheet.
*
* await pro.exportData({
* format: 'xlsx',
* sheets: [
* { label: 'All', rows: allOrders },
* { label: 'EMEA', rows: orders.filter(...) },
* { label: 'APAC', rows: orders.filter(...) },
* { label: 'AMER', rows: orders.filter(...) },
* ],
* })
*
* The grid keeps showing the filtered view. The export is a pure
* snapshot of the data you hand it.
*/
import {
SvGrid,
tableFeatures,
rowSortingFeature,
columnFilteringFeature,
type GridColumns,
type SvGridApi,
} from '@svgrid/grid'
import {
installEnterprise,
setLicenseKey,
type EnterpriseGridApi,
} from '@svgrid/enterprise'
import { makeOrders, type Order } from '../shared/seed'
setLicenseKey('SVENTERPRISE-DEV-DEMO')
const features = tableFeatures({ rowSortingFeature, columnFilteringFeature })
const allOrders = makeOrders(400)
// Map every order's country into a coarse region. The seed already
// supplies a country per row; this is the typical pattern customers
// follow when their data has finer granularity than the desired sheet
// split.
const REGION_OF: Record<string, 'AMER' | 'EMEA' | 'APAC'> = {
'United States': 'AMER', Canada: 'AMER', Mexico: 'AMER', Brazil: 'AMER', Argentina: 'AMER',
'United Kingdom': 'EMEA', Germany: 'EMEA', France: 'EMEA', Italy: 'EMEA', Spain: 'EMEA',
Netherlands: 'EMEA', Sweden: 'EMEA', Norway: 'EMEA', Poland: 'EMEA',
Japan: 'APAC', China: 'APAC', India: 'APAC', Australia: 'APAC', Singapore: 'APAC',
'South Korea': 'APAC', Indonesia: 'APAC',
}
function regionOf(o: Order): 'AMER' | 'EMEA' | 'APAC' | 'Other' {
return REGION_OF[o.country] ?? 'Other'
}
let region = $state<'all' | 'AMER' | 'EMEA' | 'APAC' | 'Other'>('all')
const visible = $derived(
region === 'all' ? allOrders : allOrders.filter((o) => regionOf(o) === region),
)
let api = $state<EnterpriseGridApi<typeof features, Order> | null>(null)
let busy = $state(false)
async function doExport() {
if (!api) return
busy = true
try {
await api.exportData({
format: 'xlsx',
filename: 'orders-by-region',
sheets: [
{ label: 'All orders', rows: allOrders },
{ label: 'AMER', rows: allOrders.filter((o) => regionOf(o) === 'AMER') },
{ label: 'EMEA', rows: allOrders.filter((o) => regionOf(o) === 'EMEA') },
{ label: 'APAC', rows: allOrders.filter((o) => regionOf(o) === 'APAC') },
{ label: 'Other', rows: allOrders.filter((o) => regionOf(o) === 'Other') },
],
})
} catch (err) {
console.error('[export]', err)
} finally {
busy = false
}
}
const columns: GridColumns<Order> = [
{ field: 'orderId', header: 'Order ID', editorType: 'text', width: 140 },
{ field: 'company', header: 'Company', editorType: 'text', width: 180 },
{ field: 'product', header: 'Product', editorType: 'text', width: 180 },
{ field: 'country', header: 'Country', editorType: 'text', width: 140 },
{ field: 'quantity', header: 'Qty', editorType: 'number', width: 80 },
{
field: 'price', header: 'Price', editorType: 'number', width: 110,
format: { type: 'currency', currency: 'USD' },
},
]
</script>
<section class="flex flex-col flex-1 min-h-0 gap-3">
<div class="flex flex-wrap items-center gap-2 text-sm shrink-0">
<span class="font-medium">Filter view:</span>
{#each ['all', 'AMER', 'EMEA', 'APAC', 'Other'] as r (r)}
<button
type="button"
onclick={() => (region = r as typeof region)}
class="rounded border px-3 py-1 ms-btn {region === r ? 'is-on' : ''}"
>{r === 'all' ? 'All' : r}</button>
{/each}
<button
type="button"
onclick={doExport}
disabled={busy}
class="ml-auto rounded border px-3 py-1 disabled:opacity-50 ms-btn"
>
{busy ? 'Exporting…' : '⬇ Export 5-sheet XLSX'}
</button>
</div>
<p class="text-xs shrink-0 ms-note">
The grid shows the <strong>{region === 'all' ? 'All orders' : region}</strong> view ({visible.length} rows).
The exported file always contains <strong>5 sheets</strong> regardless of the current filter.
</p>
<div class="flex-1 min-h-0">
<SvGrid responsive={true}
columnResize
data={visible}
columns={columns}
features={features}
filterMode="menu"
selectionMode="cell"
showRowNumbers={true}
showPagination={true}
pageSize={25}
enableInlineEditing={false}
enableCellSelection={true}
rowHeight={36}
containerHeight="100%"
fitColumns={true}
onApiReady={(next) => (api = installEnterprise(next))}
/>
</div>
</section>
<style>
.ms-note { color: var(--sg-muted, #64748b); }
.ms-btn {
border-color: var(--sg-border, #cbd5e1);
background: var(--sg-bg, #ffffff);
color: var(--sg-fg, #0f172a);
}
.ms-btn:hover:not(:disabled) { background: var(--sg-row-hover-bg, #f1f5f9); }
.ms-btn.is-on {
background: var(--sg-accent, #e2e8f0);
border-color: var(--sg-accent, #e2e8f0);
color: var(--sg-on-accent, #0f172a);
}
</style>More Data Export & Import examples
- Excel / CSV import - File picker + column mapping + per-row validation preview before commit. Reads xlsx / csv / tsv / json with format auto-detect.
- Export + Print - Enterprise feature pack: download to Excel, PDF, CSV, TSV, HTML, or open a printable view in a new window.
- Export - Theme-matched - One xlsx, light or dark - styles read from the same --sg-* tokens the grid renders with.
- Export - Header + Footer + Logo - Branded xlsx: PNG logo + title + subtitle in the page header, generated date + page numbers in the footer.
- Export - Cell images - Product grid with thumbnail column. On xlsx export each thumbnail is embedded as a real picture cell.