Table
Tables display sets of data in sortable, filterable, selectable rows and columns, configured through data and column definitions.
| Name | Role | Status |
|---|---|---|
| Ada Lovelace | Engineer | Active |
| Grace Hopper | Admiral | Active |
| Alan Turing | Researcher | Away |
Usage
forge-table renders rows and columns from two JS properties — data (an array of row objects) and columnConfigurations (column definitions) — rather than static HTML attributes, plus select/multiselect, filter, dense/roomy, resizable, and fixedHeaders. It’s a basic data table, not a fully-featured grid — use it when content has three or more well-defined, sortable dimensions and users need to compare across rows. For content that’s primarily scanned rather than compared, or that’s mostly viewed on mobile, use a list instead. And if you need virtual or infinite scrolling, or more advanced filtering than a single input per column, reach for a dedicated grid library like AG Grid instead — forge-table intentionally stays basic.
Rules
Basic usage
Set data and columnConfigurations as JS properties to populate the table — they can’t be expressed as static HTML attributes, so explore the live behavior in the Storybook playground above. The markup below shows the table’s underlying structure using the plain, CSS-only escape hatch instead of the full component.
The table's row/column structure, shown with the CSS-only markup fallback.
<table class="forge-data-table">
<thead>
<tr>
<th>
Column 1
</th>
<th>
Column 2
</th>
<th>
Column 3
</th>
<th>
Column 4
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
Row 1, Col 1
</td>
<td>
Row 1, Col 2
</td>
<td>
Row 1, Col 3
</td>
<td>
Row 1, Col 4
</td>
</tr>
<tr>
<td>
Row 2, Col 1
</td>
<td>
Row 2, Col 2
</td>
<td>
Row 2, Col 3
</td>
<td>
Row 2, Col 4
</td>
</tr>
<tr>
<td>
Row 3, Col 1
</td>
<td>
Row 3, Col 2
</td>
<td>
Row 3, Col 3
</td>
<td>
Row 3, Col 4
</td>
</tr>
</tbody>
</table>Inside a card
Place a table in a forge-card no-padding with a forge-scaffold, so it runs edge to edge. Put the table title and icon actions (filter, export, more) in the header toolbar, and a forge-paginator in an inverted footer toolbar. The primary page action, like “New order”, goes in the page’s body header, not the card.
<forge-card no-padding>
<forge-scaffold>
<forge-toolbar slot="header">
<h3 slot="start" class="forge-typography--heading3">Orders</h3>
<forge-icon-button slot="end" density="medium" aria-label="Filter orders">
<forge-icon name="filter_list"></forge-icon>
</forge-icon-button>
</forge-toolbar>
<forge-table slot="body"></forge-table>
<forge-toolbar slot="footer" inverted>
<forge-paginator slot="end"></forge-paginator>
</forge-toolbar>
</forge-scaffold>
</forge-card>
Configuring columns
Each entry in columnConfigurations describes one column: header (and optional footer) text, the property to read from each row in data, and whether it’s sortable (with initialSort marking the column sorted by default) or filter-able.
import type { IColumnConfiguration } from "@tylertech/forge";
const columnConfigurations: IColumnConfiguration[] = [
{ header: "First name", property: "firstName", sortable: true, initialSort: true },
{ header: "Last name", property: "lastName", sortable: true },
{ header: "Age", property: "age", sortable: true },
];
tableEl.columnConfigurations = columnConfigurations;
tableEl.data = data;
Column filters
Set filter: true on a column and give it a filterDelegate to render a filter input in the header. Use the built-in TextFieldComponentDelegate or SelectComponentDelegate for common input types, or build a custom delegate by extending BaseComponentDelegate or FormFieldComponentDelegate — either way, the delegate is a consistent interface for getting/setting a value and toggling invalid/disabled/required on whatever component it wraps.
import { TextFieldComponentDelegate, SelectComponentDelegate } from "@tylertech/forge";
table.columnConfigurations = [
{
property: "name",
header: "Name",
filter: true,
filterDelegate: () => new TextFieldComponentDelegate({ options: { placeholder: "Filter name..." } }),
},
{
property: "color",
header: "Favorite color",
filter: true,
filterDelegate: () => new SelectComponentDelegate({ props: { placeholder: "Filter color..." } }),
},
];
Footer row
Set includeFooter to add a footer row, then give each column either a static footer string or a footerTemplate callback for custom content, like a computed average. Style footer cells individually via footerCellStyle.
tableEl.includeFooter = true;
tableEl.columnConfigurations = [
{ header: "First name", property: "firstName", footer: "Total" },
{
header: "Age",
property: "age",
footerTemplate: () => {
const span = document.createElement("span");
span.textContent = `Avg: ${average}`;
return span;
},
},
];
Transforming values
Use a column’s transform callback to map a raw value to display text — a boolean to “Enabled”/“Disabled”, for example — without changing the underlying data.
{
property: "active",
header: "Status",
transform: (value) => (value ? "Enabled" : "Disabled"),
}Tables are used to display sets of data. They organize information into rows and columns, making it easier to read, compare, and analyze. The Forge table provides a configuration-based approach to building data tables with means for sorting, filtering, selecting, and customizing the display of tabular data.
import "@tylertech/forge/table";| Property | Attribute | Type | Default | Description |
|---|---|---|---|---|
data | — | any[] | [] | The data to be display in the table body. |
columnConfigurations | — | IColumnConfiguration[] | [] | The column configuration options. |
select | select | boolean | false | Controls the visibility of the select column. |
multiselect | multiselect | boolean | true | Controls the visibility of the select all checkbox (only applied when `select` is `true`). |
selectKey | select-key | string | string[] | — | The row key for matching data to selections. |
tooltipSelect | tooltip-select | string | TableSelectTooltipCallback | — | The tooltip to display when hovering over the select column. |
tooltipSelectAll | tooltip-select-all | string | — | The tooltip to display when hovering over the select all checkbox. |
dense | dense | boolean | false | Controls whether the table is dense or not. |
roomy | roomy | boolean | false | Controls whether the table is roomy or not. |
filter | filter | boolean | false | Controls whether the table shows its column filter row. |
fixedHeaders | fixed-headers | boolean | false | Controls whether the table applies fixed headers when in scroll containers. |
layoutType | layout-type | TableLayoutType | 'auto' | Controls the table layout algorithm. |
wrapContent | wrap-content | boolean | true | Controls whether the content in each cell wraps or not (true by default). |
includeFooter | include-footer | boolean | false | Controls whether to render a table footer. |
resizable | resizable | boolean | false | Controls whether the columns are resizable or not. |
minResizeWidth | min-resize-width | number | 100 | Gets/sets the minimum width that a column can be resized to by the user dragging the resize handle. |
allowRowClick | allow-row-click | boolean | false | Gets/sets whether the rows respond to (and emit) row click events. |
multiColumnSort | multi-column-sort | boolean | false | Gets/sets whether the table supports multi-column sorting. |
rowCreated | — | TableRowCreatedCallback | — | Callback for when a row is clicked. This allows for custom logic to run after each `<tr>` is created. |
cellCreated | — | TableCellCreatedCallback | — | Callback for when a cell is clicked. This allows for custom logic to run after each `<td>` is created. |
selectAllTemplate | — | TableHeaderSelectAllTemplate | — | The template to use for the select all checkbox in the header. |
selectCheckboxAlignment | select-checkbox-alignment | `${CellAlign}` | "center" | Controls the alignment of the select checkbox. |
| Name | Type | Description |
|---|---|---|
forge-table-row-click | CustomEvent<ITableRowClickEventData> | Dispatched when a row is clicked. Only applies when `allow-row-click` is specified. |
forge-table-select | CustomEvent<ITableSelectEventData> | Dispatched when a row is selected. Only applies when `select` is specified. |
forge-table-select-double | CustomEvent<ITableSelectDoubleEventData> | Dispatched when a row is double-clicked. Only applies when `select` is specified. |
forge-table-select-all | CustomEvent<ITableSelectAllEventData> | Dispatched when the select all checkbox is toggled. Only applies when `select` and `multiselect` is specified. |
forge-table-sort | CustomEvent<ITableSortEventData | ITableSortMultipleEventData> | Dispatched when a column is sorted. |
forge-table-filter | CustomEvent<ITableFilterEventData> | Dispatched when a column is filtered. Only applies when `filter` is specified. |
forge-table-initialized | CustomEvent<void> | Dispatched when the table is initialized in the DOM for the first time. |
forge-table-column-resize | CustomEvent<ITableColumnResizeEventData> | Dispatched when a column is resized. |
forge-table-before-body-rendered | CustomEvent<void> | Dispatched before the table body is rendered. |
forge-table-body-rendered | CustomEvent<void> | Dispatched when the table body is rendered. |
| Name | Returns | Description |
|---|---|---|
hideColumn(columnIndex) | void | Hides a column from the table. |
showColumn(columnIndex) | void | Shows a hidden column in th table. |
isColumnHidden(columnIndex) | boolean | Determines if a column at the given index is hidden or not. |
getSelectedRows() | any[] | Returns the selected row instances. |
selectRow(data) | void | Selects a row in the table. Only applicable if `select` is true. |
selectRows(data, preserveExisting) | void | Selects one or more rows in the table. Only applicable if `select` is true. |
deselectRow(data) | void | Deselects a single row in the table. |
deselectRows(data) | void | Deselects one or more rows in the table. |
clearSelections() | void | Clears all selected table rows. |
render() | void | Forces the table to re-render based on its current configuration. |
expandRow(rowIndex, template) | Promise<void> | Expands a collapsed row. |
collapseRow(rowIndex) | Promise<void> | Collapses an expanded row. |
isRowExpanded(rowIndex) | boolean | Checks if a row is expanded or not. |
selectRowsByIndex(indexes, preserveExisting) | void | Selects a rows by an index or array of indexes. |
deselectRowsByIndex(indexes) | void | Deselects a rows by an index or array of indexes. |
isRowSelected(rowData) | boolean | Checks if a row is selected or not. |
Don’t use a table for layout
Reserve forge-table for actual tabular data — using it to lay out unrelated content makes the page harder to parse for screen reader users, who rely on table semantics to mean an actual data grid.
Row selection
The selection checkbox in each row automatically receives an aria-label="Select row", so no extra labeling is needed there.
Interactive cell content
If a column renders an interactive control (a button, a link, a form field), make sure it’s reachable and operable by keyboard, the same as it would be with a mouse.