v1.6.x-dev NDS IQ v6

Export - National Design System

A declarative download utility for turning any table, card list, or marked-up container into a CSV, Excel, or print-ready PDF file with selection and pagination support.

Table Export

A button group above the table triggers CSV, Excel, or PDF downloads. The library reads the table's headers, body rows, and checkbox state automatically

Standard
Reference Customer Amount Actions
128 حسن المختار 240
129 نادية الخطيب 1250
130 طارق السديري 85
131 زهرة الحبيب 3120
<div class="nds-toolbar"> <div class="nds-bar-end"> <!-- Hiding a column stamps data-export-skip, so exports follow the view --> <div class="nds-dropmenu" data-columns-target="orders"> <button class="nds-btn nds-neutral nds-md nds-menu-btn nds-dropmenu-trigger" type="button"> <i class="nds-icon nds-hgi-view-off-slash" aria-hidden="true"></i> <span class="nds-label">Columns</span> </button> <div class="nds-dropmenu-menu" hidden> <div class="nds-dropmenu-scroll"> <fieldset class="nds-form-group nds-check-group nds-dropmenu-group" data-columns-list data-no-auto-close> <legend class="nds-label">Visible columns</legend> </fieldset> </div> </div> </div> <div class="nds-export nds-btn-group"> <button type="button" class="nds-btn nds-secondary-outline nds-md" data-export="csv" data-export-target="#orders"> <span class="nds-label">CSV</span> </button> <button type="button" class="nds-btn nds-secondary-outline nds-md" data-export="xls" data-export-target="#orders"> <span class="nds-label">Excel</span> </button> <button type="button" class="nds-btn nds-secondary-outline nds-md" data-export="pdf" data-export-target="#orders"> <span class="nds-label">PDF</span> </button> </div> </div> </div> <table id="orders" class="nds-table nds-compact" data-export-name="orders"> <thead> <tr> <th> <div class="nds-form-container nds-check-container"> <div class="nds-form-control"> <input type="checkbox" class="nds-check" aria-label="Select all rows"> </div> </div> </th> <th>Reference</th> <th>Customer</th> <th data-export-label="Amount (SAR)">Amount</th> <th data-export-skip>Actions</th> </tr> </thead> <tbody> <tr> <td> <div class="nds-form-container nds-check-container"> <div class="nds-form-control"> <input type="checkbox" class="nds-check" aria-label="Select 128"> </div> </div> </td> <td>128</td> <td>حسن المختار</td> <td data-export-value="240"><span class="nds-number-format" data-currency="SAR">240</span></td> <td><button class="nds-btn nds-sm nds-subtle">View</button></td> </tr> <tr> <td> <div class="nds-form-container nds-check-container"> <div class="nds-form-control"> <input type="checkbox" class="nds-check" aria-label="Select 129"> </div> </div> </td> <td>129</td> <td>نادية الخطيب</td> <td data-export-value="1250"><span class="nds-number-format" data-currency="SAR">1250</span></td> <td><button class="nds-btn nds-sm nds-subtle">View</button></td> </tr> <tr> <td> <div class="nds-form-container nds-check-container"> <div class="nds-form-control"> <input type="checkbox" class="nds-check" aria-label="Select 130"> </div> </div> </td> <td>130</td> <td>طارق السديري</td> <td data-export-value="85"><span class="nds-number-format" data-currency="SAR">85</span></td> <td><button class="nds-btn nds-sm nds-subtle">View</button></td> </tr> <tr> <td> <div class="nds-form-container nds-check-container"> <div class="nds-form-control"> <input type="checkbox" class="nds-check" aria-label="Select 131"> </div> </div> </td> <td>131</td> <td>زهرة الحبيب</td> <td data-export-value="3120"><span class="nds-number-format" data-currency="SAR">3120</span></td> <td><button class="nds-btn nds-sm nds-subtle">View</button></td> </tr> </tbody> </table>

Generic Source

Card lists, definition lists, and any custom container become exportable by tagging their rows and fields with two data attributes

