Table
<gcds-table>
Also called: data table, data grid.
A table is a structured layout of related data in rows and columns.
-
GitHub -
Figma
Table component preview
On this page
Coding and accessibility for tables
Use the correct component name
- Use
gcds-tablein HTML, Vue, or React. - Use
gcds-table-ngin Angular.
Define your columns and data
To build a table, you need at minimum to define the columns and the data.
- Use the
columnsattribute to define the table’s columns and their behaviour. - Use the
dataattribute to populate the table with content.
Provide an accessible caption
Use the caption slot to give an accessible name to the table, so that assistive technologies can identify it and announce it.
Add filtering for narrowing results
Set filter to true to allow filtering, so people can narrow down results by keyword.
Add sorting for reordering data
- Set
sorttotrueto allow people to sort the table by column, so they can reorganize data by priority, recency, or magnitude, for example. - If the table has a default sort order that reflects how people are most likely to first read the data, set it using the
sortDirectionproperty in the relevant column object.
Add pagination for managing large datasets
- Set
paginationto true to split data into pages. - Adjust
pagination-size-optionsto control how many rows are shown per page.
In this section
columns
Use the columns attribute to define the columns of the table. Pass an array of objects, where each object defines a column and controls how it looks and behaves.
Each column object takes the following properties:
alignment: Usealignmentto control how the content inside the column cells is positioned horizontally. Set tostartto align content to the left,centerto align it to the middle, orendto align it to the right.field: Usefieldto define the unique id that connects the column to the correct data. The value must match the key used for that data in your data object.header: Useheaderto set the column heading that appears at the top of the column.rowHeader: SetrowHeadertotrueif you want to mark each cell in the column as a row header. Row headers label what each row is about.slotted: Setslottedtotrueto flag that the cell will render custom content. To see how each framework handles this, go to Framework-specific slots for custom content.sort: Setsorttotrueto allow people to sort the table by that column.sortDirection: UsesortDirectionto set a default sort order for the column when the page loads. Set toascfor ascending order ordescfor descending order.
data
Use data to pass the content of the table. Pass an array of objects where each object represents one row, and each key matches a column field.
<gcds-table
columns='[
{
"field": "submission_id",
"header": "ID",
"rowHeader": true
},
{
"field": "submitter_name",
"header": "Name"
},
{
"field": "date_submitted",
"header": "Date Submitted"
},
{
"field": "assigned_reviewer",
"header": "Reviewer"
}
]'
data='[
{
"submission_id": "EXP-2026-001",
"submitter_name": "John A. Smith",
"date_submitted": "2026-01-15 4:30",
"assigned_reviewer": "Sarah Chen"
},
{
"submission_id": "EXP-2026-002",
"submitter_name": "Maria Gonzalez",
"date_submitted": "2026-01-15 5:15",
"assigned_reviewer": "David Patel"
},
{
"submission_id": "EXP-2026-003",
"submitter_name": "Robert James",
"date_submitted": "2026-01-15 6:22",
"assigned_reviewer": "Lisa Wong"
},
{
"submission_id": "EXP-2026-004",
"submitter_name": "Emily R. Davis",
"date_submitted": "2026-01-15 8:45",
"assigned_reviewer": "Michael Tran"
},
{
"submission_id": "EXP-2026-005",
"submitter_name": "Ahmed Khalil",
"date_submitted": "2026-01-15 9:20",
"assigned_reviewer": "Sarah Chen"
}
]'
></gcds-table>
filter
Set filter to true to display a filter input, so people can narrow down results by keyword.
<gcds-table filter></gcds-table>
filter-value
Use filter-value to set a default keyword in the filter input, so some rows are already filtered when the table loads. By default, there’s no set value.
<gcds-table filter filter-value="Dav"></gcds-table>
pagination
Set pagination to true to split the table into pages when there are many rows. By default, pagination is set to false.
<gcds-table pagination></gcds-table>
pagination-current-page
Use pagination-current-page to set which page is displayed when the table first loads. By default, it’s set to 1, which shows the first page.
<gcds-table pagination pagination-current-page="2"
></gcds-table>
pagination-size
Use pagination-size to set how many rows are displayed per page. The default is 10.
<gcds-table pagination pagination-size="10"
></gcds-table>
pagination-size-options
Use pagination-size-options to define the page size choices available to people in the row control. The default options are [10, 25, 50, 0].
Note: Including 0 in the options adds an “All” choice that displays all rows at once. Use with caution on large datasets, as it may affect performance.
<gcds-table pagination pagination-size-options="[10, 15, 20, 25, 0]"></gcds-table>
sort
Set sort to true to allow users to sort the table by clicking on column headers. Set to false to disable sorting across all columns. By default, sort is set to false.
Note: The sort property in each column object has the final say. If a column sets sort to false, that column will not be sortable even if the table-level sort is set to true.
<gcds-table sort></gcds-table>
caption
Use the caption slot to give an accessible name to the table, so that assistive technologies can identify it and announce it.
<gcds-table>
<div slot="caption">
<h5>Table caption</h5>
<p>Detailed caption for the table</p>
</div>
</gcds-table>
Framework-specific slots for custom content
Use custom cell content when you need something more than plain text in a cell, like a link, image, or button. To enable custom content for a column, set slotted to true in your column object.
Each framework handles custom cell content differently. HTML, Vue, and Angular use slots or directives, while React uses the renderCell property.
Use the cell:<field> slot to define custom content for a specific column. Replace <field> with the field name you set in the column object.
Use data-bind-* to pass a row value directly into an attribute.
Use data-bind-template-* when you need to insert a row value inside a string before assigning it to an attribute. For example, use it to build an image’s alt and src attributes.
If interactive elements need to use the row data in their functions, you can use the properties of row, rowIndex, column and value through this.
<gcds-table
columns='[
...,
{
field: "submission_id",
header: "ID",
slotted: true,
},
{
field: "actions",
header: "Actions",
slotted: true,
},
...,
];'
>
<template slot="cell:submission_id">
<a
data-bind-template-href="/view_submission/{submission_id}"
data-bind="submission_id"
></a>
</template>
<template slot="cell:actions">
<gcds-button
button-role="secondary"
size="small"
onclick="console.log(this.row, this.rowIndex, this.column, this.value)"
>
Console log row data
</gcds-button>
</template>
</gcds-table>
Use the #<field> slot to define custom content for a specific column. Replace <field> with the field name you set in the column object.
Use { row } to access row data inside the slot.
<GcdsTable
:columns="[
...,
{
field: 'submission_id',
header: 'ID',
slotted: true,
},
{
field: 'actions',
header: 'Actions',
slotted: true,
},
]"
>
<template #submission_id="{ row }">
<a
:href="`/view_submission/${row.submission_id}`"
>
{{ row.submission_id }}
</a>
</template>
<template #actions="{ row, rowIndex, column, value }">
<gcds-button
button-role="secondary"
size="small"
@click="() => {
console.log(row, rowIndex, column, value);
}"
>
Console log row data
</gcds-button>
</template>
</GcdsTable>
Use the gcdsCell=”<field>” directive to assign custom cell content to the correct column.
If interactive elements need to use the row data in their functions, you can use the properties of row, rowIndex, column and value through let-*.
<gcds-table-ng
[columns]="[
...,
{
field: 'submission_id',
header: 'ID',
slotted: true,
},
{
field: 'actions',
header: 'Actions',
slotted: true,
},
]"
>
<ng-template gcdsCell="submission_id" let-row>
<a
[href]="'/view_submission/' + row.submission_id"
>
{{ row.submission_id }}
</a>
</ng-template>
<ng-template
gcdsCell="actions"
let-row
let-rowIndex="rowIndex"
let-column="column"
let-value="value"
>
<gcds-button
button-role="secondary"
(click)="logRow(row, rowIndex, column, value)"
>
Console log row data
</gcds-button>
</ng-template>
</gcds-table-ng>
Use the renderCell property to define the content to render in the cell. Unlike the other frameworks, React uses a renderCell property instead of slots. This property extends the column object with a function that returns what to display.
<GcdsTable
columns={[
...,
{
field: 'submission_id',
header: 'ID',
slotted: true,
renderCell: ({ row }) => {
return (
<a
href={`/view_submission/${row.submission_id}`}
>
{{ row.submission_id }}
</a>
);
},
},
{
field: 'actions',
header: 'Actions',
slotted: true,
renderCell: ({ row, rowIndex, column, value }) => {
return (
<GcdsButton
buttonRole="secondary"
size="small"
onClick={() => console.log(row, rowIndex, column, value)}
>
Console log row data
</GcdsButton>
)
}
},
]}
>
</GcdsTable>
Code builder
Generate an instance of the component you need by selecting its code properties.
-
Explore by choosing different code values to generate the instance you want.
-
Get the code and pull it into your environment.
-
Add any copy you need to the component (like text for a label).
Note: The code builder uses English for all code elements, which follows standard practice.
Help us improve
Have questions or a request? Give feedback on our contact form.
Something's wrong? Raise it through GitHub with an