Helsinki Design System
Helsinki Design System
Getting started
Tutorials
Guidelines
Visual assets
Design tokens
Components
OverviewAccordionButtonCardCheckboxDate inputDialogDropdownFieldsetFile inputFooterIconKorosLinkLinkboxLoading spinnerLogoNavigationNotificationNumber inputPassword inputPhone inputRadio buttonSearch inputSelection groupSide navigationStatus labelTablePrinciplesAccessibilityUsage & variationsDemos & APITabsTagText fieldsTime inputToggle buttonTooltip
Patterns
About
Contributing
Resources

Table

DraftAccessible

Tables are used to present tabulated data to the user in a consistent manner. HDS Tables offer multiple variants to allow clear presentation of vastly different data sets.

More table features are coming!
HDS Tables are work in progress. The current feature set will serve most projects but later we are also looking into adding more features such as single row actions (edit, delete), expandable rows and supporting more HDS components inside tables.

Principles

Basic tables (Core and React)

  • Use tables to organise and present data.
  • You should consider other presentation formats when the data is very simple, e.g. when the table would only have less than 4 rows or less than 3 columns.
    • Also note that HDS Tables are not a spreadsheet application. If you expect the user to need complex data operations it may be wise to share the data as a spreadsheet file.
  • Do not use tables to create layouts. Tables are meant to present data.
  • Align text to the left and numerical data to the right. Header cells are always aligned to the left. HDS provides CSS classes to make this easier.
  • Utilise zebra lines when your table has long rows. Zebra lines help the user to follow a specific row.
  • Utilise vertical lines when your table has a lot of content and narrow cells. Number-heavy tables are an example of a situation where vertical lines may help the user.
  • HDS Table offers smaller font sizes and spacing on mobile screens.
    • If your table has a large amount of data, you can use the dense property to force mobile spacing on all screen sizes.
  • Table container is allowed to be scrollable. This is common on smaller screens where it can be impossible to fit the full table on the device screen.
    • On smaller screens, it may be beneficial to consider other presentation formats for table data. For example, a table can be broken into cards.

Interactable tables (React)

  • HDS Tables support sorting. When a column is set to be sortable, a sorting button appears after its header.
    • The sorting icon type can be changed depending on the type of data in the column.
  • Only use sorting when it is necessary or otherwise beneficial to the user.
  • HDS Table's rows can be made selectable. In this case, HDS automatically provides actions for selecting and deselecting all rows.
  • If your table includes actions that can affect multiple rows (e.g. deleting selected rows or exporting a CSV file), these actions must be placed above the table. For more information, see Selecting rows and Custom actions variant examples below.

Accessibility

  • No matter how well tables are implemented, they are always very demanding for assistive technology users. Always consider whether the table is necessary to present the information.
  • Make sure your table has a heading that describes the table’s purpose. This heading can either be a heading tag (e.g. H2) or a caption element. If it is a heading tag, reference it with an aria-labelledby attribute in the <table> tag.
  • Table header is read to assistive technologies on every cell. Keep table header labels short and concise and make sure they describe the data contained in table cells.
    • This is especially important if the column allows sorting. The sorting label (e.g. "First name, sorted") will be read to assistive technologies on every cell. Only allow sorting if it is really necessary and beneficial to the user.
  • If your table includes empty column header cells, make sure they have a role=“presentation” attribute.

Usage & variations

Default

The default HDS table variant includes horizontal lines. The header row can be either dark or light depending on the brand colour used as a background. Whether you need a black or white text colour can be checked from HDS Colour documentation page.

Table 1: Service users (dark variant)
First nameSurnameAgeProfession
LauriKekkonen
39
Engineer
MariaSarasoja
62
Designer
AnneliRouta
50
Meteorologist
OskuRausku
18
Mail Carrier
Table 1: Service users (light variant)
First nameSurnameAgeProfession
LauriKekkonen
39
Engineer
MariaSarasoja
62
Designer
AnneliRouta
50
Meteorologist
OskuRausku
18
Mail Carrier

