Skip to main content
Light Dark System

Data Table

<zn-data-table> | ZnDataTable
Since 1.0 experimental

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>

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>

Add a search component to filter table data. The search component emits debounced search events that trigger data reloading.

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

<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 the rows per page.

Pagination renders as a single joined control: first, previous, a sliding window of three page numbers, next, last. The window keeps the control a fixed width whatever the dataset — the same at 30 pages as at 3000 — while the first and last buttons cover jumping to either end. On narrow widths the footer wraps so pagination sits above the rows selector.

<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

Rows get a checkbox column and can be selected by clicking once the table has an action to use them: something in the delete-action, modify-action, create-action or actions slot. Without one, the table has no checkboxes.

Delete Selected
<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">
    Delete Selected
  </zn-button>

</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.

delete-action and modify-action appear at the start of the header’s right-hand group once rows are selected. create-action is a primary action rather than a selection one, so it renders at the end of that group, after the search field.

Delete Selected Edit Selected Create New
<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">
    Delete Selected
  </zn-button>

  <zn-button slot="modify-action" color="info" icon="edit">
    Edit Selected
  </zn-button>

  <zn-button slot="create-action" color="success" icon="add">
    Create New
  </zn-button>

</zn-data-table>

Actions Menu

Elements in the actions slot are listed in an ellipsis menu at the start of the header’s right-hand group. The menu is disabled until at least one row is checked. Each zn-button becomes a menu item using its label, icon and color, and choosing it clicks the button. A zn-confirm takes its label and icon from its trigger slot button, and choosing it opens the confirm dialog. An input[name="keys"] inside a slotted element is kept filled with the selected row keys, the same as for delete-action.

Archive Delete
<zn-data-table
  data-uri="/data/data-table.json"
  method="GET"
  caption="Customers"
  headers='[
    {"key":"id","label":"ID"},
    {"key":"name","label":"Name"},
    {"key":"email","label":"Email"},
    {"key":"status","label":"Status"}
  ]'>

  <zn-button slot="actions" icon="archive@lu">Archive</zn-button>

  <zn-confirm slot="actions" type="error" caption="Delete customers" content="Delete the selected customers?">
    <zn-button slot="trigger" icon="trash-2@lu" color="error">Delete</zn-button>
    <form><input type="hidden" name="keys"></form>
  </zn-confirm>

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

Column Select

The header carries a column select dropdown whenever the table has rows and more than one column can be toggled. Mark a header "required": true to pin it on, or "default": false to start it hidden. Set hide-column-select to remove the dropdown.

<zn-data-table
  data-uri="/data/data-table.json"
  method="GET"
  standalone
  caption="Customers"
  headers='[
    {"key":"name","label":"Name", "required":true},
    {"key":"email","label":"Email"},
    {"key":"status","label":"Status"},
    {"key":"phone","label":"Phone"},
    {"key":"address","label":"Address", "default":false}
  ]'>
</zn-data-table>

Refresh

Tables with a data-uri get a refresh button in the header, which reruns the current request. Set hide-refresh to remove it.

Both the refresh and column select buttons are hidden while the table has no rows, so an empty state keeps just the caption and the slotted controls.

<zn-data-table
  data-uri="/data/data-table.json"
  method="GET"
  standalone
  caption="Customers"
  hide-column-select
  headers='[
    {"key":"name","label":"Name"},
    {"key":"email","label":"Email"}
  ]'>
</zn-data-table>

Hide Columns

Use hide-columns to completely hide specific columns from the table. Unlike the column select, these columns cannot be turned back on.

<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

Create First Record
<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 filtering with the zn-data-table-filter component. The header carries a filter toggle beside the refresh button; clicking it reveals a row between the header and the rows holding the filter slot, where the filter component shows one pill per active filter alongside add-filter and clear controls. The row stays hidden until the toggle is clicked, and the toggle carries a count of the filters currently applied. Use default-filters to show a pill for a filter before the user adds it.

The table also feeds the bar typeahead values for its text filters, taken from the rows it has loaded and keyed on the column whose name matches the filter’s id.

