A versatile, interactive feature designed to manage, and visualize large amounts of information in a table format.
The q2-data-table
component is an incredibly powerful tool that generates an HTML table with the data that you provide. If you require extra control over specific cells, you can use a range of dynamically defined slots. These slots enable you to do things like:
Additionally, there are attributes and properties that allow you to alter the appearance and functionality of the table. For instance, you can:
Read on to discover all you can do!
The q2-data-table
has two different properties that you are responsible for providing data to. One is headers
, and the other is rows
. Below are type definitions of both.
The data you provide to the headers
property will be an array of objects with the following data structure.
interface Q2DataTableHeader {
title: string;
// Will be autogenerated from the title if not provided
// The key is used to grab the data from the row data
key?: string;
// 'auto' to use built-in sorting for this column
// 'manual' to implement your own sorting for this column
sortable?: 'auto' | 'manual';
// Indicates in what direction the data is sorted
sorted?: 'ASC' | 'DESC';
// Limits the number of rows that are displayed in a cell
// Content will be truncated if it exceeds the limit
lineClamp?: number;
// Defines alignment of the content within each cell in this column
// Defaults to 'center'
align?: 'start' | 'center' | 'end';
verticalAlign?: 'top' | 'bottom';
ariaLabel?: string;
// Defines the width of the column
width?: string;
// Defines the background of the column
backgroundColor?: string;
// Defines the content type for every cell in this column for styling puposes
type?: 'text' | 'number' | 'icon' | 'badge' | 'boolean' | 'code';
// When type = 'badge'
badgeStatus?: 'info' | 'alert' | 'warning' | 'success';
badgeTheme?: 'primary' | 'secondary' | 'tertiary';
}
Similarly, the data you pass to rows
is an array of objects with the following structure.
interface Q2DataTableRow {
id: string | number;
selected?: boolean;
expanded?: boolean;
disabled?: boolean;
cells: Record<string, string | number | Q2DataTableCell>
}
interface Q2DataTableCell {
value: string | number;
// Defines alignment of the content within this cell
// Takes priority over the column's `align` property when provided
// Defaults to 'center'
align?: 'start' | 'center' | 'end';
verticalAlign?: 'top' | 'bottom';
ariaLabel?: string;
// Defines the content type for this cell for styling purposes
// Takes priority over the column's `type` property when provided
type?: 'text' | 'number' | 'icon' | 'badge' | 'boolean' | 'code';
// Limits the number of rows that are displayed in a cell
// Content will be truncated if it exceeds the limit
lineClamp?: number;
// When type = 'badge'
badgeStatus?: 'info' | 'alert' | 'warning' | 'success';
badgeTheme?: 'primary' | 'secondary' | 'tertiary';
}
The cells
property is an object where each property key corresponds to a key
defined for one of the headers.
With that said, let's look at a sample set of data that you can provide to a q2-data-table
to be displayed.
const headerData = [
{
title: 'Day of Week',
key: 'day',
backgroundColor: 'var(--t-gray-14)',
},
{ title: 'Sales', key: 'sales', align: 'center' },
{ title: 'Revenue', key: 'revenue', align: 'center', sortable: true },
];
const rowData = [
{
id: 1,
cells: {
day: 'Monday',
sales: 93,
revenue: '$4,650',
},
},
{
id: 2,
cells: {
day: 'Tuesday',
sales: 127,
revenue: '$6,350',
},
},
{
id: 3,
cells: {
day: 'Wednesday',
sales: 121,
revenue: '$6,050',
},
},
{
id: 4,
cells: {
day: 'Thursday',
sales: 140,
revenue: '$7,000',
},
},
{
id: 5,
cells: {
day: 'Friday',
sales: 83,
revenue: '$4,150',
},
},
];
From here, you need to provide the q2-data-table
with this data:
const salesTable = document.querySelector('q2-data-table');
salesTable.headers = headerData;
salesTable.rows = rowData;
While q2-data-table
does a great job at displaying the data you need just by passing data into the component via properties, we understand that there will be times you want to customize the content. For this, we've exposed a series of dynamically named slots to allow you to do this.
In addition, by utilizing slots, you can further enhance your use of q2-data-table
to provide expandable content or dropdowns to display a list of options for each row.
header-cell-<key>
The <key>
identifies the column from the key
property in the headers
data.
With this slot, you can override the content of any header cell in the table. Using the header cell data from the Data Structure section above as reference, we use a dropdown as the "Day of Week" header.
<q2-data-table>
<q2-dropdown slot="header-cell-day" label="Day of Week" type="icon" icon="options">
<q2-dropdown-item value="Home">Home</q2-dropdown-item>
<q2-dropdown-item value="Download as PDF">Download as PDF</q2-dropdown-item>
<q2-dropdown-item value="Discombobulate">Discombobulate</q2-dropdown-item>
</q2-dropdown>
</q2-data-table>
row-<id>-cell-<key>
The <id>
corresponds to the id
property provided for each entry in the rows
property. Likewise, the <key>
identifies the cell/column from the key
property on each entry in the headers
data.
With this slot, you can override the content of any cell in any row of the table. Using the data from the Data Structure section above as a reference, we can replace the "Sales" cell on the row for "Thursday" with our own custom content:
<q2-data-table>
<div slot="row-4-cell-sales">🤯 Lots</div>
</q2-data-table>
row-<id>-dropdown
The <id>
corresponds to the id
property provided for each entry in the rows
property.
One typical behavior is to have each row of a table contain a dropdown that presents actions to a user that they can take on that particular row of data. Due to the implementation of q2-dropdown and its intricacies, we are also exposing this as a slot. Again using the data from the Data Structure section, we can add a dropdown to the row for "Thursday" like this:
<q2-data-table>
<q2-dropdown
slot="row-4-dropdown"
icon="options"
alignment="right"
>
<q2-dropdown-item value="second">Report</q2-dropdown-item>
<q2-dropdown-item value="third">Ask question</q2-dropdown-item>
</q2-dropdown>
</q2-data-table>
row-<id>-expandable-content
The <id>
corresponds to the id
property provided for each entry in the rows
property.
Another common desire is to have a table row be clickable, where upon clicking, it expands to reveal more detailed content. Because this often requires complex HTML and Javascript to display the desired results, we expose it as a slot that you can optionally utilize. The following example adds expandable content to the "Thursday" row:
But you already knew that.
<q2-data-table>
<div slot='row-4-expandable-content'>
<h3>Thursday Was Great</h3>
<p>But you already knew that.</p>
</div>
</q2-data-table>
empty-table
With this slot you can customize the look of your table's body when no row data is present. Alternatively, you may use the `emptyIcon` and `emptyMessage` properties to customize the empty state of the table with a `q2-icon` and custom text.
<q2-data-table>
<div slot="empty-table" style="display: flex; justify-content: center; align-items: center; gap: 10px;">
<q2-icon type="warning"></q2-icon>
<b>Table has no row data.</b>
</div>
</q2-data-table>
By default, if a column has sortable: 'auto'
set in the header
data, the component will do its best to sort the data you provide in the rows
property automatically. This works for most use cases you may have. However, a common use case is when you have multiple pages of content or need to provide a more detailed algorithm with which to sort your data.
For that, we recommend setting sortable: 'manual'
in the desired header data, and listening to the sort
event that is emitted from the component when you click on a sortable column header. Here is an example.
const dataTableElement = document.querySelector("q2-data-table")
function sortTransactions(event) {
// Calling preventDefault() will tell the Data Table
// NOT to perform the default sort functionality
event.preventDefault();
const {
direction,
header: { key },
} = event.detail;
dataTableElement.rows = [
...allTransactions.sort((a, b) => {
if (direction === 'ASC') return a.cells[key] > b.cells[key] ? 1 : -1;
else return a.cells[key] < b.cells[key] ? 1 : -1;
}),
]);
// You'll also want to update the headers to reflect which
// column was sorted and it's direction
dataTableElement.headers = allHeaders.map(header => (
{ ...header, sorted: header.key === key ? direction : undefined }))
);
}
tableElement.current?.addEventListener('sort', sortTransactions);
The q2-data-table
element has multiple slots that can be used to insert custom content into the component.
An optional slot to display custom content when the table is empty.
A slot for the content of any cell in the header of the table.
A slot for overriding the content of any cell in any row of the table with custom content.
A slot to provide a Dropdown for a row.
A slot that makes the row expandable and displays the provided content.
The q2-data-table
element has one or more properties that support text localization. Those properties are indicated by the localizable badge in the description.
bordered
Adds borders between rows and/or columns in the table.
caption
Provides a caption for the data table.
clickable
Adds the ability to click a row and have the table emit an event with the selected row's data.
density
Determines the amount of padding for each of the cells in the table.
emptyIcon
empty-icon
Determines the q2-icon
that will display when rows
has no value.
emptyMessage
empty-message
Determines the message that will display when rows
has no value.
headers
Defines the headers of the table.
Example:
element.headers = [
{
title: 'Day of the Week',
key: 'day',
},
{
title: 'Sales',
key: 'sales',
align: 'end',
}
]
hideCaption
hide-caption
Hides the caption from view, but still makes it available to screen readers for accessibility purposes.
hideClickable
hide-clickable
Visually hides the Select
button that displays when clickable=true
. It will still be discoverable by assistive technologies.
Use of this property requires clickable
to be set to true
.
loading
Displays a loading state on the table to indicate background activity.
rows
Defines the rows of the table.
Example:
element.rows = [
{
id: 1,
cells: {
day: 'Monday',
sales: 93
}
},
{
id: 2,
cells: {
day: 'Tuesday',
sales: 127
}
},
{
id: 3,
cells: {
day: 'Wednesday',
sales: 121
}
]
selectMode
select-mode
Determines if the selectable checkboxes allow for multi-select or not. If set to "single", once a row is selected, all other rows will be disabled.
See the documentation on the select
event for how to handle selections.
Use of this property requires selectable
to be set to true
.
selectable
Adds a checkbox to each row of the table making it selectable.
shadowed
Adds a shadow to the table
striped
Enables alternating background colors for the table rows
The q2-data-table
element exposes events that can be used to send and receive data from the component based on user interaction.
Emitted when a row is clicked.
Requires the clickable
prop to be set to true
.
Call event.preventDefault()
to prevent the default click behavior.
{ row: Q2DataTableSerializedRow; }
Emitted when a row is selected.
Requires the selectable
prop to be set to true
.
Call event.preventDefault()
to prevent the default selection behavior.
{ row: Q2DataTableSerializedRow; rows: Q2DataTableSerializedRow[]; allSelected: boolean; }
Emitted when the select-all checkbox is toggled.
Requires the selectable
prop to be set to true
and the selectMode
prop to be set to multiple
.
Call event.preventDefault()
to prevent the default behavior.
{ checked: boolean; }
Emitted when a column is sorted.
Requires the sortable
prop to be set to true
on the column.
Call event.preventDefault()
to prevent the default sorting behavior.
{ header: Q2DataTableHeader; direction: "ASC" | "DESC"; }
Emitted when an expandable row is toggled.
Requires content in the row-{id}-expandable-content
slot.
Call event.preventDefault()
to prevent the default toggling behavior.
{ row: Q2DataTableSerializedRow; }
The q2-data-table
element exposes methods that can be used to perform various actions on the component.
A method to click a row that accepts a row ID that is will be clicked.
clickRow(rowId: number | string) => Promise<void>
A method that returns the plain text value of a particular cell (including slot content).
getCellContent(rowId: number | string, columnKey: string) => Promise<string>
A method to sort a column that accepts a header object with key and sorted property.
sortColumn(header: Q2DataTableHeader) => Promise<void>
A method to toggle row expansion that accepts a row ID that will be clicked to expand or collapse the expandable content
toggleRowExpansion(rowId: number | string) => Promise<void>
A method to toggle row selection that accepts a row ID whose checkbox will be checked, if the feature is enabled.
toggleRowSelect(rowId: number | string) => Promise<void>
A method to toggle select all button (checkbox) on left top corner.
toggleSelectAllRows() => Promise<void>
Initial Release
Add boolean
cell type
Support for clickable rows, line-clamping cell content, and a code
cell type
Support for disabling the checkbox of a specific row
Support for a default empty state with optional slot for override
Support for custom header cells
Additional ways to customize borders
Support custom sorting algorithms for columns
The following CSS variables are available to override the default theme styles of the q2-data-table
component.
Many Tecton components consume other components to maintain visual and functional consistency. If you are looking for a CSS variable you think should exist but are not seeing it, it may be defined in one of the dependent components below. Either way, if you think it's something we should expose more conveniently, let us know!