Core code example:

<div class="hds-table-container" style="max-width: 640px;" tabindex="0">
<table class="hds-table hds-table--dark" aria-label="Service users (dark variant)">
<caption class="hds-table__caption"><b>Table 1</b>: Service users (dark variant)</caption>
<thead>
<tr class="hds-table__header-row">
<th scope="col">First name</th>
<th scope="col">Surname</th>
<th scope="col">Age</th>
<th scope="col">Profession</th>
</tr>
</thead>
<tbody class="hds-table__content">
<tr>
<td>Lauri</td>
<td>Kekkonen</td>
<td class="hds-table--text-align-right">39</td>
<td>Engineer</td>
</tr>
<tr>
<td>Maria</td>
<td>Sarasoja</td>
<td class="hds-table--text-align-right">62</td>
<td>Designer</td>
</tr>
<tr>
<td>Anneli</td>
<td>Routa</td>
<td class="hds-table--text-align-right">50</td>
<td>Meteorologist</td>
</tr>
<tr>
<td>Osku</td>
<td>Rausku</td>
<td class="hds-table--text-align-right">18</td>
<td>Mail carrier</td>
</tr>
</tbody>
</table>
</div>
<div class="hds-table-container" style="max-width: 640px;" tabindex="0">
<table class="hds-table hds-table--light" aria-label="Service users (light variant)">
<caption class="hds-table__caption"><b>Table 2</b>: Service users (light variant)</caption>
<!-- ... (Refer above for the full example) -->
</table>
</div>

React code example:

const cols = [
{ key: 'id', headerName: 'Not rendered' },
{ key: 'firstName', headerName: 'First name' },
{ key: 'surname', headerName: 'Surname' },
{
key: 'age',
headerName: 'Age',
transform: ({ age }) => {
return <div style={{ textAlign: 'right' }}>{age}</div>;
},
},
{ key: 'profession', headerName: 'Profession' },
];
const rows = [
{ id: 1000, firstName: 'Lauri', surname: 'Kekkonen', age: 39, profession: 'Engineer' },
{ id: 1001, firstName: 'Maria', surname: 'Sarasoja', age: 62, profession: 'Designer' },
{ id: 1002, firstName: 'Anneli', surname: 'Routa', age: 50, profession: 'Meteorologist' },
{ id: 1003, firstName: 'Osku', surname: 'Rausku', age: 18, profession: 'Mail Carrier' },
];
const captionDark = (
<span>
<b>Table 1</b>: Service users (dark variant)
</span>
);
const captionLight = (
<span>
<b>Table 1</b>: Service users (light variant)
</span>
)
return (
<div style={{ maxWidth: '640px' }}>
<Table cols={cols} rows={rows} caption={captionDark} indexKey="id" renderIndexCol={false} />
<div style={{ marginTop: 'var(--spacing-l)' }}>
<Table cols={cols} rows={rows} caption={captionLight} variant="light" indexKey="id" renderIndexCol={false} />
</div>
</div>
);

Vertical headers

Vertical headers can be used to create tables that have both a header row and a header column. Note that the empty header cell on the top left corner has role="presentation" attribute.

Table 3: Units sold by weekday
8-1212-1414-1616-18
Monday32456228094
Tuesday341688425113
Wednesday29449228067
Thursday312501455112
Friday150142362455

Core code example:

<div class="hds-table-container" style="max-width: 496px;"tabindex="0">
<table
class="hds-table hds-table--dark hds-table--with-vertical-header"
aria-label="Units sold by weekday"
>
<caption class="hds-table__caption"><b>Table 3</b>: Units sold by weekday</caption>
<colgroup>
<col span="1" class="hds-table__vertical-header-column"></col>
</colgroup>
<thead>
<tr class="hds-table__header-row">
<td role="presentation"></td>
<th scope="col">8-12</th>
<th scope="col">12-14</th>
<th scope="col">14-16</th>
<th scope="col">16-18</th>
</tr>
</thead>
<tbody class="hds-table__content hds-table__content--text-align-td-right">
<tr>
<th scope="row">Monday</th>
<td>324</td>
<td>562</td>
<td>280</td>
<td>94</td>
</tr>
<!-- ... -->
</tbody>
</table>
</div>

