Skip to main content
  1. Home
  2. Table

Table

Use the table component to make information easier to compare and scan for users.

Building a table row by row

Complex tables can be built as in HTML, by declaring the caption, head, body, rows and cells.

Tables can have one caption which should be used to describe the contents of the table.

The head and body are created using the head and body slots and can each contain one or more row elements. Each row can contain multiple cell elements.

By default cell will create a <td> element. When header: true is passed in it will create a <th>. Cells values can be set using the text: argument or by passing in a block of HTML.

Input

= govuk_table do |table|
  - table.caption(size: 'm', text: 'List of Pokémon')

  - table.head do |head|
    - head.row do |row|
      - row.cell(header: true, text: 'Name')
      - row.cell(header: true, text: 'Types')
      - row.cell(header: true, text: 'Pokédex number', numeric: true)

  - table.body do |body|
    - body.row do |row|
      - row.cell(text: 'Bulbasaur')
      - row.cell(text: 'Grass, Poison')
      - row.cell(text: '1', numeric: true)

    - body.row do |row|
      - row.cell(text: 'Charmander')
      - row.cell(text: 'Fire')
      - row.cell(text: '4', numeric: true)

    - body.row do |row|
      - row.cell { 'Squirtle' }
      - row.cell { 'Water' }
      - row.cell(numeric: true) { '7' }
<%= govuk_table do |table|
table.caption(size: 'm', text: 'List of Pokémon')

table.head do |head|
head.row do |row|
row.cell(header: true, text: 'Name')
row.cell(header: true, text: 'Types')
row.cell(header: true, text: 'Pokédex number', numeric: true)

end; end; table.body do |body|
body.row do |row|
row.cell(text: 'Bulbasaur')
row.cell(text: 'Grass, Poison')
row.cell(text: '1', numeric: true)

end; body.row do |row|
row.cell(text: 'Charmander')
row.cell(text: 'Fire')
row.cell(text: '4', numeric: true)

end; body.row do |row|
row.cell { 'Squirtle' }
row.cell { 'Water' }
row.cell(numeric: true) { '7' }
end; end; end %>

Output

List of Pokémon
Name Types Pokédex number
Bulbasaur Grass, Poison 1
Charmander Fire 4
Squirtle Water 7
<table class="govuk-table">
  <caption class="govuk-table__caption govuk-table__caption--m">
    List of Pokémon
  </caption>
  <thead class="govuk-table__head">
    <tr class="govuk-table__row">
      <th class="govuk-table__header">
        Name
      </th>
      <th class="govuk-table__header">
        Types
      </th>
      <th class="govuk-table__header govuk-table__header--numeric">
        Pokédex number
      </th>
    </tr>
  </thead>
  <tbody class="govuk-table__body">
    <tr class="govuk-table__row">
      <td class="govuk-table__cell">
        Bulbasaur
      </td>
      <td class="govuk-table__cell">
        Grass, Poison
      </td>
      <td class="govuk-table__cell govuk-table__cell--numeric">
        1
      </td>
    </tr>
    <tr class="govuk-table__row">
      <td class="govuk-table__cell">
        Charmander
      </td>
      <td class="govuk-table__cell">
        Fire
      </td>
      <td class="govuk-table__cell govuk-table__cell--numeric">
        4
      </td>
    </tr>
    <tr class="govuk-table__row">
      <td class="govuk-table__cell">
        Squirtle
      </td>
      <td class="govuk-table__cell">
        Water
      </td>
      <td class="govuk-table__cell govuk-table__cell--numeric">
        7
      </td>
    </tr>
  </tbody>
</table>

Tables with header columns

To make a column of headers, pass header: true to the first cell on each row in the body.

Input

