- Data Table
- Examples
- Basic Data Table
- With Search
- With Sorting
- Local Sorting
- Pagination
- Hide Pagination
- Row Selection
- Hide Checkboxes
- Bulk Actions
- Secondary Columns
- Hide Columns
- Hide Headers
- Unsortable Columns
- Wide Columns
- Custom Empty State
- Filtering
- Filter Top Slot
- Filter Top with Tabs
- Additional Input Parameters
- Grouping Data
- Specific Groups
- No Initial Load
- Standalone Mode
- Request Method
- Cell Styling
- Row Actions
- Caption
- Programmatic Control
- Data Format
- Request Format
- Importing
- Slots
- Custom Properties
- Parts
- Dependencies
Data Table
<zn-data-table> | ZnDataTable
Short summary of the component’s intended use.
<zn-data-table data-uri="/data/data-table.json" method="GET" empty-state-caption="No records found" empty-state-icon="data_alert" headers='[ {"key":"id","label":"ID", "required":true, "default": true}, {"key":"name","label":"Name", "required":true, "default": true, "sortable":true}, {"key":"email","label":"Email", "sortable":true}, {"key":"status","label":"Status", "sortable":true}, {"key":"date","label":"Date Joined", "sortable":true} ]'> <zn-data-table-search slot="search" placeholder="Search records..."></zn-data-table-search> </zn-data-table>
Examples
Basic Data Table
The simplest data table fetches data from a URI and displays it with defined column headers. The
headers property defines the columns to display.
<zn-data-table data-uri="/data/data-table.json" method="GET" headers='[ {"key":"id","label":"ID"}, {"key":"name","label":"Name"}, {"key":"email","label":"Email"}, {"key":"status","label":"Status"} ]'> </zn-data-table>
With Search
Add a search component to filter table data. The search component emits debounced search events that trigger data reloading.
In this preview, search sends a search parameter with each request but the static data file
always returns the same results. With a real server endpoint, results would be filtered based on the
search term.
<zn-data-table data-uri="/data/data-table.json" method="GET" headers='[ {"key":"id","label":"ID"}, {"key":"name","label":"Name"}, {"key":"email","label":"Email"}, {"key":"status","label":"Status"} ]'> <zn-data-table-search slot="search" placeholder="Search by name or email..." debounce-delay="350"> </zn-data-table-search> </zn-data-table>
With Sorting
Enable column sorting by marking headers as sortable. Click column headers to sort data ascending or descending.
Server-side sorting sends sortColumn and sortDirection parameters with each
request. In this preview, the static data file returns results in the same order regardless. Use
local-sort (shown below) to see sorting in action without a server.
<zn-data-table data-uri="/data/data-table.json" method="GET" sort-column="name" sort-direction="asc" headers='[ {"key":"id","label":"ID"}, {"key":"name","label":"Name", "sortable":true}, {"key":"email","label":"Email", "sortable":true}, {"key":"status","label":"Status", "sortable":true}, {"key":"date","label":"Date", "sortable":true} ]'> </zn-data-table>
Local Sorting
Use local-sort to sort data client-side without making server requests. Best for small
datasets.
<zn-data-table data-uri="/data/data-table.json" method="GET" local-sort sort-column="name" sort-direction="asc" headers='[ {"key":"id","label":"ID"}, {"key":"name","label":"Name", "sortable":true}, {"key":"email","label":"Email", "sortable":true}, {"key":"status","label":"Status", "sortable":true} ]'> </zn-data-table>
Pagination
Data tables automatically display pagination controls when the total number of records exceeds the per-page limit. Users can navigate between pages and adjust rows per page.
Pagination controls appear based on the total and perPage values in the
response. In this preview, changing pages re-fetches the same static data. With a real server, each page
request would return the corresponding slice of data.
<zn-data-table data-uri="/data/data-table.json" method="GET" headers='[ {"key":"id","label":"ID"}, {"key":"name","label":"Name"}, {"key":"email","label":"Email"}, {"key":"status","label":"Status"} ]'> </zn-data-table>
Hide Pagination
Use hide-pagination to hide pagination controls even when multiple pages are available.
<zn-data-table data-uri="/data/data-table.json" method="GET" hide-pagination headers='[ {"key":"id","label":"ID"}, {"key":"name","label":"Name"}, {"key":"email","label":"Email"} ]'> </zn-data-table>
Row Selection
By default, rows can be selected by clicking. Selected rows are tracked and can be used with bulk actions.
<zn-data-table data-uri="/data/data-table.json" method="GET" headers='[ {"key":"id","label":"ID"}, {"key":"name","label":"Name"}, {"key":"email","label":"Email"}, {"key":"status","label":"Status"} ]'> <zn-button slot="delete-action" color="error" icon="delete" size="x-small"> Delete Selected </zn-button> </zn-data-table>
Hide Checkboxes
Use hide-checkboxes to disable row selection functionality.
<zn-data-table data-uri="/data/data-table.json" method="GET" hide-checkboxes headers='[ {"key":"id","label":"ID"}, {"key":"name","label":"Name"}, {"key":"email","label":"Email"} ]'> </zn-data-table>
Bulk Actions
Add action buttons to the table header for performing operations on selected rows. Use the
delete-action, modify-action, and create-action slots.
<zn-data-table data-uri="/data/data-table.json" method="GET" headers='[ {"key":"id","label":"ID"}, {"key":"name","label":"Name"}, {"key":"email","label":"Email"}, {"key":"status","label":"Status"} ]'> <zn-button slot="delete-action" color="error" icon="delete" size="x-small"> Delete Selected </zn-button> <zn-button slot="modify-action" color="info" icon="edit" size="x-small"> Edit Selected </zn-button> <zn-button slot="create-action" color="success" icon="add" size="x-small"> Create New </zn-button> </zn-data-table>
Secondary Columns
Mark columns as secondary to hide them by default. Users can expand rows to view secondary data.
<zn-data-table data-uri="/data/data-table.json" method="GET" headers='[ {"key":"id","label":"ID"}, {"key":"name","label":"Name"}, {"key":"email","label":"Email"}, {"key":"phone","label":"Phone", "secondary":true}, {"key":"address","label":"Address", "secondary":true}, {"key":"notes","label":"Notes", "secondary":true} ]'> </zn-data-table>
Hide Columns
Use hide-columns to completely hide specific columns from the table.
<zn-data-table data-uri="/data/data-table.json" method="GET" hide-columns='["id", "internal_id"]' headers='[ {"key":"id","label":"ID"}, {"key":"internal_id","label":"Internal ID"}, {"key":"name","label":"Name"}, {"key":"email","label":"Email"} ]'> </zn-data-table>
Hide Headers
Use hide-headers to hide column header text while keeping the column content visible.
<zn-data-table data-uri="/data/data-table.json" method="GET" hide-headers='["actions"]' headers='[ {"key":"name","label":"Name"}, {"key":"email","label":"Email"}, {"key":"actions","label":"Actions"} ]'> </zn-data-table>
Unsortable Columns
Disable sorting on specific columns using unsortable-headers, or disable sorting entirely with
unsortable.
<zn-data-table data-uri="/data/data-table.json" method="GET" unsortable-headers='["actions", "status"]' headers='[ {"key":"name","label":"Name", "sortable":true}, {"key":"email","label":"Email", "sortable":true}, {"key":"status","label":"Status"}, {"key":"actions","label":"Actions"} ]'> </zn-data-table>
Make the entire table unsortable:
<zn-data-table data-uri="/data/data-table.json" method="GET" unsortable headers='[ {"key":"name","label":"Name"}, {"key":"email","label":"Email"}, {"key":"status","label":"Status"} ]'> </zn-data-table>
Wide Columns
Use wide-column to specify which column should expand to fill available space.
<zn-data-table data-uri="/data/data-table.json" method="GET" wide-column="description" headers='[ {"key":"id","label":"ID"}, {"key":"name","label":"Name"}, {"key":"description","label":"Description"}, {"key":"status","label":"Status"} ]'> </zn-data-table>
Custom Empty State
Customize the empty state shown when no data is available using the empty-state slot or caption
attributes.
Try adjusting your search or filter criteria
<zn-data-table data-uri="/data/empty.json" method="GET" headers='[{"key":"id","label":"ID"},{"key":"name","label":"Name"}]'> <zn-empty-state slot="empty-state" icon="inbox" caption="No records found"> <p>Try adjusting your search or filter criteria</p> <zn-button color="success" icon="add">Create First Record</zn-button> </zn-empty-state> </zn-data-table>
Or use the built-in empty state with custom text:
<zn-data-table data-uri="/data/empty.json" method="GET" empty-state-caption="No customers found" empty-state-icon="person_off" caption="Customers" headers='[{"key":"id","label":"ID"},{"key":"name","label":"Name"}]'> </zn-data-table>
Filtering
Add advanced filtering with the zn-data-table-filter component. The filter opens a slideout
with a query builder.
In this preview, filter parameters are sent with the request but the static data file returns the same results regardless. With a real server endpoint, results would be filtered based on the applied criteria.
<zn-data-table data-uri="/data/data-table.json" method="GET" headers='[ {"key":"name","label":"Name", "filterable":true}, {"key":"email","label":"Email", "filterable":true}, {"key":"status","label":"Status", "filterable":true} ]'> <zn-data-table-search slot="search" placeholder="Search..."></zn-data-table-search> <zn-data-table-filter slot="filter" filters='[ {"id":"name","name":"Name","operators":["eq","contains"]}, {"id":"status","name":"Status","options":{"active":"Active","inactive":"Inactive"},"operators":["eq"]} ]'> </zn-data-table-filter> </zn-data-table>
Filter Top Slot
Add complex filtering options above the table using the filter-top slot. Perfect for search
forms and advanced filters.
This example uses no-initial-load so the table starts empty. Submitting the filter form
triggers a data load, but the static data file returns the same results regardless of filter values. With
a real server, results would be filtered accordingly.
Use the filters above to search for products
<zn-data-table data-uri="/data/products-table.json" method="GET" no-initial-load headers='[ {"key":"name","label":"Name"}, {"key":"category","label":"Category"}, {"key":"price","label":"Price"}, {"key":"stock","label":"Stock"} ]'> <zn-filter-wrapper slot="filter-top"> <div class="form-spacing"> <zn-input type="text" name="name" label="Product Name" span="4"></zn-input> <zn-input type="currency" name="price" label="Max Price" span="3"></zn-input> <zn-select name="category" span="3" label="Category" clearable> <zn-option value="beauty">Beauty</zn-option> <zn-option value="electronics">Electronics</zn-option> </zn-select> <zn-button color="success" submit>Search</zn-button> </div> </zn-filter-wrapper> <zn-empty-state slot="empty-state" icon="inventory_2" caption="No products found"> <p>Use the filters above to search for products</p> </zn-empty-state> </zn-data-table>
Filter Top with Tabs
Combine the filter-top slot with tabs for multiple filtering interfaces.
In this preview, filter and search parameters are sent with each request but the static data file returns the same results. With a real server endpoint, each tab’s filters would produce different results.
<zn-data-table data-uri="/data/products-table.json" method="GET" headers='[ {"key":"name","label":"Name"}, {"key":"category","label":"Category"}, {"key":"price","label":"Price"}, {"key":"stock","label":"Stock"} ]'> <zn-panel flush-x slot="filter-top"> <zn-tabs> <zn-navbar slot="top"> <li tab>Quick Search</li> <li tab="advanced">Advanced Search</li> </zn-navbar> <zn-sp gap="sm"> <zn-filter-wrapper with-submit> <zn-form-group label="Quick Search" help-text="Search by common fields"> <zn-input type="text" name="search" label="Keyword" span="6"></zn-input> <zn-input type="currency" name="price" label="Max Price" span="3"></zn-input> <zn-select name="category" span="3" label="Category" clearable> <zn-option value="beauty">Beauty</zn-option> </zn-select> </zn-form-group> </zn-filter-wrapper> </zn-sp> <zn-sp id="advanced" flush-y> <zn-filter-wrapper with-submit> <zn-query-builder filters='[ {"id":"name","name":"Name","operators":["eq","contains"]}, {"id":"category","name":"Category","options":{"beauty":"Beauty"},"operators":["eq"]} ]' name="query"> </zn-query-builder> </zn-filter-wrapper> </zn-sp> </zn-tabs> </zn-panel> </zn-data-table>
Additional Input Parameters
Use the inputs slot to include additional form inputs that get sent with every data request.
In this preview, the input values are sent as parameters with each request but the static data file returns the same results. With a real server, these additional parameters would filter or modify the response data.
<zn-data-table data-uri="/data/data-table.json" method="GET" headers='[ {"key":"name","label":"Name"}, {"key":"status","label":"Status"} ]'> <zn-select slot="inputs" name="filter_type" value="active"> <zn-option value="active">Active Only</zn-option> <zn-option value="all">All Records</zn-option> </zn-select> <input slot="inputs" name="user_id" value="123" type="hidden"> </zn-data-table>
Grouping Data
Group rows by a specific column using the group-by property. This loads all data and splits it
into separate tables.
No products match your criteria
<zn-data-table data-uri="/data/products-table.json" method="GET" group-by="category" headers='[ {"key":"name","label":"Name"}, {"key":"category","label":"Category"}, {"key":"price","label":"Price"}, {"key":"stock","label":"Stock"}, {"key":"rating","label":"Rating"} ]'> <zn-empty-state slot="empty-state" icon="inventory_2" caption="No products found"> <p>No products match your criteria</p> </zn-empty-state> </zn-data-table>
Specific Groups
When using grouping, control which groups to show with the groups property.
<zn-data-table data-uri="/data/products-table.json" method="GET" group-by="category" groups="Beauty, Electronics, *" headers='[ {"key":"name","label":"Name"}, {"key":"category","label":"Category"}, {"key":"price","label":"Price"} ]'> </zn-data-table>
Use * as a wildcard to include all other groups not explicitly listed.
No Initial Load
Prevent automatic data loading on mount with no-initial-load. Call the
refresh() method to manually trigger loading.
<zn-data-table id="manual-table" data-uri="/data/data-table.json" method="GET" no-initial-load headers='[ {"key":"name","label":"Name"}, {"key":"email","label":"Email"} ]'> <zn-filter-wrapper slot="filter-top"> <zn-input name="search" label="Search" span="6"></zn-input> <zn-button color="success" submit>Load Data</zn-button> </zn-filter-wrapper> </zn-data-table> <script type="module"> const table = document.querySelector('#manual-table'); const form = table.querySelector('zn-filter-wrapper'); form.addEventListener('submit', (e) => { e.preventDefault(); table.refresh(); }); </script>
Standalone Mode
Use standalone to render the table without a container wrapper, useful for embedding in other
components.
<zn-data-table data-uri="/data/data-table.json" method="GET" standalone headers='[ {"key":"name","label":"Name"}, {"key":"email","label":"Email"} ]'> </zn-data-table>
Request Method
Choose between GET and POST requests using the method property. POST is default and sends
parameters in the request body.
This preview uses GET against a static file. In production, POST requests send pagination, sorting, and filter parameters in the request body rather than as query string parameters.
<zn-data-table data-uri="/data/data-table.json" method="GET" headers='[ {"key":"name","label":"Name"}, {"key":"email","label":"Email"} ]'> </zn-data-table>
Cell Styling
Cells support various styling options through the data response format. Each cell can have colors, icons, links, chips, and hover content.
{ "rows": [ { "id": "1", "cells": [ {"text": "John Doe", "column": "name", "style": "bold"}, {"text": "Active", "column": "status", "chipColor": "success"}, {"text": "admin@example.com", "column": "email", "copyable": true}, {"text": "View", "column": "action", "uri": "/users/1", "color": "info"} ] } ], "page": 1, "perPage": 10, "total": 100 }
Available cell properties:
text: The display textcolumn: Column key this cell belongs tostyle: Comma-separated styles (bold, italic, mono, code, border, center)color: Text colorchipColor: Renders as a chip with specified coloruri: Makes cell content a linktarget: Link target attributecopyable: Adds a copy buttoniconSrc: Icon to display with texticonColor: Icon colorhoverContent: HTML content shown on hoverhoverPlacement: Hover tooltip placementsortValue: Value to use for sorting (overrides text)gaid: Google Analytics ID for tracking
Row Actions
Rows can have contextual actions that appear in a dropdown menu.
{ "rows": [ { "id": "1", "uri": "/users/1", "actions": [ { "text": "Edit", "uri": "/users/1/edit", "icon": "edit", "gaid": "edit-user" }, { "text": "Delete", "uri": "/users/1/delete", "icon": "delete", "confirmType": "error", "confirmTitle": "Delete User", "confirmContent": "Are you sure you want to delete this user?" } ], "cells": [...] } ] }
Caption
Add a caption to describe the table data.
<zn-data-table data-uri="/data/data-table.json" method="GET" caption="Customer Records" headers='[ {"key":"name","label":"Name"}, {"key":"email","label":"Email"} ]'> </zn-data-table>
Programmatic Control
Access table methods programmatically to control behavior.
<zn-data-table id="controlled-table" data-uri="/data/data-table.json" method="GET" headers='[ {"key":"name","label":"Name"}, {"key":"email","label":"Email"}, {"key":"status","label":"Status"} ]'> </zn-data-table> <br /> <zn-button id="refresh-btn" icon="refresh">Refresh Data</zn-button> <zn-button id="select-all-btn" icon="check_box">Select All</zn-button> <script type="module"> const table = document.querySelector('#controlled-table'); document.querySelector('#refresh-btn').addEventListener('click', () => { table.refresh(); }); document.querySelector('#select-all-btn').addEventListener('click', () => { table.selectAll(new Event('click')); }); </script>
Data Format
The data table expects responses in the following format:
{ "rows": [ { "id": "unique-row-id", "uri": "/path/to/resource", "target": "_blank", "actions": [], "cells": [ { "text": "Display Value", "column": "column_key", "color": "success", "style": "bold,mono", "uri": "/link", "copyable": true } ] } ], "page": 1, "perPage": 10, "total": 100 }
Request Format
For POST requests, the table sends:
{ "page": 1, "perPage": 10, "sortColumn": "name", "sortDirection": "asc", "filter": "", "search": "search term" }
Additional parameters from the inputs slot are merged into the request.
Importing
If you’re using the autoloader or the traditional loader, you can ignore this section. Otherwise, feel free to use any of the following snippets to cherry pick this component.
To import this component from the CDN using a script tag:
<script type="module" src="https://cdn.jsdelivr.net/npm/@kubex/zinc@1.0.86/dist/components/data-table/data-table.js"></script>
To import this component from the CDN using a JavaScript import:
import 'https://cdn.jsdelivr.net/npm/@kubex/zinc@1.0.86/dist/components/data-table/data-table.js';
To import this component using a bundler:
import '@kubex/zinc/dist/components/data-table/data-table.js';
Slots
| Name | Description |
|---|---|
| (default) | The default slot. |
search
|
Slot for search component. |
sort
|
Slot for sort component. |
filter
|
Slot for filter component. |
filter-top
|
Slot for top-level filter component. |
delete-action
|
Slot for delete action button. |
modify-action
|
Slot for modify action button. |
create-action
|
Slot for create action button. |
inputs
|
Slot for additional input controls. |
empty-state
|
Slot for custom empty state. |
Learn more about using slots.
Custom Properties
| Name | Description | Default |
|---|---|---|
--example |
An example CSS custom property. |
Learn more about customizing CSS custom properties.
Parts
| Name | Description |
|---|---|
base |
The component’s base wrapper. |
Learn more about customizing CSS parts.
Dependencies
This component automatically imports the following dependencies.
<zn-button><zn-button-group><zn-chip><zn-confirm><zn-data-table-search><zn-dropdown><zn-empty-state><zn-example><zn-hover-container><zn-icon><zn-input><zn-menu><zn-menu-item><zn-skeleton><zn-tooltip>