<zn-data-table
  standalone
  caption="Users"
  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"
    default-filters="status"
    filters='[
      {"id":"name","name":"Name","operators":["contains"]},
      {"id":"status","name":"Status","options":{"active":"Active","inactive":"Inactive"},"operators":["eq"]},
      {"id":"role","name":"Role","options":{"admin":"Admin","user":"User"},"operators":["in"]}
    ]'>
  </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.

Content in this slot renders above the table’s own panel rather than inside it, so wrap it in a zn-panel when it needs its own frame. It never contributes a header row to the table, and with standalone an empty state that has no caption or header controls is left unwrapped, so a zn-panel around the empty-state slot doesn’t end up nested inside another.

Beauty Electronics Search

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.

  • Quick Search
  • Advanced Search
  • Beauty
    <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.

    Active Only All Records
    <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 groups.

    Groups render as header rows inside a single table, so every group shares the same column widths, one set of column headers and one horizontal scrollbar.

    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.

    Load Data
    <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>
    

    Shareable URL State

    Set sharable to mirror the table’s non-default state to the URL query string and restore it on load, so a view can be copied straight from the address bar and reproduced elsewhere. What syncs: the search text, the filter, the sort column and direction, the current page, the page size, and any search fields values.

    Only state that differs from its initial/default value is written, so the URL stays clean — the default sort and direction, page 1, the default page size and an empty search/filter/fields are all omitted. Unrelated query parameters (for example utm_*) are left untouched. Updates use history.replaceState, so they never add browser-history entries.

    On load, the table seeds its state from the query string before the first request. A URL parameter is only adopted as a field value when a matching [name="…"] control exists in the table’s light DOM; anything else is left alone as an unrelated parameter. When combined with no-initial-load, a URL that carries relevant parameters forces the first load anyway, so a shared link never lands on an empty table.

    <zn-data-table
      sharable
      standalone
      caption="Users"
      data-uri="/api/users"
      headers='[
        {"key":"name","label":"Name", "sortable":true},
        {"key":"email","label":"Email", "sortable":true},
        {"key":"status","label":"Status", "sortable":true}
      ]'>
    
      <zn-data-table-search slot="search" placeholder="Search users..."></zn-data-table-search>
    
      <zn-data-table-filter
        slot="filter"
        default-filters="status"
        filters='[
          {"id":"status","name":"Status","options":{"active":"Active","inactive":"Inactive"},"operators":["eq"]}
        ]'>
      </zn-data-table-filter>
    
    </zn-data-table>
    

    Opening /users?search=acme&status=<encoded>&page=2 reproduces that exact search, filter and page; sorting a column or paging then rewrites the query in place.

    Standalone Mode

    Use standalone when the table supplies its own panel rather than sitting inside one. It renders a zn-panel, passing caption through as the panel’s caption, the header controls into its actions slot and the pagination into its footer slot, with the rows flush against the panel edges. Columns scroll under the panel’s edges, so the border stays put on a wide table.

    The panel footer is only slotted when there is pagination to show, so an empty table or one with hide-pagination gets no footer bar.

    Leave standalone off when the table is already inside a zn-panel.

    New Customer
    <zn-data-table
      data-uri="/data/data-table.json"
      method="GET"
      standalone
      caption="All Customers"
      headers='[
        {"key":"name","label":"Name"},
        {"key":"email","label":"Email"},
        {"key":"status","label":"Status"},
        {"key":"date","label":"Date Joined"},
        {"key":"phone","label":"Phone"},
        {"key":"address","label":"Address"},
        {"key":"notes","label":"Notes"}
      ]'>
    
      <zn-data-table-search slot="search" placeholder="Search"></zn-data-table-search>
    
      <zn-button slot="create-action" icon="add">New Customer</zn-button>
    
    </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.

    <zn-data-table
      data-uri="/data/data-table.json"
      method="GET"
      headers='[
        {"key":"name","label":"Name"},
        {"key":"email","label":"Email"}
      ]'>
    </zn-data-table>
    

    Response Errors

    Include an error object in the response to display a message inside the table, between the column headers and the first record, using the alert component. The error can be returned alongside row data — useful when results are valid but limited, or when a filter is invalid. The object supports text, an optional icon, and an optional level to control the alert level (defaults to error).

    <zn-data-table
      data-uri="/data/data-table-error.json"
      method="GET"
      headers='[
        {"key":"id","label":"ID"},
        {"key":"name","label":"Name"},
        {"key":"email","label":"Email"},
        {"key":"status","label":"Status"}
      ]'>
    </zn-data-table>
    

    If the response contains an error and no rows, the error is shown above the empty state.

    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 text
    • column: Column key this cell belongs to
    • style: Comma-separated styles (bold, italic, mono, code, border, center)
    • color: Text color
    • chipColor: Renders as a chip with specified color
    • uri: Makes cell content a link
    • target: Link target attribute
    • copyable: Adds a copy button
    • iconSrc: Icon to display with text
    • iconColor: Icon color
    • hoverContent: HTML content shown on hover
    • hoverPlacement: Hover tooltip placement
    • sortValue: 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 name the table. It renders as the title on the left of the header row, and supplies the wording for the default empty state.

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

    Delete Selected
    Refresh Data Select All
    <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-button slot="delete-action" color="error" icon="delete">Delete Selected</zn-button>
    </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();
      });
    </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,
      "error": {
        "text": "Optional message displayed below the column headers",
        "icon": "warning",
        "level": "warning"
      }
    }
    
    • error: Optional object displayed as an alert row below the column headers, alongside any returned rows
      • text: The message to display
      • icon: Optional icon shown in the alert
      • level: Optional alert level (primary, error, info, success, warning, note), defaults to error

    Request Format

    For POST requests, the table sends a JSON body:

    {
      "page": 1,
      "perPage": 10,
      "sortColumn": "name",
      "sortDirection": "asc",
      "filter": "",
      "search": "search term",
      "status": "open"
    }
    

    Field values from inputs slotted into a zn-data-table-search, and anything set on the table’s requestParams, are merged at the root of the body under their own name. The search text itself is sent as search.

    Parameters from the inputs slot are context/system values (a CSRF token, a package name, and the like) sent with every request. They are merged at the root too.

    Wrapped search fields

    Add wrap-search-fields to nest the search field values under a searchFields object instead, so a backend can bind them to a single map rather than arbitrary top-level keys:

    <zn-data-table wrap-search-fields data-uri="/data"></zn-data-table>
    
    {
      "page": 1,
      "perPage": 10,
      "sortColumn": "name",
      "sortDirection": "asc",
      "filter": "",
      "search": "search term",
      "searchFields": {
        "q": "search term",
        "status": "open"
      }
    }
    

    q mirrors the search text, which is still sent at the root. Empty values are dropped, and searchFields is null when nothing meaningful remains — no search text and no field values — so the backend can treat that as “no search”. Parameters from the inputs slot stay at the root either way.

    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.1.185/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.1.185/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, in the header’s right-hand group.
    sort Slot for sort component, in the header’s right-hand group.
    filter Slot for filter component, in the header’s right-hand group.
    filter-top Slot for a top-level filter component, rendered above the table’s panel.
    delete-action Slot for delete action button, shown in the header once rows are selected.
    modify-action Slot for modify action button, shown in the header once rows are selected.
    actions zn-button or zn-confirm elements listed in a header menu, enabled once rows are selected.
    create-action Slot for create action button, at the end of the header’s right-hand group.
    inputs Slot for additional input controls.
    empty-state Slot for custom empty state.
    no-results Slot for a custom no-results state, shown when a search on a no-initial-load table returns no rows.

    Learn more about using slots.

    Properties

    Name Description Reflects Type Default
    sharable When set, the table’s non-default state (search, filter, sort, page, per-page and field values) is mirrored to the URL query string and restored from it on load, so the view is shareable. boolean false
    wrapSearchFields
    wrap-search-fields
    When set, extra request params (search-component field values) are nested under a searchFields object - with q mirroring the search text - instead of being merged at the root of the request body. boolean false
    updateComplete A read-only promise that resolves when the component has finished updating.

    Learn more about attributes and properties.

    Methods

    Name Description Arguments
    selectAll() Selects every row on the page, or clears the selection when every row is already selected. -

    Learn more about methods.

    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-alert>
    • <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-panel>
    • <zn-skeleton>
    • <zn-slash-item>
    • <zn-slash-menu>
    • <zn-tooltip>