GC Design System Components
GC Design System Start to use Page templates overview Basic page Components overview Alert Breadcrumbs Button Card Checkboxes Container Date input Date modified Details Error message Error summary Fieldset File uploader Footer Grid Header Heading Icon Input Language toggle Link Notice Pagination Radios Screenreader-only Search Select Side navigation Signature Stepper Table Text Textarea Theme and topic menu Top navigation CSS shortcuts overview Reset styles Responsive layout State Box sizing Container sizing Display Overflow Position Visibility Font Font family Font size Font style Font weight Line height Link colour Link size Link text decoration List style Text align Text colour Text overflow Text transform Word break Margin Padding Align content Align items Align self Flex Flex direction Flex grow Flex shrink Flex wrap Gap Grid columns Grid rows Justify content Justify items Justify self Order Place content Place items Place self Background colour Border colour Border radius Border style Border width Icon names Icon size Image Cursor Pointer events Transition Styles overview Design tokens Colour tokens Spacing tokens Typography tokens Contact us Get involved Find a demo

Table
<gcds-table>

Also called: data table, data grid.

A table is a structured layout of related data in rows and columns.

Table component preview

On this page

Coding and accessibility for tables

Use the correct component name

  • Use gcds-table in HTML, Vue, or React.
  • Use gcds-table-ng in Angular.

Define your columns and data

To build a table, you need at minimum to define the columns and the data.

  • Use the columns attribute to define the table’s columns and their behaviour.
  • Use the data attribute 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 sort to true to 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 sortDirection property in the relevant column object.

Add pagination for managing large datasets

  • Set pagination to true to split data into pages.
  • Adjust pagination-size-options to control how many rows are shown per page.

Examples Explore the different ways you can configure the component. Each example shows a working implementation and ready-to-copy code.

In this section

Optional attributes These attributes allow you to customize or extend the component’s behaviour and presentation.

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: Use alignment to control how the content inside the column cells is positioned horizontally. Set to start to align content to the left, center to align it to the middle, or end to align it to the right.
  • field: Use field to 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: Use header to set the column heading that appears at the top of the column.
  • rowHeader: Set rowHeader to true if you want to mark each cell in the column as a row header. Row headers label what each row is about.
  • slotted: Set slotted to true to flag that the cell will render custom content. To see how each framework handles this, go to Framework-specific slots for custom content.
  • sort: Set sort to true to allow people to sort the table by that column.
  • sortDirection: Use sortDirection to set a default sort order for the column when the page loads. Set to asc for ascending order or desc for 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>

Slots The default slot allows you to inject custom content into the component’s primary content area, and named slots, into specific areas.

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.

  1. Explore by choosing different code values to generate the instance you want.

  2. Get the code and pull it into your environment.

  3. 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 account. You'll have access to the team's direct responses, progress made on your issue, and issues raised by others.

Give feedback Report an issue on GitHub
2026-06-01