Data Table

Updated:

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:

  • Customize the content of a cell
  • Add a dropdown menu to every row
  • Create content for an expandable row
  • Customize the content of an empty table

Additionally, there are attributes and properties that allow you to alter the appearance and functionality of the table. For instance, you can:

  • Display checkboxes for each row
  • Add a shadow to the table
  • Show a border between rows and/or columns

Read on to discover all you can do!

Data Structure

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.

Header Data Structure

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';
}

Row Data Structure

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.

Sample

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;

Slot Examples

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

Home Download as PDF Discombobulate
<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>


Cell Slots: 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:

🤯 Lots
<q2-data-table>
  <div slot="row-4-cell-sales">🤯 Lots</div>
</q2-data-table>

Dropdown cell: 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:

Report Ask question
<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>

Expandable Content Slot: 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:

Thursday Was Great

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

Table has no row data.
<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>

Sorting

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);

Slots

The q2-data-table element has multiple slots that can be used to insert custom content into the component.

Learn more about slots

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.

Properties

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.

Learn more about properties.

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.

Localizable
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

Events

The q2-data-table element exposes events that can be used to send and receive data from the component based on user interaction.

Learn more about events.

click

Emitted when a row is clicked.

Requires the clickable prop to be set to true.

Call event.preventDefault() to prevent the default click behavior.

Event Detail Type signature

{ row: Q2DataTableSerializedRow; }

select

Emitted when a row is selected.

Requires the selectable prop to be set to true.

Call event.preventDefault() to prevent the default selection behavior.

Event Detail Type signature

{ row: Q2DataTableSerializedRow; rows: Q2DataTableSerializedRow[]; allSelected: boolean; }

selectAllRows

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.

Event Detail Type signature

{ checked: boolean; }

sort

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.

Event Detail Type signature

{ header: Q2DataTableHeader; direction: "ASC" | "DESC"; }

toggle

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.

Event Detail Type signature

{ row: Q2DataTableSerializedRow; }

Methods

The q2-data-table element exposes methods that can be used to perform various actions on the component.

Learn more about methods.

clickRow

Test only

A method to click a row that accepts a row ID that is will be clicked.

Type signature

clickRow(rowId: number | string) => Promise<void>

getCellContent

Test only

A method that returns the plain text value of a particular cell (including slot content).

Type signature

getCellContent(rowId: number | string, columnKey: string) => Promise<string>

sortColumn

Test only

A method to sort a column that accepts a header object with key and sorted property.

Type signature

sortColumn(header: Q2DataTableHeader) => Promise<void>

toggleRowExpansion

Test only

A method to toggle row expansion that accepts a row ID that will be clicked to expand or collapse the expandable content

Type signature

toggleRowExpansion(rowId: number | string) => Promise<void>

toggleRowSelect

Test only

A method to toggle row selection that accepts a row ID whose checkbox will be checked, if the feature is enabled.

Type signature

toggleRowSelect(rowId: number | string) => Promise<void>

toggleSelectAllRows

Test only

A method to toggle select all button (checkbox) on left top corner.

Type signature

toggleSelectAllRows() => Promise<void>

Release Notes

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

Accessibility Report

Tecton components are designed and tested to be WCAG compliant when used appropriately, and do not get released without proper validation. Developers should prefer not to set ARIA attributes when using components from the Tecton Design System.

The following CSS variables are available to override the default theme styles of the q2-data-tablecomponent.

Dependencies

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!

  • q2-badge
  • q2-icon
  • q2-checkbox
  • q2-btn
  • q2-loading