= govuk_table do |table|
  - table.caption(size: 'm', text: 'List of Pokémon generations')

  - table.head do |head|
    - head.row do |row|
      - row.cell(header: true, text: 'Generation')
      - row.cell(header: true, text: 'Years')

  - table.body do |body|
    - body.row do |row|
      - row.cell(header: true, text: 'Generation 1')
      - row.cell(text: '1996-1999')

    - body.row do |row|
      - row.cell(header: true, text: 'Generation 2')
      - row.cell(text: '1999-2002')

    - body.row do |row|
      - row.cell(header: true, text: 'Generation 3')
      - row.cell(text: '2002-2006')

    - body.row do |row|
      - row.cell(header: true, text: 'Generation 4')
      - row.cell(text: '2006-2010')
<%= govuk_table do |table|
table.caption(size: 'm', text: 'List of Pokémon generations')

table.head do |head|
head.row do |row|
row.cell(header: true, text: 'Generation')
row.cell(header: true, text: 'Years')

end; end; table.body do |body|
body.row do |row|
row.cell(header: true, text: 'Generation 1')
row.cell(text: '1996-1999')

end; body.row do |row|
row.cell(header: true, text: 'Generation 2')
row.cell(text: '1999-2002')

end; body.row do |row|
row.cell(header: true, text: 'Generation 3')
row.cell(text: '2002-2006')

end; body.row do |row|
row.cell(header: true, text: 'Generation 4')
row.cell(text: '2006-2010')
end; end; end %>

Output

List of Pokémon generations
Generation Years
Generation 1 1996-1999
Generation 2 1999-2002
Generation 3 2002-2006
Generation 4 2006-2010
<table class="govuk-table">
  <caption class="govuk-table__caption govuk-table__caption--m">
    List of Pokémon generations
  </caption>
  <thead class="govuk-table__head">
    <tr class="govuk-table__row">
      <th class="govuk-table__header">
        Generation
      </th>
      <th class="govuk-table__header">
        Years
      </th>
    </tr>
  </thead>
  <tbody class="govuk-table__body">
    <tr class="govuk-table__row">
      <th class="govuk-table__header">
        Generation 1
      </th>
      <td class="govuk-table__cell">
        1996-1999
      </td>
    </tr>
    <tr class="govuk-table__row">
      <th class="govuk-table__header">
        Generation 2
      </th>
      <td class="govuk-table__cell">
        1999-2002
      </td>
    </tr>
    <tr class="govuk-table__row">
      <th class="govuk-table__header">
        Generation 3
      </th>
      <td class="govuk-table__cell">
        2002-2006
      </td>
    </tr>
    <tr class="govuk-table__row">
      <th class="govuk-table__header">
        Generation 4
      </th>
      <td class="govuk-table__cell">
        2006-2010
      </td>
    </tr>
  </tbody>
</table>

Building a table from arrays

If you want to build a table without advanced options, you can pass in an array of arrays via the rows argument. Each element in the outer array represents a row and each element in the inner array represents a cell.

You can set the header columns explicitly by passing an array of headers using the head argument. If nothing is set, the first row will be used for headers.

Input

= govuk_table(rows: data, caption: "Pokémon species and types")
<%= govuk_table(rows: data, caption: "Pokémon species and types") %>
{
  data: [
    ["Name", "Primary type"],
    ["Weedle", "Bug"],
    ["Rattata", "Normal"],
    ["Raichu", "Electric"],
    ["Golduck", "Water"]
  ]
}

Output

Pokémon species and types
Name Primary type
Weedle Bug
Rattata Normal
Raichu Electric
Golduck Water
<table class="govuk-table">
  <caption class="govuk-table__caption govuk-table__caption--m">
    Pokémon species and types
  </caption>
  <thead class="govuk-table__head">
    <tr class="govuk-table__row">
      <th class="govuk-table__header">
        Name
      </th>
      <th class="govuk-table__header">
        Primary type
      </th>
    </tr>
  </thead>
  <tbody class="govuk-table__body">
    <tr class="govuk-table__row">
      <td class="govuk-table__cell">
        Weedle
      </td>
      <td class="govuk-table__cell">
        Bug
      </td>
    </tr>
    <tr class="govuk-table__row">
      <td class="govuk-table__cell">
        Rattata
      </td>
      <td class="govuk-table__cell">
        Normal
      </td>
    </tr>
    <tr class="govuk-table__row">
      <td class="govuk-table__cell">
        Raichu
      </td>
      <td class="govuk-table__cell">
        Electric
      </td>
    </tr>
    <tr class="govuk-table__row">
      <td class="govuk-table__cell">
        Golduck
      </td>
      <td class="govuk-table__cell">
        Water
      </td>
    </tr>
  </tbody>
