Agriculture Design System
Beta
Design System for the Export Service

Table

Tables help make complex information easier to scan and compare. Use tables for exact values or information that would be hard to read in body text.

View in FigmaView in StorybookView in Github
import { ... } from '@ag.ds-next/react/table';
Open in Playroom, opens in a new tab
<TableWrapper>
	<Table>
		<TableCaption>
			Population of Australian states and territories, December 2015
		</TableCaption>
		<TableHead>
			<TableRow>
				<TableHeader scope="col">Location</TableHeader>
				<TableHeader textAlign="right" scope="col">
					Population
				</TableHeader>
				<TableHeader textAlign="right" scope="col">
					Change over previous year %
				</TableHeader>
				<TableHeader textAlign="right" scope="col">
					Change over previous decade %
				</TableHeader>
			</TableRow>
		</TableHead>
		<TableBody>
			<TableRow>
				<TableCell>New South Wales</TableCell>
				<TableCell textAlign="right">7,670,700</TableCell>
				<TableCell textAlign="right">3.1%</TableCell>
				<TableCell textAlign="right">12.9%</TableCell>
			</TableRow>
			<TableRow>
				<TableCell>Victoria</TableCell>
				<TableCell textAlign="right">5,996,400</TableCell>
				<TableCell textAlign="right">2.5%</TableCell>
				<TableCell textAlign="right">9.3%</TableCell>
			</TableRow>
			<TableRow>
				<TableCell>Queensland</TableCell>
				<TableCell textAlign="right">4,808,800</TableCell>
				<TableCell textAlign="right">1.7%</TableCell>
				<TableCell textAlign="right">13.3%</TableCell>
			</TableRow>
			<TableRow>
				<TableCell>Western Australia</TableCell>
				<TableCell textAlign="right">2,603,900</TableCell>
				<TableCell textAlign="right">2.3%</TableCell>
				<TableCell textAlign="right">11.6%</TableCell>
			</TableRow>
			<TableRow>
				<TableCell>South Australia</TableCell>
				<TableCell textAlign="right">1,702,800</TableCell>
				<TableCell textAlign="right">2.0%</TableCell>
				<TableCell textAlign="right">6.8%</TableCell>
			</TableRow>
			<TableRow>
				<TableCell>Tasmania</TableCell>
				<TableCell textAlign="right">517,400</TableCell>
				<TableCell textAlign="right">4%</TableCell>
				<TableCell textAlign="right">5.3%</TableCell>
			</TableRow>
			<TableRow>
				<TableCell>Northern Territory</TableCell>
				<TableCell textAlign="right">244,400</TableCell>
				<TableCell textAlign="right">1.2%</TableCell>
				<TableCell textAlign="right">4.5%</TableCell>
			</TableRow>
			<TableRow>
				<TableCell>Australian Capital Territory</TableCell>
				<TableCell textAlign="right">393,000</TableCell>
				<TableCell textAlign="right">2.4%</TableCell>
				<TableCell textAlign="right">9.6%</TableCell>
			</TableRow>
		</TableBody>
	</Table>
</TableWrapper>

Tables are used to scan for information and compare values. They are useful for displaying exact values or information that would be hard to read in body text.

For data tables with a small amount of rows, use the default table. Align text columns and corresponding data cells to the left. When comparing numbers in a column, align data cells and column headers to the right.

Do

  • use for datasets with more than 2 columns
  • use for tabular data - not layouts
  • provide a meaningful caption (heading), or use aria-labelledby to reference a heading
  • keep row heights small
  • use a simple table structure - complex tables are difficult to navigate
  • avoid complex tables by splitting the data into simple, seperate tables
  • avoid empty table headers
  • use Pagination to break up tables with many rows
  • align text left and numeric data right
  • only include text, tags, links, actions and status badges as content
  • only use dropdown menu if you require three or more actions in a table cell
  • always use a label on the dropdown menu button
  • use a human readable format for numeric data – for example, 1,234,000 instead of 12340000
  • allow row sorting by using TableHeaderSortable.

Don’t

  • repeat information across cells. If each cell has the same content, add it as the column header – for example, Width (cm)
  • use if a list, paragraph of text or diagram will work
  • use to summarise form collection data - use a Summary list
  • add lists, diagrams or images
  • use a combination of actions in table cells and actions in dropdown menus together in the same table row
  • put form inputs in table cells - use an action in a cell to open a drawer or navigate to another page instead
  • have too many rows. Use pagination or start another table where logical – for example, an alphabetical list, Table 1: A to D, Table 2: E to H and so on
  • use bespoke styling – follow consistent layouts and styles
  • nest tables inside tables
  • use inside an accordion
  • use empty table headers unless spanning multiple columns and a header isn’t appropriate
  • set a row as invalid without adding a section alert.

Striped

Use zebra stripes for tables with complex information:

  • 4 or more rows
  • 3 or more columns
  • comparing important or similar information.

You can enable zebra stripes by applying the striped prop.

