# Export - Header + Footer + Logo

Branded xlsx: PNG logo + title + subtitle in the page header, generated date + page numbers in the footer.

Requires `@svgrid/enterprise` (and `@svgrid/grid`). Category: Data Export & Import. Live demo: https://svgrid.com/demos/57-export-header-footer-logo/

Install: `npm i @svgrid/grid @svgrid/enterprise` (Svelte 5).

## 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](https://svgrid.com/blog/whats-new-svgrid-enterprise/) - 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](https://svgrid.com/blog/multi-level-column-headers/) - 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](https://svgrid.com/blog/importing-csv-into-the-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)

```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,
    type EnterpriseGridApi,
    type ExportHeaderFooterLine,
  } from '@svgrid/enterprise'
  import { makeOrders, type Order } from '../shared/seed'

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

[View this example on GitHub](https://github.com/sv-grid/sv-grid/blob/main/examples/src/demos/57-export-header-footer-logo.svelte)