React code example:

const cols = [
{ key: 'id', headerName: 'Not rendered' },
{ key: '8-12', headerName: '8-12' },
{ key: '12-14', headerName: '12-14' },
{ key: '14-16', headerName: '14-16' },
{ key: '16-18', headerName: '16-18' },
];
const unitRows = [
{ id: 'monday', '8-12': 324, '12-14': 562, '14-16': 280, '16-18': 94 },
{ id: 'tuesday', '8-12': 341, '12-14': 688, '14-16': 425, '16-18': 113 },
{ id: 'wednesday', '8-12': 294, '12-14': 492, '14-16': 280, '16-18': 67 },
{ id: 'thursday', '8-12': 312, '12-14': 501, '14-16': 455, '16-18': 112 },
{ id: 'friday', '8-12': 150, '12-14': 142, '14-16': 362, '16-18': 455 },
];
const verticalHeaders = [
{ key: 'monday', headerName: 'Monday' },
{ key: 'tuesday', headerName: 'Tuesday' },
{ key: 'wednesday', headerName: 'Wednesday' },
{ key: 'thursday', headerName: 'Thursday' },
{ key: 'friday', headerName: 'Friday' },
];
const caption = (
<span>
<b>Table 3</b>: Units sold by weekday
</span>
);
return (
<div style={{ maxWidth: '486px' }}>
<Table
verticalHeaders={verticalHeaders}
cols={cols}
rows={unitRows}
caption={caption}
textAlignContentRight
indexKey="id"
renderIndexCol={false}
/>
</div>
);

Zebra rows

Zebra rows (alternating row colours) should be used on tables that have very long rows. It makes it easier to visually scan the table and follow rows.

Table 4: Service users (zebra variant)
First nameSurnameAgeCityProfessionExperience (years)
LauriKekkonen
39
HelsinkiEngineer
10
MariaSarasoja
62
TampereDesigner
39
AnneliRouta
50
TurkuMeteorologist
25
OskuRausku
18
OuluMail Carrier
1

Core code example:

<div class="hds-table-container" style="max-width: 800px;" tabindex="0">
<table class="hds-table hds-table--dark hds-table--zebra" aria-label="Service users (zebra variant)">
<caption class="hds-table__caption"><b>Table 4</b>: Service users (zebra variant)</caption>
<!-- ... (Refer the default variant for the full example) -->
</table>
</div>

React code example:

const cols = [
{ key: 'id', headerName: 'Not rendered' },
{ key: 'firstName', headerName: 'First name' },
{ key: 'surname', headerName: 'Surname' },
{
key: 'age',
headerName: 'Age',
transform: ({ age }) => {
return <div style={{ textAlign: 'right' }}>{age}</div>;
},
},
{ key: 'city', headerName: 'City' },
{ key: 'profession', headerName: 'Profession' },
{
key: 'experience',
headerName: 'Experience (years)',
transform: ({ experience }) => {
return <div style={{ textAlign: 'right' }}>{experience}</div>;
},
},
];
const rows = [
{
id: 1000,
firstName: 'Lauri',
surname: 'Kekkonen',
age: 39,
city: 'Helsinki',
profession: 'Engineer',
experience: 10,
},
// ...
];
const caption = (
<span>
<b>Table 4</b>: Service users (zebra variant)
</span>
);
return (
<div style={{ maxWidth: '800px' }}>
<Table rows={rows} cols={cols} caption={caption} zebra indexKey="id" renderIndexCol={false} />
</div>
);

Vertical lines

Vertical lines can be used on tables that have a lot of columns or a lot of similar data (e.g. numbers).