<TableWrapper>
	<Table striped>
		<TableCaption>
			Population of Australian states and territories, December 2016
		</TableCaption>
		<TableHead>
			<TableRow>
				<TableHeader scope="col">Location</TableHeader>
				<TableHeader textAlign="right" scope="col">
					Population
				</TableHeader>
				<TableHeader textAlign="right" scope="col">
					Change over previous year %
				</TableHeader>
				<TableHeader textAlign="right" scope="col">
					Change over previous decade %
				</TableHeader>
			</TableRow>
		</TableHead>
		<TableBody>
			<TableRow>
				<TableCell>New South Wales</TableCell>
				<TableCell textAlign="right">7,670,700</TableCell>
				<TableCell textAlign="right">3.1%</TableCell>
				<TableCell textAlign="right">12.9%</TableCell>
			</TableRow>
			<TableRow>
				<TableCell>Victoria</TableCell>
				<TableCell textAlign="right">5,996,400</TableCell>
				<TableCell textAlign="right">2.5%</TableCell>
				<TableCell textAlign="right">9.3%</TableCell>
			</TableRow>
			<TableRow>
				<TableCell>Queensland</TableCell>
				<TableCell textAlign="right">4,808,800</TableCell>
				<TableCell textAlign="right">1.7%</TableCell>
				<TableCell textAlign="right">13.3%</TableCell>
			</TableRow>
			<TableRow>
				<TableCell>Western Australia</TableCell>
				<TableCell textAlign="right">2,603,900</TableCell>
				<TableCell textAlign="right">2.3%</TableCell>
				<TableCell textAlign="right">11.6%</TableCell>
			</TableRow>
			<TableRow>
				<TableCell>South Australia</TableCell>
				<TableCell textAlign="right">1,702,800</TableCell>
				<TableCell textAlign="right">2.0%</TableCell>
				<TableCell textAlign="right">6.8%</TableCell>
			</TableRow>
			<TableRow>
				<TableCell>Tasmania</TableCell>
				<TableCell textAlign="right">517,400</TableCell>
				<TableCell textAlign="right">4%</TableCell>
				<TableCell textAlign="right">5.3%</TableCell>
			</TableRow>
			<TableRow>
				<TableCell>Northern Territory</TableCell>
				<TableCell textAlign="right">244,400</TableCell>
				<TableCell textAlign="right">1.2%</TableCell>
				<TableCell textAlign="right">4.5%</TableCell>
			</TableRow>
			<TableRow>
				<TableCell>Australian Capital Territory</TableCell>
				<TableCell textAlign="right">393,000</TableCell>
				<TableCell textAlign="right">2.4%</TableCell>
				<TableCell textAlign="right">9.6%</TableCell>
			</TableRow>
		</TableBody>
	</Table>
</TableWrapper>

Custom column width

You can use custom widths based on the expected length of the data under each corresponding column.

<TableWrapper>
	<Table striped>
		<TableCaption>
			Population of Australian states and territories, December 2017
		</TableCaption>
		<TableHead>
			<TableRow>
				<TableHeader scope="col" width="50%">
					Location
				</TableHeader>
				<TableHeader textAlign="right" scope="col">
					Population
				</TableHeader>
				<TableHeader textAlign="right" scope="col">
					Change over previous year %
				</TableHeader>
				<TableHeader textAlign="right" scope="col">
					Change over previous decade %
				</TableHeader>
			</TableRow>
		</TableHead>
		<TableBody>
			<TableRow>
				<TableCell>New South Wales</TableCell>
				<TableCell textAlign="right">7,670,700</TableCell>
				<TableCell textAlign="right">3.1%</TableCell>
				<TableCell textAlign="right">12.9%</TableCell>
			</TableRow>
			<TableRow>
				<TableCell>Victoria</TableCell>
				<TableCell textAlign="right">5,996,400</TableCell>
				<TableCell textAlign="right">2.5%</TableCell>
				<TableCell textAlign="right">9.3%</TableCell>
			</TableRow>
			<TableRow>
				<TableCell>Queensland</TableCell>
				<TableCell textAlign="right">4,808,800</TableCell>
				<TableCell textAlign="right">1.7%</TableCell>
				<TableCell textAlign="right">13.3%</TableCell>
			</TableRow>
			<TableRow>
				<TableCell>Western Australia</TableCell>
				<TableCell textAlign="right">2,603,900</TableCell>
				<TableCell textAlign="right">2.3%</TableCell>
				<TableCell textAlign="right">11.6%</TableCell>
			</TableRow>
			<TableRow>
				<TableCell>South Australia</TableCell>
				<TableCell textAlign="right">1,702,800</TableCell>
				<TableCell textAlign="right">2.0%</TableCell>
				<TableCell textAlign="right">6.8%</TableCell>
			</TableRow>
			<TableRow>
				<TableCell>Tasmania</TableCell>
				<TableCell textAlign="right">517,400</TableCell>
				<TableCell textAlign="right">4%</TableCell>
				<TableCell textAlign="right">5.3%</TableCell>
			</TableRow>
			<TableRow>
				<TableCell>Northern Territory</TableCell>
				<TableCell textAlign="right">244,400</TableCell>
				<TableCell textAlign="right">1.2%</TableCell>
				<TableCell textAlign="right">4.5%</TableCell>
			</TableRow>
			<TableRow>
				<TableCell>Australian Capital Territory</TableCell>
				<TableCell textAlign="right">393,000</TableCell>
				<TableCell textAlign="right">2.4%</TableCell>
				<TableCell textAlign="right">9.6%</TableCell>
			</TableRow>
		</TableBody>
	</Table>
