Data Tables
UtilityA set of utility features for creating template-driven data tables.
Import
Types
Package
Source
Doc
WAI-ARIA
Examples
ID | User | Title | Body | ||
---|---|---|---|---|---|
1 | sunt aut facere repellat provident occaecati excepturi optio reprehenderit | quia et suscipit suscipit recusandae consequuntur expedita et cum reprehenderit molestiae ut ut quas totam nostrum rerum est autem sunt rem eveniet architecto | |||
2 | qui est esse | est rerum tempore vitae sequi sint nihil reprehenderit dolor beatae ea dolores neque fugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis qui aperiam non debitis possimus qui neque nisi nulla | |||
3 | ea molestias quasi exercitationem repellat qui ipsa sit aut | et iusto sed quo iure voluptatem occaecati omnis eligendi aut ad voluptatem doloribus vel accusantium quis pariatur molestiae porro eius odio et labore et velit aut | |||
4 | eum et est occaecati | ullam et saepe reiciendis voluptatem adipisci sit amet autem assumenda provident rerum culpa quis hic commodi nesciunt rem tenetur doloremque ipsam iure quis sunt voluptatem rerum illo velit | |||
5 | nesciunt quas odio | repudiandae veniam quaerat sunt sed alias aut fugiat sit autem sed est voluptatem omnis possimus esse voluptatibus quis est aut tenetur dolor neque |
Usage
What are Data Tables?
Within the context of Skeleton, data tables are not a singular feature, but rather a collection of utilities. These utilty features are opt-in, meaning you can progressively enhance any native HTML table to meet your requirements. This is one of the most complex features Skeleton provides, so please read carefully.
Getting Started
Let's start by importing all the utility features we'll need. We'll cover each of these in greater detail below.
import {
// Utilities
createDataTableStore,
dataTableHandler,
// Svelte Actions
tableInteraction,
tableA11y
} from '@skeletonlabs/skeleton';
We need data to populate the table. For simplicity, let's create this locally. In a real world app you might fetch this from an
external API. We demonstrate this in the example on this page. See the use of PageData
in the source.
const sourceData = [
{ position: 1, name: 'Hydrogen', weight: 1.0079, symbol: 'H' },
{ position: 2, name: 'Helium', weight: 4.0026, symbol: 'He' },
{ position: 3, name: 'Lithium', weight: 6.941, symbol: 'Li' },
{ position: 4, name: 'Beryllium', weight: 9.0122, symbol: 'Be' },
{ position: 5, name: 'Boron', weight: 10.811, symbol: 'B' },
{ position: 6, name: 'Carbon', weight: 12.0107, symbol: 'C' },
{ position: 7, name: 'Nitrogen', weight: 14.0067, symbol: 'N' },
{ position: 8, name: 'Oxygen', weight: 15.9994, symbol: 'O' },
{ position: 9, name: 'Fluorine', weight: 18.9984, symbol: 'F' },
{ position: 10, name: 'Neon', weight: 20.1797, symbol: 'Ne' }
];
We'll make use of Skeleton's table element classes to provide base styles to our native HTML table element. These are optional, but recommended.
<div class="table-container">
<table class="table table-hover">
<thead>
<tr>
<th>Heading 1</th>
</tr>
</thead>
<tbody>
<tr>
<td>Cell 1</td>
</tr>
</tbody>
</table>
</div>
Data Table Model
To unlock the power of our data tables, we'll need to create what we'll refer to as a data table model. Create a new Svelte
writable store with createDataTableStore
, then pass the model of our store to the dataTableHandler
method.
const dataTableStore = createDataTableStore(
// Pass your source data here:
sourceData,
// Provide optional settings:
{
// The current search term.
search: '',
// The current sort key.
sort: '',
// Paginator component settings.
pagination: { offset: 0, limit: 5, size: 0, amounts: [1, 2, 5, 10] }
}
);
// This automatically handles search, sort, etc when the model updates.
dataTableStore.subscribe((model) => dataTableHandler(model));
Next, we'll update our table markup to display our model data. Implement matching parent headings and body cells. We'll use an #each
loop to generate each table row. Note we use $dataTableStore.filtered
as our loop source. This represents the data as modified by search, sort, pagination, and more.
<thead>
<tr>
<th>Position</th>
<th>Name</th>
<!-- ... --->
</tr>
</thead>
<tbody>
{#each $dataTableStore.filtered as row, rowIndex}
<tr>
<td>{row.position}</td>
<td>{row.name}</td>
<!-- ... --->
</tr>
{/each}
</tbody>
Updating the Source
To update the content of the data table, just call the dataTableStore.updateSource()
method and pass in your new source
data.
dataTableStore.updateSource(newSourceData)
Search
To implement search, bind $dataTableStore.search
to any search input. You may add this anywhere as long as it has scope
of your table model (the store).
<input bind:value={$dataTableStore.search} type="search" placeholder="Search..." />
Sort
We'll use the dataTableStore.sort()
method to automatically set $dataTableStore.sort
when a table heading
is tapped. Add the following click method once to your table's thead
element.
<thead on:click={(e) => { dataTableStore.sort(e) }} on:keypress>
Add a data-sort="(key)"
attribute to each heading you wish to be sortable. Tapping a heading will set the
$dataTableStore.sort
value and update the UI. Tapping a heading repeatedly will toggle between ascending and descending sort order.
<th data-sort="position">Position</th>
<th data-sort="name">Name</th>
<!-- ... -->
While sort is working, there's currently no visual UI indicator. To handle this, implement the Svelte Action called tableInteraction
to your table element. This will toggle the appropriate CSS classes and show ↑ and ↓ sort arrows.
<table ... use:tableInteraction>
Selection
Per Row
To handle row selection, we'll add a new heading column. Keep the comment shown, as we'll replace it in a following step.
<th><!-- selection --></th>
Pair this with a matching table body cell that includes a checkbox input. Append bind:checked
to the input to extend
the row object source data. When checked on/off, the dataTableHandler
will automatically include/exclude the entire row
object in
$dataTableStore.selection
.
<td><input type="checkbox" bind:checked={row.dataTableChecked} /></td>
If you wish to visually highlight the row selection, Tailwind Elements includes a semantic class for this. Append this to your table body row element.
<tr class:table-row-checked={row.dataTableChecked}>
Pre-Selected
You may wish to pre-select certain table rows. We've provided a utility method to handle this. Pass in the key to query against, and a whitelist of values. Any object that matches the conditions will be selected. Trigger this multiple times for multiple selection queries.
// Selects all objects with a position value of 1 or 2:
dataTableStore.select('position', [1,2]);
Select All
If you wish to add a select all feature, replace <th><!-- selection --></th>
with the following.
<th><input type="checkbox" on:click={(e) => { dataTableStore.selectAll(e.currentTarget.checked) }} /></th>
Pagination
Please refer to the Paginators component to learn more about this feature. For data tables, use
$dataTableStore.pagination
to ensures the model updates reactively. The wrapping if statement is required.
{#if $dataTableStore.pagination}<Paginator bind:settings={$dataTableStore.pagination} />{/if}
Accessibility
Since data tables make use of native HTML table elements, you will need to implement accessibility features directly. However, we've
simplified this by providing a Svelte Action called tableA11y
. This implements the required event listeners for
keyboard interaction. Start by appending role and action to your table element.
<table ... role="grid" use:tableA11y>
Implement the aria-rowindex
attribute. This starts at 1 and increments per tr row. We can
utilize the #each loop index value, named rowIndex
.
<tr ... aria-rowindex={rowIndex + 1}>
Implement three attributes per table body td cell. role
and tabindex
are static, while
aria-colindex
starts at 1 and increments per cell.
<td ... role="gridcell" aria-colindex={1} tabindex="0">...</td>
<td ... role="gridcell" aria-colindex={2} tabindex="0">...</td>
<!-- ... -->
Reference the Keyboard tab section at the top of this page for a list of available keyboard interactions.
View Reference
If you wish to see a complete data table, we recommend tapping the Doc Source link at the top of this page. This will allow you to inspect how the featured example at the top of this page was constructed. This implements every available data table feature.
Table Components
Looking for a simpler data-driven table component? Visit the Table documentation.