<div id="servicesExport"> <div class="nds-toolbar"> <div class="nds-bar-end"> <div class="nds-export nds-btn-group"> <button type="button" class="nds-btn nds-secondary-outline nds-md" data-export="csv" data-export-target="#services"> <span class="nds-label">CSV</span> </button> <button type="button" class="nds-btn nds-secondary-outline nds-md" data-export="xls" data-export-target="#services"> <span class="nds-label">Excel</span> </button> <button type="button" class="nds-btn nds-secondary-outline nds-md" data-export="pdf" data-export-target="#services"> <span class="nds-label">PDF</span> </button> </div> </div> </div> <div id="services" class="nds-grid" style="--max-col:3;--mid-col:2;--min-col:1;" data-export-rows=".nds-card" data-export-name="services"> <label class="nds-card nds-stroke"> <div class="nds-card-header"> <div class="nds-card-featured-icon"> <span class="nds-featured-icon nds-circle nds-lg"> <i class="hgi hgi-stroke hgi-passport"></i> </span> </div> </div> <div class="nds-card-checkbox"> <div class="nds-form-container nds-check-container"> <div class="nds-form-control"> <input type="checkbox" class="nds-check" aria-label="Select Passport Renewal"> </div> </div> </div> <div class="nds-card-content"> <div class="nds-card-text"> <span class="nds-card-title" data-export-field="service" data-export-label="Service">Passport Renewal</span> <p class="nds-card-description" data-export-field="entity" data-export-label="Entity">General Directorate of Passports</p> </div> <div class="nds-card-meta"> <div class="nds-card-tags"> <span class="nds-tag nds-yellow nds-sm" data-export-field="status" data-export-label="Status"> <span class="nds-label">In Progress</span> </span> </div> </div> </div> </label> <label class="nds-card nds-stroke"> <div class="nds-card-header"> <div class="nds-card-featured-icon"> <span class="nds-featured-icon nds-circle nds-lg"> <i class="hgi hgi-stroke hgi-car-01"></i> </span> </div> </div> <div class="nds-card-checkbox"> <div class="nds-form-container nds-check-container"> <div class="nds-form-control"> <input type="checkbox" class="nds-check" aria-label="Select Driving Licence"> </div> </div> </div> <div class="nds-card-content"> <div class="nds-card-text"> <span class="nds-card-title" data-export-field="service">Driving Licence</span> <p class="nds-card-description" data-export-field="entity">Traffic Department</p> </div> <div class="nds-card-meta"> <div class="nds-card-tags"> <span class="nds-tag nds-green nds-sm" data-export-field="status"> <span class="nds-label">Completed</span> </span> </div> </div> </div> </label> <label class="nds-card nds-stroke"> <div class="nds-card-header"> <div class="nds-card-featured-icon"> <span class="nds-featured-icon nds-circle nds-lg"> <i class="hgi hgi-stroke hgi-store-01"></i> </span> </div> </div> <div class="nds-card-checkbox"> <div class="nds-form-container nds-check-container"> <div class="nds-form-control"> <input type="checkbox" class="nds-check" aria-label="Select Commercial Registration"> </div> </div> </div> <div class="nds-card-content"> <div class="nds-card-text"> <span class="nds-card-title" data-export-field="service">Commercial Registration</span> <p class="nds-card-description" data-export-field="entity">Ministry of Commerce</p> </div> <div class="nds-card-meta"> <div class="nds-card-tags"> <span class="nds-tag nds-gray nds-sm" data-export-field="status"> <span class="nds-label">Pending</span> </span> </div> </div> </div> </label> </div> </div>

Built-in Features

Multi-Format Output

Every source exports to CSV, Excel, or PDF from the same buttons. CSV ships with a UTF-8 BOM and RFC 4180 quoting, Excel as an HTML payload with the correct MIME, and PDF through the browser's native print dialog.

Source Agnostic

Works on any <table> or .nds-table with zero markup changes. Card lists, definition lists, and custom containers opt in by adding data-export-rows and data-export-field.

Smart Selection Scope

If any row carries data-state="selected" or contains a checked input.nds-check, only that subset is exported. Otherwise the full set ships. No wiring required.

Pagination Aware

Paginated tables export every page, not just the visible one. The library walks through hidden rows inside .nds-paged-content so the file always matches the full dataset. A table's own rows only: detail rows (nds-sub) and any table nested inside one are skipped, so an expanded row never leaks its inner table into the file.

CSV Injection Guard

Cells starting with =, +, -, or @ are auto-prefixed with an apostrophe so spreadsheets treat them as text instead of evaluating them as formulas.

Print-Ready PDF

The PDF path renders a clean table into a hidden iframe and triggers the browser's print dialog. Output uses light-mode tokens for legibility on paper, with header repeat across pages and proper page breaks.

RTL & UTF-8 Ready

Arabic and other non-Latin scripts round-trip cleanly in CSV thanks to the UTF-8 BOM. Excel and PDF outputs honor the page's text direction so right-to-left columns stay right-to-left.

Filter Aware

Rows hidden by NDS.Filter (data-filtered attribute) are excluded from the export. This is distinct from pagination-hidden rows, which are always included. Export reflects the active filter without any extra wiring.

Declarative & Programmatic

Drop a data-export button anywhere on the page and it works through a single delegated listener. The full NDS.Export namespace is also available for triggering exports from custom JS.