</TableWrapper>

Sortable columns

You can use the <TableHeaderSortable> component to make columns sortable. This component is a wrapper around the TableHeader component and adds the necessary aria attributes to make the column sortable.

It is important to add <VisuallyHidden> text in the table’s caption to explain the purpose of the TableHeaderSortable buttons. This reduces confusion for screen reader users who may not understand their significance when focusing them.

You can see a working example of this component in the Search filters patterns.

<TableWrapper>
	<Table striped>
		<TableCaption>
			Population of Australian states and territories, December 2018
			<VisuallyHidden>
				, column headers with buttons are sortable.
			</VisuallyHidden>
		</TableCaption>
		<TableHead>
			<TableRow>
				<TableHeaderSortable
					scope="col"
					sort="ASC"
					width="50%"
					onClick={console.log}
				>
					Location
				</TableHeaderSortable>
				<TableHeaderSortable
					scope="col"
					width="50%"
					onClick={console.log}
					textAlign="right"
				>
					Population
				</TableHeaderSortable>
			</TableRow>
		</TableHead>
		<TableBody>
			<TableRow>
				<TableCell>Australian Capital Territory</TableCell>
				<TableCell textAlign="right">393,000</TableCell>
			</TableRow>
			<TableRow>
				<TableCell>New South Wales</TableCell>
				<TableCell textAlign="right">7,670,700</TableCell>
			</TableRow>
			<TableRow>
				<TableCell>Northern Territory</TableCell>
				<TableCell textAlign="right">244,400</TableCell>
			</TableRow>
			<TableRow>
				<TableCell>Queensland</TableCell>
				<TableCell textAlign="right">4,808,800</TableCell>
			</TableRow>
			<TableRow>
				<TableCell>South Australia</TableCell>
				<TableCell textAlign="right">1,702,800</TableCell>
			</TableRow>
			<TableRow>
				<TableCell>Tasmania</TableCell>
				<TableCell textAlign="right">517,400</TableCell>
			</TableRow>
			<TableRow>
				<TableCell>Victoria</TableCell>
				<TableCell textAlign="right">5,996,400</TableCell>
			</TableRow>
			<TableRow>
				<TableCell>Western Australia</TableCell>
				<TableCell textAlign="right">2,603,900</TableCell>
			</TableRow>
		</TableBody>
	</Table>
</TableWrapper>

Labels and headings

A Table must have some form of caption or heading to describe the data it contains. This can be done using the TableCaption component, or referencing a heading using aria-labelledby.

<Stack gap={1}>
	<H3 id="table-heading">Applications</H3>
	<Text id="table-description">Active establishment registrations</Text>
	<TableWrapper>
		<Table aria-labelledby="table-heading table-description">
			<TableHead>
				<TableRow>
					<TableHeader scope="col">Location</TableHeader>
					<TableHeader textAlign="right" scope="col">
						Population
					</TableHeader>
					<TableHeader textAlign="right" scope="col">
						Change over previous year %
					</TableHeader>
					<TableHeader textAlign="right" scope="col">
						Change over previous decade %
					</TableHeader>
				</TableRow>
			</TableHead>
			<TableBody>
				<TableRow>
					<TableCell as="th" scope="row">
						New South Wales
					</TableCell>
					<TableCell textAlign="right">7,670,700</TableCell>
					<TableCell textAlign="right">3.1%</TableCell>
					<TableCell textAlign="right">12.9%</TableCell>
				</TableRow>
				<TableRow>
					<TableCell as="th" scope="row">
						Victoria
					</TableCell>
					<TableCell textAlign="right">5,996,400</TableCell>
					<TableCell textAlign="right">2.5%</TableCell>
					<TableCell textAlign="right">9.3%</TableCell>
				</TableRow>
				<TableRow>
					<TableCell as="th" scope="row">
						Queensland
					</TableCell>
					<TableCell textAlign="right">4,808,800</TableCell>
					<TableCell textAlign="right">1.7%</TableCell>
					<TableCell textAlign="right">13.3%</TableCell>
				</TableRow>
				<TableRow>
					<TableCell as="th" scope="row">
						Western Australia
					</TableCell>
					<TableCell textAlign="right">2,603,900</TableCell>
					<TableCell textAlign="right">2.3%</TableCell>
					<TableCell textAlign="right">11.6%</TableCell>
				</TableRow>
				<TableRow>
					<TableCell as="th" scope="row">
						South Australia
					</TableCell>
					<TableCell textAlign="right">1,702,800</TableCell>
					<TableCell textAlign="right">2.0%</TableCell>
					<TableCell textAlign="right">6.8%</TableCell>
				</TableRow>
				<TableRow>
					<TableCell as="th" scope="row">
						Tasmania
					</TableCell>
					<TableCell textAlign="right">517,400</TableCell>
					<TableCell textAlign="right">4%</TableCell>
					<TableCell textAlign="right">5.3%</TableCell>
				</TableRow>
				<TableRow>
					<TableCell as="th" scope="row">
						Northern Territory
					</TableCell>
					<TableCell textAlign="right">244,400</TableCell>
					<TableCell textAlign="right">1.2%</TableCell>
					<TableCell textAlign="right">4.5%</TableCell>
				</TableRow>
				<TableRow>
					<TableCell as="th" scope="row">
						Australian Capital Territory
					</TableCell>
					<TableCell textAlign="right">393,000</TableCell>
					<TableCell textAlign="right">2.4%</TableCell>
					<TableCell textAlign="right">9.6%</TableCell>
				</TableRow>
			</TableBody>
		</Table>
	</TableWrapper>