Table 5: Units sold by weekday (vertical lines variant)
DayProduct 1Product 2Product 3
Monday
12
24
5
Tuesday
10
32
6
Wednesday
14
35
6
Thursday
11
18
2
Friday
16
45
12

Core code example:

<div class="hds-table-container" style="max-width: 496px;" tabindex="0">
<table class="hds-table hds-table--dark hds-table--with-vertical-lines" aria-label="Units sold by weekday">
<caption class="hds-table__caption"><b>Table 1</b>: Table description</caption>
<thead>
<tr class="hds-table__header-row">
<th scope="col">Day</th>
<th scope="col">Product 1</th>
<th scope="col">Product 2</th>
<th scope="col">Product 3</th>
</tr>
</thead>
<tbody class="hds-table__content">
<tr>
<td>Monday</td>
<td class="hds-table--text-align-right">12</td>
<td class="hds-table--text-align-right">24</td>
<td class="hds-table--text-align-right">5</td>
</tr>
<!-- ... -->
</tbody>
</table>
</div>

React code example:

const cols = [
{ key: 'day', headerName: 'Day' },
{ key: 'product1',
headerName: 'Product 1',
transform: ({ product1 }) => {
return <div style={{ textAlign: 'right' }}>{product1}</div>;
},
},
{ key: 'product2',
headerName: 'Product 2',
transform: ({ product2 }) => {
return <div style={{ textAlign: 'right' }}>{product2}</div>;
},
},
{ key: 'product3',
headerName: 'Product 3',
transform: ({ product3 }) => {
return <div style={{ textAlign: 'right' }}>{product3}</div>;
},
},
];
const rows = [
{ day: 'Monday', product1: 12, product2: 24, product3: 5, },
// ...
];
const caption = (
<span>
<b>Table 5</b>: Units sold by weekday (vertical lines variant)
</span>
);
return (
<div style={{ maxWidth: '496px' }}>
<Table verticalLines cols={cols} rows={rows} caption={caption} indexKey="day" renderIndexCol={true} />
</div>
);

Dense tables

If your table has a large amount of data, you can use the dense property to force mobile spacing on all screen sizes. This allows more data to fit into the view at the same time.