</table>

Table with resized columns

By default the table will automatically size the columns to avoid wrapping. This can make tables with lots of data feel cramped.

We can avoid this by setting the width of cells. We only need to set it once per column and usually this is set in the head section.

The options available are one-quarter, one-third, one-half, two-thirds, three-quarters and full.

Input

= govuk_table do |table|
  - table.caption(size: 'm', text: 'List of Pokémon with descriptions')

  - table.head do |head|
    - head.row do |row|
      - row.cell(header: true, text: 'Name', width: 'one-third')
      - row.cell(header: true, text: 'Description')

  - table.body do |body|
    - body.row do |row|
      - row.cell(text: 'Blastoise')
      - row.cell(text: 'Blastoise is a portmanteau of "blast" and "tortoise". It is the mascot of Pokémon Blue.')

    - body.row do |row|
      - row.cell(text: 'Spearow')
      - row.cell(text: 'Spearows eat bugs in grassy areas and have to flap their short wings at high-speed to stay airborne.')

    - body.row do |row|
      - row.cell(text: 'Tangela')
      - row.cell(text: %(Blue plant vines cloak the Pokémon's identity in a tangled mass.))
<%= govuk_table do |table|
table.caption(size: 'm', text: 'List of Pokémon with descriptions')

table.head do |head|
head.row do |row|
row.cell(header: true, text: 'Name', width: 'one-third')
row.cell(header: true, text: 'Description')

end; end; table.body do |body|
body.row do |row|
row.cell(text: 'Blastoise')
row.cell(text: 'Blastoise is a portmanteau of "blast" and "tortoise". It is the mascot of Pokémon Blue.')

end; body.row do |row|
row.cell(text: 'Spearow')
row.cell(text: 'Spearows eat bugs in grassy areas and have to flap their short wings at high-speed to stay airborne.')

end; body.row do |row|
row.cell(text: 'Tangela')
row.cell(text: %(Blue plant vines cloak the Pokémon's identity in a tangled mass.))
end; end; end %>

Output

List of Pokémon with descriptions
Name Description
Blastoise Blastoise is a portmanteau of “blast” and “tortoise”. It is the mascot of Pokémon Blue.
Spearow Spearows eat bugs in grassy areas and have to flap their short wings at high-speed to stay airborne.
Tangela Blue plant vines cloak the Pokémon’s identity in a tangled mass.
<table class="govuk-table">
  <caption class="govuk-table__caption govuk-table__caption--m">
    List of Pokémon with descriptions
  </caption>
  <thead class="govuk-table__head">
    <tr class="govuk-table__row">
      <th class="govuk-table__header govuk-!-width-one-third">
        Name
      </th>
      <th class="govuk-table__header">
        Description
      </th>
    </tr>
  </thead>
  <tbody class="govuk-table__body">
    <tr class="govuk-table__row">
      <td class="govuk-table__cell">
        Blastoise
      </td>
      <td class="govuk-table__cell">
        Blastoise is a portmanteau of "blast" and "tortoise". It is the mascot of Pokémon Blue.
      </td>
    </tr>
    <tr class="govuk-table__row">
      <td class="govuk-table__cell">
        Spearow
      </td>
      <td class="govuk-table__cell">
        Spearows eat bugs in grassy areas and have to flap their short wings at high-speed to stay airborne.
      </td>
    </tr>
    <tr class="govuk-table__row">
      <td class="govuk-table__cell">
        Tangela
      </td>
      <td class="govuk-table__cell">
        Blue plant vines cloak the Pokémon's identity in a tangled mass.
      </td>
    </tr>
  </tbody>
</table>

Related information