</Stack>

Wide tables

When a table is too wide for its container, a custom scrollbar will be rendered. This scrollbar also sticks to the bottom of the screen when the bottom of the table is off-screen, so users can still easily scroll the table regardless of which rows they’re looking at.

<Stack gap={1}>
	<H3 id="wide-table-heading">Business registrations</H3>
	<TableWrapper>
		<Table aria-labelledby="wide-table-heading" tableLayout="fixed">
			<TableHead>
				<TableRow>
					<TableHeader scope="col" width="20rem">
						Business name
					</TableHeader>
					<TableHeader scope="col" width="12rem">
						Assignee
					</TableHeader>
					<TableHeader scope="col" width="16rem">
						City
					</TableHeader>
					<TableHeader scope="col" width="12rem">
						Date registered
					</TableHeader>
					<TableHeader scope="col" width="11rem">
						Status
					</TableHeader>
				</TableRow>
			</TableHead>
			<TableBody>
				<TableRow>
					<TableCell as="th" scope="row">
						Agriculture Victoria
					</TableCell>
					<TableCell>
						<Flex alignItems="center" gap={0.25}>
							<Avatar name="Oscar Piastri" size="sm" aria-hidden />
							<Text>Oscar Piastri</Text>
						</Flex>
					</TableCell>
					<TableCell>Melbourne, VIC</TableCell>
					<TableCell>14/08/2023</TableCell>
					<TableCell>
						<StatusBadge appearance="subtle" label="Booked" tone="infoMedium" />
					</TableCell>
				</TableRow>
				<TableRow>
					<TableCell as="th" scope="row">
						Aussie Acres Produce
					</TableCell>
					<TableCell>
						<Flex alignItems="center" gap={0.25}>
							<Avatar name="George Russell" size="sm" aria-hidden />
							<Text>George Russell</Text>
						</Flex>
					</TableCell>
					<TableCell>White Plains, NSW</TableCell>
					<TableCell>17/03/2024</TableCell>
					<TableCell>
						<StatusBadge
							appearance="subtle"
							label="Completed"
							tone="successMedium"
						/>
					</TableCell>
				</TableRow>
				<TableRow>
					<TableCell as="th" scope="row">
						Aussie Agribusiness
					</TableCell>
					<TableCell>
						<Flex alignItems="center" gap={0.25}>
							<Avatar name="Lando Norris" size="sm" aria-hidden />
							<Text>Lando Norris</Text>
						</Flex>
					</TableCell>
					<TableCell>Sydney, NSW</TableCell>
					<TableCell>19/11/2023</TableCell>
					<TableCell>
						<StatusBadge appearance="subtle" label="Booked" tone="infoMedium" />
					</TableCell>
				</TableRow>
				<TableRow>
					<TableCell as="th" scope="row">
						Aussie Agro Supplies
					</TableCell>
					<TableCell>
						<Flex alignItems="center" gap={0.25}>
							<Avatar name="Lando Norris" size="sm" aria-hidden />
							<Text>Lando Norris</Text>
						</Flex>
					</TableCell>
					<TableCell>Shanahanberg, TAS</TableCell>
					<TableCell>16/07/2023</TableCell>
					<TableCell>
						<StatusBadge
							appearance="subtle"
							label="Not booked"
							tone="notStartedLow"
						/>
					</TableCell>
				</TableRow>
				<TableRow>
					<TableCell as="th" scope="row">
						Australian Cattle Co.
					</TableCell>
					<TableCell>
						<Flex alignItems="center" gap={0.25}>
							<Avatar name="Lando Norris" size="sm" aria-hidden />
							<Text>Lando Norris</Text>
						</Flex>
					</TableCell>
					<TableCell>North Margarettaborough, WA</TableCell>
					<TableCell>01/11/2023</TableCell>
					<TableCell>
						<StatusBadge appearance="subtle" label="Booked" tone="infoMedium" />
					</TableCell>
				</TableRow>
				<TableRow>
					<TableCell as="th" scope="row">
						Baumbach, Williamson and Rosenbaum
					</TableCell>
					<TableCell>
						<Flex alignItems="center" gap={0.25}>
							<Avatar name="Oscar Piastri" size="sm" aria-hidden />
							<Text>Oscar Piastri</Text>
						</Flex>
					</TableCell>
					<TableCell>Oakland Park, VIC</TableCell>
					<TableCell>02/09/2023</TableCell>
					<TableCell>
						<StatusBadge appearance="subtle" label="Booked" tone="infoMedium" />
					</TableCell>
				</TableRow>
				<TableRow>
					<TableCell as="th" scope="row">
						Bergnaum Inc
					</TableCell>
					<TableCell>
						<Flex alignItems="center" gap={0.25}>
							<Avatar name="Oscar Piastri" size="sm" aria-hidden />
							<Text>Oscar Piastri</Text>
						</Flex>
					</TableCell>
					<TableCell>Tallahassee, SA</TableCell>
					<TableCell>23/12/2023</TableCell>
					<TableCell>
						<StatusBadge appearance="subtle" label="Booked" tone="infoMedium" />
					</TableCell>
				</TableRow>
				<TableRow>
					<TableCell as="th" scope="row">
						Brown Group
					</TableCell>
					<TableCell>
						<Flex alignItems="center" gap={0.25}>
							<Avatar name="George Russell" size="sm" aria-hidden />
							<Text>George Russell</Text>
						</Flex>
					</TableCell>
					<TableCell>Elgin, VIC</TableCell>
					<TableCell>28/12/2023</TableCell>
					<TableCell>
						<StatusBadge
							appearance="subtle"
							label="Cancelled"
							tone="errorMedium"
						/>
					</TableCell>
				</TableRow>
				<TableRow>
					<TableCell as="th" scope="row">
						Brown, Mayert and Robel
					</TableCell>
					<TableCell>-</TableCell>
					<TableCell>Ismaelshire, SA</TableCell>
					<TableCell>21/04/2024</TableCell>
					<TableCell>
						<StatusBadge
							appearance="subtle"
							label="Completed"
							tone="successMedium"
						/>
					</TableCell>
				</TableRow>
				<TableRow>
					<TableCell as="th" scope="row">
						Bushland Farms
					</TableCell>
					<TableCell>
						<Flex alignItems="center" gap={0.25}>
							<Avatar name="Oscar Piastri" size="sm" aria-hidden />
							<Text>Oscar Piastri</Text>
						</Flex>
					</TableCell>
					<TableCell>New Oleta, TAS</TableCell>
					<TableCell>22/05/2024</TableCell>
					<TableCell>
						<StatusBadge
							appearance="subtle"
							label="Not booked"
							tone="notStartedLow"
						/>
					</TableCell>
				</TableRow>
			</TableBody>
		</Table>
	</TableWrapper>