Table 6: Job trials (source: Helsinki Employment Services)
Job idTypeTitleExpiresDepartmentJob namePostal codeAvailable placesTo be interviewed
33740TyökokeilupaikkaHarjoittelija31.12.2021Kasvatus ja koulutusTYÖKOKEILU Snellu Cafe´ lounaskahvila009003640
33741TyökokeilupaikkaHarjoittelija31.12.2021Kasvatus ja koulutusMaunulatalon kahvila (Månsas Deli)006303950
33823TyökokeilupaikkaViestintäalan harjoittelija31.12.2021Kasvatus ja koulutusTarinapaja006101230
33739TyökokeilupaikkaKahvila-apulainen31.12.2021Kasvatus ja koulutusKahvilapalvelut006101220
33918TyökokeilupaikkaTeknisen alan harjoittelija31.12.2021Kasvatus ja koulutusWooDoo-verstas008804550
34825TyökokeilupaikkaHoitoapulainen31.12.2021Sosiaali- ja terveystoimialaSinikello0042035
35212TyökokeilupaikkaTeknisen alan harjoittelija31.12.2021Kasvatus ja koulutusMetalliverstas008803740
35213TyökokeilupaikkaTeknisen alan harjoittelija30.06.2022Kasvatus ja koulutusMoottoripaja Pitäjänmäki003701821
35294TyökokeilupaikkaErityisavustaja29.11.2021Kasvatus ja koulutusPk Savela00720110
35295TyökokeilupaikkaErityisavustaja29.11.2021Kasvatus ja koulutusPk Sinivuori00720110
35296TyökokeilupaikkaPäiväkodin harjoittelija29.11.2021Kasvatus ja koulutusVarhaiskasvatusyksikkö Siilitie0080022
35283TyökokeilupaikkaLiikunnanohjaaja27.11.2021Sosiaali- ja terveystoimialaPalvelukeskus0042012
34165TyökokeilupaikkaICT-alan harjoittelija27.02.2022Kasvatus ja koulutusDigitalents Helsinki002705170
35096TyökokeilupaikkaErityisavustaja25.10.2021Kasvatus ja koulutusVarhaiskasvatusyksikkö Herttoniemi0080011
35088TyökokeilupaikkaPäiväkodin harjoittelija24.10.2021Kasvatus ja koulutusPäiväkoti Lapinmäki0035034
34549TyökokeilupaikkaTeknisen alan harjoittelija19.07.2023Kasvatus ja koulutusWooDoo-verstas008802950
35050TyökokeilupaikkaErityisavustaja18.10.2021Kasvatus ja koulutusPäiväkoti Neulanen00920720
35237TyökokeilupaikkaOhjaaja17.11.2021Sosiaali- ja terveystoimialaStadin asukastalo Pihlajamäki0071014
35230TyökokeilupaikkaErityisavustaja16.11.2021Kasvatus ja koulutusKuninkaantammi0043023
35224TyökokeilupaikkaErityisavustaja15.11.2021Kasvatus ja koulutusPäiväkoti Loimi0094012
35223TyökokeilupaikkaPäiväkodin harjoittelija15.11.2021Kasvatus ja koulutusPk Pihapirtti0094023
35221TyökokeilupaikkaHoiva-avustaja14.11.2021Sosiaali- ja terveystoimialaUsva-tiimi0077012
35222TyökokeilupaikkaHoiva-avustaja14.11.2021Sosiaali- ja terveystoimialaRuska-tiimi0077013
35218TyökokeilupaikkaHoitoapulainen14.11.2021Sosiaali- ja terveystoimialaTuulensuu0050013
35018TyökokeilupaikkaAvustaja12.10.2021Kasvatus ja koulutusPäiväkoti Tapanila0073011
35003TyökokeilupaikkaPäiväkotiapulainen12.10.2021Kasvatus ja koulutusPäiväkoti Neulanen0092025
35002TyökokeilupaikkaPäiväkodin harjoittelija11.10.2021Kasvatus ja koulutusPäiväkoti Terhi0053022
34998TyökokeilupaikkaErityisavustaja11.10.2021Kasvatus ja koulutusPäiväkoti Ruuti0094022
34999TyökokeilupaikkaErityisavustaja11.10.2021Kasvatus ja koulutusPäiväkoti Haikara0094022
34986TyökokeilupaikkaHoitoavustaja10.10.2021Sosiaali- ja terveystoimialaKannelmäen palvelutalo0042012
34987TyökokeilupaikkaHoitoavustaja10.10.2021Sosiaali- ja terveystoimialaKannelmäen palvelutalo0042012
34988TyökokeilupaikkaHoitoavustaja10.10.2021Sosiaali- ja terveystoimialaKannelmäen palvelutalo0042013
35202TyökokeilupaikkaErityisavustaja08.11.2021Kasvatus ja koulutusPk Lassi ja Pk Niitty0044025
35176TyökokeilupaikkaPäiväkotiapulainen07.11.2021Kasvatus ja koulutusPäiväkoti Suomenlinna0019013
35193TyökokeilupaikkaHoitoavustaja07.11.2021Sosiaali- ja terveystoimialaRyhmäkoti Kantola tai Pohjantähti0094013
35194TyökokeilupaikkaHoitoavustaja07.11.2021Sosiaali- ja terveystoimialaRyhmäkoti Apila, Orvokki tai Vanamo0094013
35195TyökokeilupaikkaHoitoavustaja07.11.2021Sosiaali- ja terveystoimialaRyhmäkoti Puolukka, Karpalo tai Mansikka0094013
35179TyökokeilupaikkaLeikkipuistoavustaja07.11.2021Kasvatus ja koulutusLeikkipuisto Intia0056013
35189TyökokeilupaikkaLeikkipuistoavustaja07.11.2021Kasvatus ja koulutusLeikkipuisto Lehdokki0052023
35190TyökokeilupaikkaLeikkipuistoavustaja07.11.2021Kasvatus ja koulutusLeikkipuisto Linja0053033
35191TyökokeilupaikkaLeikkipuistoavustaja07.11.2021Kasvatus ja koulutusLeikkipuisto Sanna0024033
35192TyökokeilupaikkaLeikkipuistoavustaja07.11.2021Kasvatus ja koulutusLeikkipuisto Vallila0055033
35196TyökokeilupaikkaHoitoavustaja07.11.2021Sosiaali- ja terveystoimialaRyhmäkoti Vadelma tai Mustikka0094013
35197TyökokeilupaikkaKuntoutusavustaja07.11.2021Sosiaali- ja terveystoimialaRyhmäkoti Kantola0094015
35201TyökokeilupaikkaErityisavustaja07.11.2021Kasvatus ja koulutusPk Jousi0094024
34969TyökokeilupaikkaErityisavustaja06.10.2021Kasvatus ja koulutusPk Haaga0032013
34970TyökokeilupaikkaErityisavustaja06.10.2021Kasvatus ja koulutusPk Kylätie0032013
34957TyökokeilupaikkaApuohjaaja05.10.2021Sosiaali- ja terveystoimialaSisustusompelimo0050016
34960TyökokeilupaikkaApuohjaaja05.10.2021Sosiaali- ja terveystoimialaMuusix-ruokala0050014
34961TyökokeilupaikkaPäiväkodin harjoittelija05.10.2021Kasvatus ja koulutusVarhaiskasvatusyksikkö Siilitie0080033
34952TyökokeilupaikkaPäiväkodin harjoittelija04.10.2021Kasvatus ja koulutusMyrskyluoto0098012
34953TyökokeilupaikkaPäiväkodin harjoittelija04.10.2021Kasvatus ja koulutusHippaheikki098022
34954TyökokeilupaikkaPäiväkodin harjoittelija04.10.2021Kasvatus ja koulutusKajuutta0098022
34948TyökokeilupaikkaErityisavustaja03.10.2021Kasvatus ja koulutusPäiväkoti Vanhainen0042022
35138TyökokeilupaikkaApuohjaaja02.11.2021Sosiaali- ja terveystoimialaKeramiikka0058015
34550TyökokeilupaikkaKahvila-apulainen01.07.2023Kasvatus ja koulutusKahvila Villa Ullas009807899