Usage Guidelines

Best Practices

  • Reach for the declarative attribute pattern first: a [data-export] button with data-export-target needs no per-page JS and works for dynamically injected toolbars too.
  • Use the same component for non-table lists. Tag the container with data-export-rows="<selector>" and each field inside a row with data-export-field="key". Cards and definition lists become exportable without a new component.
  • Place currency, units, and other column-wide qualifiers in the header label via data-export-label="Amount (SAR)", not in every cell. CSV and Excel can then do math on the column.
  • Add data-export-skip on per-row action columns (Edit, Delete, View buttons) so they don't leak into the file. The auto-detected checkbox column is already skipped.
  • Exports follow the visible table. A column hidden through the Table column menu stamps its own data-export-skip, so it drops out of the file and returns when the column is shown again. An authored data-export-skip always survives. A table with an id remembers its hidden columns across visits, so a returning user's export matches the view they left behind.
  • Set data-export-name on the source for a meaningful filename. Output is {name}-YYYY-MM-DD.{ext}.
  • If a cell shows a formatted value but the spreadsheet needs the raw one, set data-export-value on the <td>. The display stays the same, the export gets the raw number or ISO date.
  • Selection just works: drop the canonical nds-card-checkbox or .nds-check markup, and any checked row is exported automatically when scope is 'auto'.
  • For tables that use a header column for the visible label and a separate value (sortable status enums, currency cells), do not rely on data-sort-value for the export. Sort and export are decoupled by design.
  • Don't pre-format numbers inside cells if you want spreadsheet math. Use data-export-value with the raw number so the export becomes summable.
  • For pure source-of-truth control over the file, the programmatic API (NDS.Export.collect + NDS.Export.toCSV) lets a custom script transform or filter the data before download.
  • CSV and Excel downloads announce the row count to screen readers automatically: NDS.announce('Exported N rows') fires after the file is triggered. No extra markup is needed, but avoid suppressing the live region if you customize the download flow.

Data Attributes

AttributePlacementDescription
data-export="csv|xls|pdf"Trigger buttonMarks the element as an export button and chooses the format. Required.
data-export-target="<selector>"Trigger buttonSelector for the source. Optional: omit when the button lives inside the source.
data-export-scope="all|selected|auto"Trigger buttonForce the export scope. Default "auto": selected rows if any, otherwise all.
data-export-nameSource elementFilename stem. Result: {name}-YYYY-MM-DD.{ext}. Default "nds-export".
data-export-rows="<selector>"Non-table sourceSelector that matches each row inside the source. Required to opt a non-table container into the generic adapter.
data-export-field="key"Element inside a rowMarks an element as a field. The set of keys across all rows becomes the export columns.
data-export-label<th> or field elementOverride the column heading used in the file (e.g. "Amount (SAR)" for a raw number column).
data-export-value<td> or field elementOverride the exported cell value. Useful when the cell shows a formatted string and the file needs the raw value.
data-export-skip<th>, <td>, or field elementDrop the column (on a <th>) or the single cell (on a <td> / field). On the source itself, accepts a space-separated list of field keys.

JavaScript API

The library auto-binds to [data-export] buttons via a single delegated listener. The NDS.Export namespace is also available for triggering exports from custom scripts, building one-off formats, or accessing the normalized data.

// Per-format shortcuts: preferred for most call sites NDS.Export.csv('#orders'); // 'auto' scope, default filename NDS.Export.xls('#orders', 'all'); // force the full set NDS.Export.pdf('#orders', 'selected', { // explicit override + opts filename: 'q2-orders.pdf', title: 'Q2 Orders' }); // Generic entry point: useful when the format is dynamic NDS.Export.export('#orders', format, 'auto'); // Normalize a source to { columns, rows } without downloading const data = NDS.Export.collect('#orders', 'all'); // returns { columns: [{ key, label }, ...], rows: [{ [key]: value }, ...] } // Pure formatters: transform the data manually, then download const csvString = NDS.Export.toCSV(data); // UTF-8 string with BOM const xlsHtmlStr = NDS.Export.toXLSHtml(data, { dir: 'rtl' // override the page's direction }); // Side-effecting helpers: used by the shortcuts above NDS.Export.openPrint(data, { title: 'Q2 Orders' }); // hidden iframe + native print NDS.Export.download(data, 'csv', { // route normalized data to a file filename: 'snapshot.csv' }); // Trigger any format from a custom event document.querySelector('#exportNow').addEventListener('click', () => { NDS.Export.csv('#orders'); });
Last Modified Date: 29/07/2026 - 01:32 AM
Was this page useful?
60% of users said Yes from 2843 Feedbacks