</Stack>

‘colSpan’ and ‘rowSpan’

Some tables require cells which represent multiple rows or columns. Instead of repeating the spanning data each time, you can use the colSpan and rowSpan props to specify how a specific cell spans multiple columns and rows, respectively.

<TableWrapper>
	<Table>
		<TableCaption>Items sold December 2024</TableCaption>
		<TableHead>
			<TableRow>
				<TableHeader as="td" colSpan={2}></TableHeader>
				<TableHeader scope="col" textAlign="right">
					Trousers
				</TableHeader>
				<TableHeader scope="col" textAlign="right">
					Skirts
				</TableHeader>
				<TableHeader scope="col" textAlign="right">
					Dresses
				</TableHeader>
				<TableHeader scope="col" textAlign="right">
					Bracelets
				</TableHeader>
			</TableRow>
		</TableHead>
		<TableBody>
			<TableRow>
				<TableCell as="th" fontWeight="bold" rowSpan="2" scope="rowgroup">
					Australia
				</TableCell>
				<TableCell as="th" fontWeight="bold" scope="row">
					Canberra
				</TableCell>
				<TableCell textAlign="right">80</TableCell>
				<TableCell textAlign="right">12</TableCell>
				<TableCell textAlign="right">43</TableCell>
				<TableCell textAlign="right">36</TableCell>
			</TableRow>
			<TableRow>
				<TableCell as="th" fontWeight="bold" scope="row">
					Sydney
				</TableCell>
				<TableCell textAlign="right">89</TableCell>
				<TableCell textAlign="right">34</TableCell>
				<TableCell textAlign="right">69</TableCell>
				<TableCell textAlign="right">85</TableCell>
			</TableRow>
			<TableRow>
				<TableCell as="th" fontWeight="bold" rowSpan="3" scope="rowgroup">
					Belgium
				</TableCell>
				<TableCell as="th" fontWeight="bold" scope="row">
					Antwerp
				</TableCell>
				<TableCell textAlign="right">56</TableCell>
				<TableCell textAlign="right">22</TableCell>
				<TableCell textAlign="right">43</TableCell>
				<TableCell textAlign="right">72</TableCell>
			</TableRow>
			<TableRow>
				<TableCell as="th" fontWeight="bold" scope="row">
					Brussels
				</TableCell>
				<TableCell textAlign="right">51</TableCell>
				<TableCell textAlign="right">27</TableCell>
				<TableCell textAlign="right">38</TableCell>
				<TableCell textAlign="right">69</TableCell>
			</TableRow>
			<TableRow>
				<TableCell as="th" fontWeight="bold" scope="row">
					Gent
				</TableCell>
				<TableCell textAlign="right">46</TableCell>
				<TableCell textAlign="right">18</TableCell>
				<TableCell textAlign="right">50</TableCell>
				<TableCell textAlign="right">61</TableCell>
			</TableRow>
		</TableBody>
	</Table>
</TableWrapper>

Actions

The actions associated with each table row (e.g. ‘Edit’, ‘Delete’, ‘Download’) should always be positioned in the last column, beneath the table header labeled ‘Actions’.