Core code example:

<div class="hds-table-container" style="max-height: 600px;" tabindex="0">
<table class="hds-table hds-table--dense hds-table--dark hds-table--zebra" aria-label="Job trials (source: Helsinki Employment Services)">
<caption class="hds-table__caption"><b>Table 6</b>: Job trials (source: Helsinki Employment Services)</caption>
<thead>
<tr class="hds-table__header-row">
<th scope="col">Job id</th>
<th scope="col">Type</th>
<th scope="col">Title</th>
<th scope="col">Expires</th>
<th scope="col">Department</th>
<th scope="col">Job name</th>
<th scope="col">Postal code</th>
<th scope="col">Available places</th>
<th scope="col">To be interviewed</th>
</tr>
</thead>
<tbody class="hds-table__content">
<tr>
<td class="hds-table--text-align-right">33740</td>
<td>Työkokeilupaikka</td>
<td>Harjoittelija</td>
<td>31.12.2021</td>
<td>Kasvatus ja koulutus</td>
<td>TYÖKOKEILU Snellu Cafe´ lounaskahvila</td>
<td class="hds-table--text-align-right">00900</td>
<td class="hds-table--text-align-right">36</td>
<td class="hds-table--text-align-right">40</td>
</tr>
<!-- ... -->
</tbody>
</table>
</div>

React code example:

const cols = [
{ key: 'Paikka-ID', headerName: 'Paikka-ID' },
{ key: 'Paikan tyyppi', headerName: 'Paikan tyyppi' },
{ key: 'Tehtävänimike', headerName: 'Tehtävänimike' },
{ key: 'Ilmoitus vanhenee', headerName: 'Ilmoitus vanhenee' },
{ key: 'Toimiala/liikelaitos', headerName: 'Toimiala/liikelaitos' },
{ key: 'Työpaikka', headerName: 'Työpaikka' },
{ key: 'Postinumero', headerName: 'Postinumero' },
{
key: 'Paikkoja',
headerName: 'Paikkoja',
transform: ({ Paikkoja }) => {
return <div style={{ textAlign: 'right' }}>{Paikkoja}</div>;
},
},
{
key: 'Haastatteluun halutaan',
headerName: 'Haastatteluun halutaan',
transform: (row) => {
return <div style={{ textAlign: 'right' }}>{row['Haastatteluun halutaan']}</div>;
},
},
];
const rows = workTrial;
const caption = (
<span>
<b>Table 6</b>: Job trials (source: Helsinki Employment Services)
</span>
);
return (
<div style={{ maxWidth: '1200px', height: '600px' }}>
<Table cols={cols} rows={rows} indexKey="Paikka-ID" caption={caption} dense />
</div>
);

Sorting

Columns can be configured to be sortable which makes the sorting button appear after the column header. The sorting icon is different depending on the data type of the column (alphabetical or numeric/other).

Currently, only one column can be sorted at a time.

Table 7: Service users (sorting, dark variant)
LauriKekkonen
39
Engineer
MariaSarasoja
62
Designer
AnneliRouta
50
Meteorologist
OskuRausku
18
Mail Carrier
LindaKoululainen
8
School student

Core code example:

Not supported in hds-core!

React code example:

const cols = [
{ key: 'id', headerName: 'Not rendered' },
{ key: 'firstName', headerName: 'First name', isSortable: true },
{ key: 'surname', headerName: 'Surname', isSortable: true },
{
key: 'age',
headerName: 'Age',
sortIconType: 'other',
transform: ({ age }) => {
return <div style={{ textAlign: 'right' }}>{age}</div>;
},
isSortable: true,
},
{ key: 'profession', headerName: 'Profession', isSortable: true },
];
const rows = [
{ id: 1000, firstName: 'Lauri', surname: 'Kekkonen', age: 39, profession: 'Engineer' },
{ id: 1001, firstName: 'Maria', surname: 'Sarasoja', age: 62, profession: 'Designer' },
{ id: 1002, firstName: 'Anneli', surname: 'Routa', age: 50, profession: 'Meteorologist' },
{ id: 1003, firstName: 'Osku', surname: 'Rausku', age: 18, profession: 'Mail Carrier' },
{ id: 1004, firstName: 'Linda', surname: 'Koululainen', age: 8, profession: 'School student' },
];
const caption = (
<span>
<b>Table 7</b>: Service users (sorting, dark variant)
</span>
);
return (
<div style={{ maxWidth: '640px' }}>
<Table
ariaLabelSortButtonUnset="Not sorted"
ariaLabelSortButtonAscending="Sorted in ascending order"
ariaLabelSortButtonDescending="Sorted in descending order"
indexKey="id"
renderIndexCol={false}
cols={cols}
rows={rows}
caption={caption}
/>
</div>
);

Selecting rows

HDS Table rows can be set to be selectable. This makes the first column to be a selection column. This also adds two (2) action buttons above the table; one button for selecting all rows and one button to clear selection.

Employees
First nameSurnameAgeProfession
LauriKekkonen
39
Engineer
MariaSarasoja
62
Designer
AnneliRouta
50
Meteorologist
OskuRausku
18
Mail Carrier

Core code example:

Not supported in hds-core!

React code example:

