Export - Header + Footer + Logo
Branded xlsx: PNG logo + title + subtitle in the page header, generated date + page numbers in the footer. (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 branded Excel export from the Svelte 5 data grid: a single-sheet xlsx that opens with a page header holding a PNG logo, the company name and a report subtitle, and a three-segment footer with the generated date on the left, the brand URL in the centre and Excel page-number fields on the right. The lines are passed as ExportHeaderFooterLine entries, and image lines are embedded as real pictures in the workbook.
Generates a single-sheet xlsx that opens with a branded page header (PNG logo + company name + report subtitle) and a three-segment footer (left: generated date, center: brand URL, right: Excel page-number macros). All lines are forwarded via ExportHeaderFooterLine[] and the wrapper translates them into Smart's headerContent rows; image lines route through addImageToCell to embed a real picture.
Imports, features and API used
Imports: svelte, @svgrid/grid, @svgrid/enterprise, ../shared/seed
Table features registered: rowSortingFeature, columnFilteringFeature
Columns: orderId (Order ID), company (Company), product (Product), sellDate (Sell date), quantity (Qty), price (Price), country (Country)
SvGridApi methods called: api.exportData()
Frequently asked questions
How do I add a logo to the export?
Pass an image line in the header array of exportData with the PNG as a data URL or fetched bytes. The exporter embeds it in the workbook's media and anchors it in the header area.
How do page numbers work?
The footer's right segment carries Excel's page-number and page-count fields, which Excel resolves when printing, so a long sheet numbers itself.
Can the header be text only?
Yes. Any mix of text and image lines is accepted; omit the image line for a plain title and subtitle.
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.
- Multi-Level (Grouped) Column Headers in SvGrid - Band related columns under a shared parent header using SvGrid's nested column definition - how to nest, pin, combine with sorting and filtering, and when NOT to use grouping.
- 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.
Source code (57-export-header-footer-logo.svelte)
<script lang="ts">
/**
* 57. Export - branded xlsx (header + footer + logo) (Pro)
* -------------------------------------------------------
* Generates a single-sheet xlsx that opens with a branded page header
* (PNG logo + company name + report subtitle) and a three-segment footer
* (left: generated date, center: brand URL, right: Excel page-number
* macros). All lines are forwarded via `ExportHeaderFooterLine[]` and the
* wrapper translates them into Smart's `headerContent` rows; image lines
* route through `addImageToCell` to embed a real picture.
*/
import { onMount } from 'svelte'
import {
SvGrid,
tableFeatures,
rowSortingFeature,
columnFilteringFeature,
type GridColumns,
} from '@svgrid/grid'
import {
installEnterprise,
setLicenseKey,
type EnterpriseGridApi,
type ExportHeaderFooterLine,
} from '@svgrid/enterprise'
import { makeOrders, type Order } from '../shared/seed'
setLicenseKey('SVENTERPRISE-DEV-DEMO')
const features = tableFeatures({ rowSortingFeature, columnFilteringFeature })
const rows = makeOrders(120)
let api = $state<EnterpriseGridApi<typeof features, Order> | null>(null)
let busy = $state(false)
let logoPng = $state<string | null>(null)
// Rasterise the SVG mark to PNG once. Excel doesn't render embedded SVG
// reliably, so we paint it to a canvas and read back a PNG data URL.
onMount(async () => {
const svg = `
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'>
<rect width='64' height='64' rx='12' fill='#2563eb'/>
<text x='32' y='42' text-anchor='middle' fill='#fff'
font-family='Inter, sans-serif' font-size='28' font-weight='800'>SG</text>
</svg>`
const svgUrl = `data:image/svg+xml;base64,${btoa(svg.trim())}`
const img = new Image()
img.src = svgUrl
await new Promise<void>((resolve) => { img.onload = () => resolve() })
const cv = document.createElement('canvas')
cv.width = 64; cv.height = 64
cv.getContext('2d')!.drawImage(img, 0, 0, 64, 64)
logoPng = cv.toDataURL('image/png')
})
async function doExport() {
if (!api || !logoPng) return
busy = true
try {
const header: ExportHeaderFooterLine[] = [
{ image: logoPng, width: 64, height: 64 },
{ text: 'SvGrid Industries Inc.',
style: { fontWeight: 'bold', fontSize: 18, color: '#0f172a' } },
{ text: `Q${Math.ceil((new Date().getMonth() + 1) / 3)} ${new Date().getFullYear()} Orders - Internal`,
style: { color: '#64748b', fontSize: 12 } },
]
const footer: ExportHeaderFooterLine[] = [
{
left: `Generated ${new Date().toISOString().slice(0, 10)}`,
center: 'svgrid.com',
right: 'Page &P of &N',
},
]
await api.exportData({
format: 'xlsx',
filename: 'orders-branded',
header,
footer,
})
} 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: 'sellDate', header: 'Sell date', editorType: 'date', width: 120,
format: { type: 'date', pattern: 'y-m-d' },
},
{ field: 'quantity', header: 'Qty', editorType: 'number', width: 80 },
{
field: 'price', header: 'Price', editorType: 'number', width: 110,
format: { type: 'currency', currency: 'USD' },
},
{ field: 'country', header: 'Country', editorType: 'text', width: 110 },
]
</script>
<section class="flex flex-col flex-1 min-h-0 gap-3">
<div class="flex flex-wrap items-center gap-3 text-sm shrink-0">
<button
type="button"
onclick={doExport}
disabled={busy || !logoPng}
class="xp-btn inline-flex items-center gap-2 rounded-md px-3 py-1.5 font-medium disabled:opacity-50"
>
{#if logoPng}<img src={logoPng} alt="" class="h-5 w-5 rounded" />{/if}
{busy ? 'Exporting…' : 'Download branded XLSX'}
</button>
<div class="xp-note">
The logo above is embedded in the xlsx page header; the footer carries the date + Excel page-number macros.
</div>
</div>
<div class="flex-1 min-h-0">
<SvGrid responsive={true}
columnResize
data={rows}
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>
.xp-btn {
border: 1px solid var(--sg-accent, #4f46e5);
background: var(--sg-accent, #4f46e5);
color: var(--sg-on-accent, #fff);
}
.xp-btn:hover:not(:disabled) { filter: brightness(1.08); }
.xp-note { color: var(--sg-muted, #64748b); }
</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 - Cell images - Product grid with thumbnail column. On xlsx export each thumbnail is embedded as a real picture cell.
- Export - Multiple sheets - One xlsx with 5 tabs - All orders + per-region splits - independent of the current grid filter.