If rows contain three or more actions, they can instead be replaced with a Dropdown menu containing these actions.

To ensure the accessible name of each row’s actions is unique, associate them with an aria-describedby that points to the id of the primary, unique identifier for that row.

Links that open a page to view a record or more information should be located in the first column, be labelled with a unique identifier, and display as bold text.

<TableWrapper>
	<Table>
		<TableCaption>Applications (with actions)</TableCaption>
		<TableHead>
			<TableRow>
				<TableHeader scope="col">Reference</TableHeader>
				<TableHeader scope="col">Date submitted</TableHeader>
				<TableHeader scope="col">Status</TableHeader>
				<TableHeader scope="col">Actions</TableHeader>
			</TableRow>
		</TableHead>
		<TableBody>
			<TableRow>
				<TableCell as="th" scope="row" fontWeight="bold">
					<TextLink href="#" id="REF-AB3CD4EF">
						REF-AB3CD4EF
					</TextLink>
				</TableCell>
				<TableCell>20/06/2024</TableCell>
				<TableCell>
					<StatusBadge
						appearance="subtle"
						tone="infoMedium"
						label="In progress"
					/>
				</TableCell>
				<TableCell>
					<Flex gap={1}>
						<TextLink href="#" aria-describedby="REF-AB3CD4EF">
							Edit
						</TextLink>
						<TextLink href="#" aria-describedby="REF-AB3CD4EF">
							Download
						</TextLink>
					</Flex>
				</TableCell>
			</TableRow>
			<TableRow>
				<TableCell as="th" scope="row" fontWeight="bold">
					<TextLink href="#" id="REF-5GH6IJ7K">
						REF-5GH6IJ7K
					</TextLink>
				</TableCell>
				<TableCell>25/06/2024</TableCell>
				<TableCell>
					<StatusBadge
						appearance="subtle"
						tone="infoMedium"
						label="In progress"
					/>
				</TableCell>
				<TableCell>
					<Flex gap={1}>
						<TextLink href="#" aria-describedby="REF-5GH6IJ7K">
							Edit
						</TextLink>
						<TextLink href="#" aria-describedby="REF-5GH6IJ7K">
							Download
						</TextLink>
					</Flex>
				</TableCell>
			</TableRow>
			<TableRow>
				<TableCell as="th" scope="row" fontWeight="bold">
					<TextLink href="#" id="REF-M8NO9PQR">
						REF-M8NO9PQR
					</TextLink>
				</TableCell>
				<TableCell>02/07/2024</TableCell>
				<TableCell>
					<StatusBadge
						appearance="subtle"
						tone="successMedium"
						label="Completed"
					/>
				</TableCell>
				<TableCell>
					<Flex gap={1}>
						<TextLink href="#" aria-describedby="REF-M8NO9PQR">
							Edit
						</TextLink>
						<TextLink href="#" aria-describedby="REF-M8NO9PQR">
							Download
						</TextLink>
					</Flex>
				</TableCell>
			</TableRow>
			<TableRow>
				<TableCell as="th" scope="row" fontWeight="bold">
					<TextLink href="#" id="REF-S1TU2VWX">
						REF-S1TU2VWX
					</TextLink>
				</TableCell>
				<TableCell>05/08/2024</TableCell>
				<TableCell>
					<StatusBadge
						appearance="subtle"
						tone="infoMedium"
						label="In progress"
					/>
				</TableCell>
				<TableCell>
					<Flex gap={1}>
						<TextLink href="#" aria-describedby="REF-S1TU2VWX">
							Edit
						</TextLink>
						<TextLink href="#" aria-describedby="REF-S1TU2VWX">
							Download
						</TextLink>
					</Flex>
				</TableCell>
			</TableRow>
			<TableRow>
				<TableCell as="th" scope="row" fontWeight="bold">
					<TextLink href="#" id="REF-Y3ZA4B5C">
						REF-Y3ZA4B5C
					</TextLink>
				</TableCell>
				<TableCell>19/10/2024</TableCell>
				<TableCell>
					<StatusBadge
						appearance="subtle"
						tone="successMedium"
						label="Completed"
					/>
				</TableCell>
				<TableCell>
					<Flex gap={1}>
						<TextLink href="#" aria-describedby="REF-Y3ZA4B5C">
							Edit
						</TextLink>
						<TextLink href="#" aria-describedby="REF-Y3ZA4B5C">
							Download
						</TextLink>
					</Flex>
				</TableCell>
			</TableRow>
		</TableBody>
	</Table>