const cols = [
{ key: 'id', headerName: 'Not rendered' },
{ key: 'firstName', headerName: 'First name' },
{ key: 'surname', headerName: 'Surname' },
{
key: 'age',
headerName: 'Age',
transform: ({ age }) => {
return <div style={{ textAlign: 'right' }}>{age}</div>;
},
},
{ key: 'profession', headerName: 'Profession' },
];
const rows = [
{ id: 1000, firstName: 'Lauri', surname: 'Kekkonen', age: 39, profession: 'Engineer' },
{ id: 1001, firstName: 'Maria', surname: 'Sarasoja', age: 62, profession: 'Designer' },
{ id: 1002, firstName: 'Anneli', surname: 'Routa', age: 50, profession: 'Meteorologist' },
{ id: 1003, firstName: 'Osku', surname: 'Rausku', age: 18, profession: 'Mail Carrier' },
];
const [selectedRows, setSelectedRows] = useState([]);
return (
<div style={{ maxWidth: '640px' }}>
<Table
checkboxSelection
selectedRows={selectedRows}
setSelectedRows={setSelectedRows}
heading="Employees"
id="checkbox-selection"
indexKey="id"
renderIndexCol={false}
cols={cols}
rows={rows}
selectAllRowsText="Select all rows"
clearSelectionsText="Clear selections"
ariaLabelCheckboxSelection="Row selection"
/>
</div>
);

Custom table actions

If the action you need is not directly supported by the HDS Table, you can also add custom actions. Like other actions, they are placed above the table as HDS Buttons.

Employees
First nameSurnameAgeProfession
LauriKekkonen
39
Engineer
MariaSarasoja
62
Designer
AnneliRouta
50
Meteorologist
OskuRausku
18
Mail Carrier

Core code example:

Not supported in hds-core!

React code example:

const cols = [
{ key: 'id', headerName: 'Not rendered' },
{ key: 'firstName', headerName: 'First name' },
{ key: 'surname', headerName: 'Surname' },
{
key: 'age',
headerName: 'Age',
transform: ({ age }) => {
return <div style={{ textAlign: 'right' }}>{age}</div>;
},
},
{ key: 'profession', headerName: 'Profession' },
];
const indexKey = 'id';
const rows = [
{ id: 1000, firstName: 'Lauri', surname: 'Kekkonen', age: 39, profession: 'Engineer' },
{ id: 1001, firstName: 'Maria', surname: 'Sarasoja', age: 62, profession: 'Designer' },
{ id: 1002, firstName: 'Anneli', surname: 'Routa', age: 50, profession: 'Meteorologist' },
{ id: 1003, firstName: 'Osku', surname: 'Rausku', age: 18, profession: 'Mail Carrier' },
];
const [tableRows, setTableRows] = useState(rows);
const [selectedRows, setSelectedRows] = useState([]);
const deleteSelectedButton = (
<Button
key={1}
onClick={() => {
setTableRows(
tableRows.filter((row) => {
const rowId = row[indexKey];
return (
selectedRows.some((selectedRow) => {
return selectedRow === rowId;
}) === false
);
}),
);
setSelectedRows([]);
}}
style={{
flexGrow: 0,
}}
className="table-custom-action"
variant="secondary"
size="small"
iconLeft={<IconTrash />}
disabled={selectedRows.length === 0}
>
Delete selected
</Button>
);
const copySelected = (
<Button
key={2}
onClick={() => {
console.log('Copy clicked!');
}}
style={{
flexGrow: 0,
}}
className="table-custom-action"
variant="secondary"
size="small"
disabled={selectedRows.length === 0}
>
Copy selected
</Button>
);
return (
<div style={{ maxWidth: '640px' }}>
<Table
customActionButtons={[deleteSelectedButton, copySelected]}
selectedRows={selectedRows}
setSelectedRows={setSelectedRows}
checkboxSelection
cols={cols}
rows={tableRows}
heading="Employees"
id="custom-actions"
indexKey={indexKey}
renderIndexCol={false}
variant="dark"
selectAllRowsText="Select all rows"
clearSelectionsText="Clear selections"
ariaLabelCheckboxSelection="Row selection"
/>
</div>
);

Demos & API

Core

Tables in hds-core

React

Tables in hds-react

Table API