</TableWrapper>
<TableWrapper>
	<Table>
		<TableCaption>Applications (with actions dropdown)</TableCaption>
		<TableHead>
			<TableRow>
				<TableHeader scope="col">Reference</TableHeader>
				<TableHeader scope="col">Date submitted</TableHeader>
				<TableHeader scope="col">Status</TableHeader>
				<TableHeader scope="col">Actions</TableHeader>
			</TableRow>
		</TableHead>
		<TableBody>
			<TableRow>
				<TableCell as="th" scope="row" fontWeight="bold">
					<TextLink href="#" id="REF-ABC3CD4EF">
						REF-ABC3CD4EF
					</TextLink>
				</TableCell>
				<TableCell>20/06/2024</TableCell>
				<TableCell>
					<StatusBadge
						appearance="subtle"
						tone="infoMedium"
						label="In progress"
					/>
				</TableCell>
				<TableCell>
					<DropdownMenu>
						<DropdownMenuButton aria-describedby="REF-ABC3CD4EF">
							Action
						</DropdownMenuButton>
						<DropdownMenuPanel>
							<DropdownMenuItem>Edit</DropdownMenuItem>
							<DropdownMenuItem>Download</DropdownMenuItem>
							<DropdownMenuItem>Delete</DropdownMenuItem>
						</DropdownMenuPanel>
					</DropdownMenu>
				</TableCell>
			</TableRow>
			<TableRow>
				<TableCell as="th" scope="row" fontWeight="bold">
					<TextLink href="#" id="REF-5GHC6IJ7K">
						REF-5GHC6IJ7K
					</TextLink>
				</TableCell>
				<TableCell>25/06/2024</TableCell>
				<TableCell>
					<StatusBadge
						appearance="subtle"
						tone="infoMedium"
						label="In progress"
					/>
				</TableCell>
				<TableCell>
					<DropdownMenu>
						<DropdownMenuButton aria-describedby="REF-5GHC6IJ7K">
							Action
						</DropdownMenuButton>
						<DropdownMenuPanel>
							<DropdownMenuItem>Edit</DropdownMenuItem>
							<DropdownMenuItem>Download</DropdownMenuItem>
							<DropdownMenuItem>Delete</DropdownMenuItem>
						</DropdownMenuPanel>
					</DropdownMenu>
				</TableCell>
			</TableRow>
			<TableRow>
				<TableCell as="th" scope="row" fontWeight="bold">
					<TextLink href="#" id="REF-M8NCO9PQR">
						REF-M8NCO9PQR
					</TextLink>
				</TableCell>
				<TableCell>02/07/2024</TableCell>
				<TableCell>
					<StatusBadge
						appearance="subtle"
						tone="successMedium"
						label="Completed"
					/>
				</TableCell>
				<TableCell>
					<DropdownMenu>
						<DropdownMenuButton aria-describedby="REF-M8NCO9PQR">
							Action
						</DropdownMenuButton>
						<DropdownMenuPanel>
							<DropdownMenuItem>Edit</DropdownMenuItem>
							<DropdownMenuItem>Download</DropdownMenuItem>
							<DropdownMenuItem>Delete</DropdownMenuItem>
						</DropdownMenuPanel>
					</DropdownMenu>
				</TableCell>
			</TableRow>
			<TableRow>
				<TableCell as="th" scope="row" fontWeight="bold">
					<TextLink href="#" id="REF-S1TCU2VWX">
						REF-S1TCU2VWX
					</TextLink>
				</TableCell>
				<TableCell>05/08/2024</TableCell>
				<TableCell>
					<StatusBadge
						appearance="subtle"
						tone="infoMedium"
						label="In progress"
					/>
				</TableCell>
				<TableCell>
					<DropdownMenu>
						<DropdownMenuButton aria-describedby="REF-S1TCU2VWX">
							Action
						</DropdownMenuButton>
						<DropdownMenuPanel>
							<DropdownMenuItem>Edit</DropdownMenuItem>
							<DropdownMenuItem>Download</DropdownMenuItem>
							<DropdownMenuItem>Delete</DropdownMenuItem>
						</DropdownMenuPanel>
					</DropdownMenu>
				</TableCell>
			</TableRow>
			<TableRow>
				<TableCell as="th" scope="row" fontWeight="bold">
					<TextLink href="#" id="REF-Y3ZCA4B5C">
						REF-Y3ZCA4B5C
					</TextLink>
				</TableCell>
				<TableCell>19/10/2024</TableCell>
				<TableCell>
					<StatusBadge
						appearance="subtle"
						tone="successMedium"
						label="Completed"
					/>
				</TableCell>
				<TableCell>
					<DropdownMenu>
						<DropdownMenuButton aria-describedby="REF-Y3ZCA4B5C">
							Action
						</DropdownMenuButton>
						<DropdownMenuPanel>
							<DropdownMenuItem>Edit</DropdownMenuItem>
							<DropdownMenuItem>Download</DropdownMenuItem>
							<DropdownMenuItem>Delete</DropdownMenuItem>
						</DropdownMenuPanel>
					</DropdownMenu>
				</TableCell>
			</TableRow>
		</TableBody>
	</Table>
</TableWrapper>

Selectable with batch actions

Selectable tables allow users to select one or more rows simultaneously and perform batch actions against the selected items.

For more information, read the Selectable tables with batch actions pattern.

() => {
	const [selectedRows, setSelectedRows] = React.useState([]);

	function toggleRowSelection(rowIndex) {
		if (selectedRows.includes(rowIndex)) {
			setSelectedRows((r) => r.filter((s) => s !== rowIndex));
		} else {
			setSelectedRows((r) => [...r, rowIndex]);
		}
	}

	const anyRowsChecked = selectedRows.length > 0;
	const allRowsChecked = selectedRows.length === 3;

	function toggleAllRows() {
		if (anyRowsChecked) {
			setSelectedRows([]);
		} else {
			setSelectedRows([0, 1, 2]);
		}
	}

	return (
		<Stack gap={0.5}>
			<Stack>
				<Box paddingBottom={0.75} paddingLeft={0.75} borderBottom>
					<Checkbox
						size="sm"
						checked={allRowsChecked}
						indeterminate={anyRowsChecked && !allRowsChecked}
						onChange={() => toggleAllRows()}
					>
						Select all rows
					</Checkbox>
				</Box>
				<TableWrapper>
					<Table>
						<TableHead>
							<TableRow>
								<TableHeader>Select</TableHeader>
								<TableHeader scope="col">Reference</TableHeader>
								<TableHeader scope="col">Date submitted</TableHeader>
								<TableHeader scope="col">Actions</TableHeader>
							</TableRow>
						</TableHead>
						<TableBody>
							{Array.from(new Array(3).keys()).map((index) => {
								const isRowSelected = selectedRows.includes(index);
								return (
									<TableRow selected={isRowSelected} key={index}>
										<TableCell>
											<Checkbox
												size="sm"
												checked={isRowSelected}
												onChange={() => toggleRowSelection(index)}
											>
												<VisuallyHidden>Select</VisuallyHidden>
											</Checkbox>
										</TableCell>
										<TableCell as="th" scope="row" fontWeight="bold">
											<TextLink href="#" id={`REF-AB${index}CD4EF`}>
												REF-AB{index}CD4EF
											</TextLink>
										</TableCell>
										<TableCell>2{index}/06/2024</TableCell>
										<TableCell>
											<Flex gap={1}>
												<TextLink
													aria-describedby={`REF-AB${index}CD4EF`}
													href="#"
												>
													Download
												</TextLink>
												<TextLink
													aria-describedby={`REF-AB${index}CD4EF`}
													href="#"
												>
													Delete
												</TextLink>
											</Flex>
										</TableCell>
									</TableRow>
								);
							})}
						</TableBody>
					</Table>
				</TableWrapper>
			</Stack>
			{selectedRows.length > 0 ? (
				<TableBatchActionsBar>
					<TableBatchActionsTitle>
						Apply action to {selectedRows.length} items
					</TableBatchActionsTitle>
					<ButtonGroup>
						<Button variant="secondary" size="sm">
							Download
						</Button>
						<Button variant="secondary" size="sm">
							Delete
						</Button>
						<Button variant="tertiary" size="sm" onClick={toggleAllRows}>
							Cancel
						</Button>
					</ButtonGroup>
				</TableBatchActionsBar>
			) : null}
		</Stack>
	);
};

Indicating an invalid row

To indicate an error in a row containing an action, set the invalid prop to true. This should be accompanied by a section alert.

<Stack gap={2}>
	<SectionAlert title="There was an error" tone="error">
		<UnorderedList>
			<ListItem>
				<TextLink href="#operational-plan-of-management-upload-button">
					File is missing for Operational Plan of Management
				</TextLink>
			</ListItem>
		</UnorderedList>
	</SectionAlert>

	<TableWrapper>
		<Table>
			<TableCaption>Assessment files</TableCaption>
			<TableHead>
				<TableRow>
					<TableHeader scope="col">Document type</TableHeader>
					<TableHeader scope="col">File</TableHeader>
					<TableHeader scope="col">Size</TableHeader>
					<TableHeader scope="col">Action</TableHeader>
				</TableRow>
			</TableHead>
			<TableBody>
				<TableRow>
					<TableCell as="th" scope="row">
						RMS Vehicle registration
					</TableCell>
					<TableCell>
						<Box>filename.pdf</Box>
					</TableCell>
					<TableCell>88kb</TableCell>
					<TableCell>
						<Button
							iconBefore={UploadIcon}
							id="rms-vehicle-registration-upload-button"
							variant="text"
						>
							Upload
						</Button>
					</TableCell>
				</TableRow>
				<TableRow invalid={true}>
					<TableCell as="th" scope="row">
						Operational Plan of Management
					</TableCell>
					<TableCell></TableCell>
					<TableCell>
						<StatusBadge
							appearance="subtle"
							label="File missing"
							appearance="subtle"
							tone="errorHigh"
						/>
					</TableCell>
					<TableCell>
						<Button
							iconBefore={UploadIcon}
							id="operational-plan-of-management-upload-button"
							variant="text"
						>
							Upload
						</Button>
					</TableCell>
				</TableRow>
				<TableRow>
					<TableCell as="th" scope="row">
						Vehicle build and layout plans
					</TableCell>
					<TableCell>
						<Box>filename.pdf</Box>
					</TableCell>
					<TableCell>88kb</TableCell>
					<TableCell>
						<Button
							iconBefore={UploadIcon}
							id="vehicle-build-and-layout-plans-upload-button"
							variant="text"
						>
							Upload
						</Button>
					</TableCell>
				</TableRow>
			</TableBody>
		</Table>
	</TableWrapper>
</Stack>
  • Summary list Summary list is used to summarise information such as a user’s responses at the end of a form.
  • Search filters Search filters help users find what they’re looking for by displaying options that meet specified criteria.
  • Selectable tables with batch actions Selectable tables allow users to select one or more rows simultaneously and perform batch actions against the selected rows. A batch action is any action that can be performed against any selectable row of a table.