Tables

Tables allow for the presentation of many data points grouped together in a visual way. They serve a unique purpose of allowing easy organization or comparison of more complex data than a chart or graph. They can be read either vertically (by columns) or horizontally (by rows).

Standard table

This is the default style at the large screen breakpoint. Tables are not responsive by default; see options below for responsive tables.

Table caption describing the data
Column 1 header Column 2 header Column 3 header
Row 1, column 1 Row 1, column 2 Row 1, column 3
Row 2, column 1 Row 2, column 2 Row 2, column 3
Row 3, column 1 Row 3, column 2 Row 3, column 3

HTML code snippet

<table>
    <caption>Table caption describing the data</caption>
    <thead>
        <tr>
            <th>Column 1 header</th>
            <th>Column 2 header</th>
            <th>Column 3 header</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>Row 1, column 1</td>
            <td>Row 1, column 2</td>
            <td>Row 1, column 3</td>
        </tr>
        <tr>
            <td>Row 2, column 1</td>
            <td>Row 2, column 2</td>
            <td>Row 2, column 3</td>
        </tr>
        <tr>
            <td>Row 3, column 1</td>
            <td>Row 3, column 2</td>
            <td>Row 3, column 3</td>
        </tr>
    </tbody>
</table>

<!--
Note: While th elements normally only contain raw text, they may sometimes contain heading elements when that would be beneficial to navigating a page’s content with a screenreader.
-->

Specs

Color variables for tables

Specs for default and directory table (large screens)

  • Background: Gray-05 #f7f8f9
  • Font: Avenir Next Demi-bold, all caps
  • Font-color: Black #101820
  • Font-size: 14px

Border

  • Bottom: 1px, Gray-50 #a2a3a4 on each row, including header

Cells

  • Background: Gray-05 #f7f8f9
  • Font: Avenir Next Regular Black
  • Font-color: Black #101820
  • Font-size: 16px
  • Padding: 10px

Responsive tables

Responsive tables fall into two main types: stacked, which stacks information vertically on smaller screens, and scrolling, which ensures that all the information can be accessed in its original tabular structure, even on a smaller screen.

Note that tables are not responsive unless you add one of the small screen classes detailed below. Also note that the data-label attribute must be used to label each cell in a table for small screen responsive views.

Responsive stacked table

To stack table information on smaller screens and make the information legible, use the .o-table__stack-on-small class.

Column 1 Column 2 Column 3
Row A Cell A2 Cell A3
Row B Cell B2 Cell B3
Row C Cell C2 Cell C3
Row D Cell D2 Cell D3

HTML code snippet

<table class="o-table o-table__stack-on-small">
    <thead>
        <tr>
            <th>Column 1</th>
            <th>Column 2</th>
            <th>Column 3</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td data-label="Column 1">Row A</td>
            <td data-label="Column 2">Cell A2</td>
            <td data-label="Column 3">Cell A3</td>
        </tr>
        <tr>
            <td data-label="Column 1">Row B</td>
            <td data-label="Column 2">Cell B2</td>
            <td data-label="Column 3">Cell B3</td>
        </tr>
        <tr>
            <td data-label="Column 1">Row C</td>
            <td data-label="Column 2">Cell C2</td>
            <td data-label="Column 3">Cell C3</td>
        </tr>
        <tr>
            <td data-label="Column 1">Row D</td>
            <td data-label="Column 2">Cell D2</td>
            <td data-label="Column 3">Cell D3</td>
        </tr>
    </tbody>
</table>

Specs

Default table (small screens)

Border

  • Bottom: 1px, Gray-50 #a2a3a4

Cells

  • Font: 16px Avenir Next Regular Black
  • Font-color: Black #101820
  • Labels font: 14px Avenir Next Regular, all caps
  • Labels font-color: Black #101820

Padding

  • Padding, label / content: 15px
  • Padding, content / next label: 30px
  • Padding, rule line / first label: 15px

Responsive stacked table with header (directory tables)

The directory table is a variation of the stacked table. At the small screen breakpoint, the directory table pattern uses first column data (employee name, for instance) as a way to group and label stacks of rows.

This is useful when data is read across rows, instead of down columns. For instance, contact information is comprised of a name, phone number, and email address. An event is made up of the name of the event, time, and location. You need all three pieces of data to create an understanding of the thing being shown, and the first column of data is the key to that understanding. At the small screen breakpoint, the first column (in the example shown below, employee names) become headers, and the remaining data points in the same row (phone number, email address) are stacked below.

The .o-table__entry-header-on-small class in addition to .o-table__stack-on-small class changes the first column to be styled as an entry header. This style requires both classes be added.

Employee name Phone number Email address
Andrew Able (202) XXX-XXXX aable@example.com
Betsy Bort (202) XXX-XXXX bbort@example.com
Charles Clark (202) XXX-XXXX cclark@example.com

HTML code snippet

<table class="o-table
              o-table__stack-on-small
              o-table__entry-header-on-small">
    <thead>
        <tr>
            <th>Employee name</th>
            <th>Phone number</th>
            <th>Email address</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td data-label="Employee name">Andrew Able</td>
            <td data-label="Phone number">(202) XXX-XXXX</td>
            <td data-label="Email address">aable@example.com</td>
        </tr>
        <tr>
            <td data-label="Employee name">Betsy Bort</td>
            <td data-label="Phone number">(202) XXX-XXXX</td>
            <td data-label="Email address">bbort@example.com</td>
        </tr>
        <tr>
            <td data-label="Employee name">Charles Clark</td>
            <td data-label="Phone number">(202) XXX-XXXX</td>
            <td data-label="Email address">cclark@example.com</td>
        </tr>
    </tbody>
</table>

Specs

Style for directory tables (small screens)

  • Bottom border: 1px, Gray-50 #a2a3a4 on each row
  • Font: 16px Avenir Next Regular Black
  • Font-color: Black #101820
  • Header background color: Gray-05 #f7f8f9
  • Labels font: 14px Avenir Next Regular, all caps
  • Labels font-color: Black #101820
  • Padding, column label/bottom border: 15px
  • Padding, bottom border/content: 15px
  • Padding, content / next label: 30px

Responsive table with horizontal scroll

Use a table with horizontal scroll when the data you’re presenting has more columns than will fit comfortably on the screen, and you want to ensure all information can be accessed in its original tabular structure, even on smaller screens.

The .o-table-wrapper__scrolling class must be added to the parent element of the table (by adding a wrapping div, in most cases). The table element does not need additional markup in this case. The “Comparative with horizontal scroll” style also adds striped rows to the table contained within, and remains striped on small screens (unlike the o-table__striped class, below).

Column 1 Column 2 Column 3 Column 4 Column 5 Column 6 Column 7 Column 8
Row A Cell A2 Cell A3 Cell A4 Cell A5 Cell A6 Cell A7 Cell A8
Row B Cell B2 Cell B3 Cell B4 Cell B5 Cell B6 Cell B7 Cell B8
Row C Cell C2 Cell C3 Cell C4 Cell C5 Cell C6 Cell C7 Cell C8
Row D Cell D2 Cell D3 Cell D4 Cell D5 Cell D6 Cell D7 Cell D8

HTML code snippet

<div class="o-table o-table-wrapper__scrolling">
    <table>
        <thead>
            <tr>
                <th>Column 1</th>
                <th>Column 2</th>
                <th>Column 3</th>
                <th>Column 4</th>
                <th>Column 5</th>
                <th>Column 6</th>
                <th>Column 7</th>
                <th>Column 8</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td data-label="Column 1">Row A</td>
                <td data-label="Column 2">Cell A2</td>
                <td data-label="Column 3">Cell A3</td>
                <td data-label="Column 4">Cell A4</td>
                <td data-label="Column 5">Cell A5</td>
                <td data-label="Column 6">Cell A6</td>
                <td data-label="Column 7">Cell A7</td>
                <td data-label="Column 8">Cell A8</td>
            </tr>
            <tr>
                <td data-label="Column 1">Row B</td>
                <td data-label="Column 2">Cell B2</td>
                <td data-label="Column 3">Cell B3</td>
                <td data-label="Column 4">Cell B4</td>
                <td data-label="Column 5">Cell B5</td>
                <td data-label="Column 6">Cell B6</td>
                <td data-label="Column 7">Cell B7</td>
                <td data-label="Column 8">Cell B8</td>
            </tr>
            <tr>
                <td data-label="Column 1">Row C</td>
                <td data-label="Column 2">Cell C2</td>
                <td data-label="Column 3">Cell C3</td>
                <td data-label="Column 4">Cell C4</td>
                <td data-label="Column 5">Cell C5</td>
                <td data-label="Column 6">Cell C6</td>
                <td data-label="Column 7">Cell C7</td>
                <td data-label="Column 8">Cell C8</td>
            </tr>
            <tr>
                <td data-label="Column 1">Row D</td>
                <td data-label="Column 2">Cell D2</td>
                <td data-label="Column 3">Cell D3</td>
                <td data-label="Column 4">Cell D4</td>
                <td data-label="Column 5">Cell D5</td>
                <td data-label="Column 6">Cell D6</td>
                <td data-label="Column 7">Cell D7</td>
                <td data-label="Column 8">Cell D8</td>
            </tr>
        </tbody>
    </table>
</div>

Specs

Styles for scrolling tables

  • Border: 1px, Gray-50 #a2a3a4 around the scrolling table
  • Alternate row striping: Grey-05 #f7f8f9

Variations

Striped table

Striping is useful to help the eye track across table rows. Use striping for tables that have more than five columns, or for tables with rows that are difficult to follow across the full width of the table.

The .o-table__striped class adds stripes to the table rows. This striping is not visible on small screens.

Column 1 Column 2 Column 3
Row A Cell A2 Cell A3
Row B Cell B2 Cell B3
Row C Cell C2 Cell C3
Row D Cell D2 Cell D3

HTML code snippet

<table class="o-table o-table__striped">
    <thead>
        <tr>
            <th>Column 1</th>
            <th>Column 2</th>
            <th>Column 3</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td data-label="Column 1">Row A</td>
            <td data-label="Column 2">Cell A2</td>
            <td data-label="Column 3">Cell A3</td>
        </tr>
        <tr>
            <td data-label="Column 1">Row B</td>
            <td data-label="Column 2">Cell B2</td>
            <td data-label="Column 3">Cell B3</td>
        </tr>
        <tr>
            <td data-label="Column 1">Row C</td>
            <td data-label="Column 2">Cell C2</td>
            <td data-label="Column 3">Cell C3</td>
        </tr>
        <tr>
            <td data-label="Column 1">Row D</td>
            <td data-label="Column 2">Cell D2</td>
            <td data-label="Column 3">Cell D3</td>
        </tr>
    </tbody>
</table>

Right-aligned table

Right-align columns of numbers when they’re quantities (counts, dollar amounts, percentages) or ordinals (ranks, item numbers). Use the .o-table_cell__right-align class on a td.

Left-align columns of numbers when they’re nominal (ZIP codes, room numbers) or non-numeric values (names, phrases).

Column 1 Column 2 Right-aligned column
Row A Cell A2 $1.00
Row B Cell B2 $2.00

HTML code snippet

<table class="o-table o-table__stack-on-small">
    <thead>
        <tr>
            <th>Column 1</th>
            <th>Column 2</th>
            <th>Right-aligned column</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td data-label="Column 1">Row A</td>
            <td data-label="Column 2">Cell A2</td>
            <td data-label="Right-aligned column" class="o-table_cell__right-align">$1.00</td>
        </tr>
        <tr>
            <td data-label="Column 1">Row B</td>
            <td data-label="Column 2">Cell B2</td>
            <td data-label="Right-aligned column" class="o-table_cell__right-align">$2.00</td>
        </tr>
    </tbody>
</table>

Specs

  • Alternate row background: Grey-05 #F8F8F8

Table with row links

The .o-table_cell__row-links class is added to a table to enable highlighting and hyperlinking rows which contain links.

Sortable table

Sorting allows users to reorder the contents of a table by a sortable column of their choice. See the Behavior section for more information.

Add the .o-table__sortable class to a table to make it sortable. To sort by a specific column, add a button to the th of the column. The use of a button helps address accessibility concerns.

Agency
Alpha English 2.6 mi
Beta English, Spanish 1.4 mi
Gamma English, French, Spanish 1.4 mi
Delta English, Spanish 3.2 mi
Epsilon English 1.6 mi
Zeta English, Spanish 1.2 mi
Eta English 11.1 mi

HTML code snippet

<table class="o-table o-table__sortable">
    <thead>
        <tr>
            <th>
                Agency
            </th>
            <th>
              <button class="sortable">
                Languages
              </button>
            </th>
            <th>
              <button class="sortable sorted-up" data-sort_type="number">
                Distance
              </button>
            </th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>
                Alpha
            </td>
            <td data-label="Languages">
                English
            </td>
            <td data-label="Distance">
                2.6 mi
            </td>
        </tr>
        <tr>
            <td>
                Beta
            </td>
            <td data-label="Languages">
                English, Spanish
            </td>
            <td data-label="Distance">
                1.4 mi
            </td>
        </tr>
        <tr>
            <td>
                Gamma
            </td>
            <td data-label="Languages">
                English, French, Spanish
            </td>
            <td data-label="Distance">
                1.4 mi
            </td>
        </tr>
        <tr>
            <td>
                Delta
            </td>
            <td data-label="Languages">
                English, Spanish
            </td>
            <td data-label="Distance">
                3.2 mi
            </td>
        </tr>
        <tr>
            <td>
                Epsilon
            </td>
            <td data-label="Languages">
                English
            </td>
            <td data-label="Distance">
                1.6 mi
            </td>
        </tr>
        <tr>
            <td>
                Zeta
            </td>
            <td data-label="Languages">
                English, Spanish
            </td>
            <td data-label="Distance">
                1.2 mi
            </td>
        </tr>
        <tr>
            <td>
                Eta
            </td>
            <td data-label="Languages">
                English
            </td>
            <td data-label="Distance">
                11.1 mi
            </td>
        </tr>
    </tbody>
</table>

Implementation details

Making a table sortable

By adding the .o-table__sortable class to a table, the table becomes sortable. To allow the table to be sorted by a column, add a button to the th of the column like so:

…
<button class="sortable">
    Column Name
</button>
…

The use of a button helps address certain accessibility concerns.

Sorting type

To sort properly, the type of the data can be specified. By default, the column’s values will be sorted as string values. However, the column can be specifically sorted by number values (in which case, the cell’s contents are stripped of non-numeric characters, then sorted by the resulting number). To see an example, the sample table later in this document sorts the “Distance” column by number value.

To sort by number value, add the data-sort_type="number" attribute to the sorting button:

<table class="o-table o-table__sortable">
    …
        <th>
            <button class="sortable" data-sort_type="number">Column Name</button>
        </th>
    …
</table>

Sorting table on page load

To sort the table on page load, use the .sorted-up and .sorted-down classes:

<table class="o-table o-table__sortable">
    …
        <th>
            <button class="sortable sorted-up">Column Name</button>
        </th>
    …
</table>
  • The class .sorted-up refers to a sort from smallest to greatest (first to last), and .sorted-down refers to a sort from greatest to smallest (last to first). These classes are added to the th when sorting occurs.
  • Please note the importance of defining a thead and tbody to preserve the table’s header through sorting operations.

Pagination

Tables with over 20 rows can be paired with pagination.

image showing a table with pagination

HTML code snippet

<!--Code from Design Manual
<table class="o-table o-table__stack-on-small">
    <thead>
        <tr>
            <th class="u-w20pct">
                Type
            </th>
            <th class="u-w55pct">
                Title
            </th>
            <th class="u-w25pct">
                Date
            </th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td data-label="Type">
                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 825.1 1200" class="cf-icon-svg"><path d="M795.1 263.9H30c-16.5 0-30 13.5-30 30v539.5c0 16.5 13.5 30 30 30h95.3v144.5c0 17.7 8.5 31.8 22.7 37.7 4.2 1.8 8.7 2.7 13.3 2.7 10.3 0 20.6-4.6 29.4-13.3l171.5-171.6h432.9c16.5 0 30-13.5 30-30V293.9c-.1-16.6-13.5-30-30-30zm-90 409H120v-60h585.1v60zm0-158.6H120v-60h585.1v60z"></path></svg> Blog
            </td>
            <td data-label="Title">
                Three things to do before closing
            </td>
            <td data-label="Date">
                AUG 5, 2015
            </td>
        </tr>
        <tr>
            <td data-label="Type">
                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 975.1 1200" class="cf-icon-svg"><path d="M907.2 277L151 466.7H30c-16.5 0-30 13.5-30 30v197.5c0 16.5 13.5 30 30 30h121l93 23.3-20.6 82.4c-8 32.1 11.5 64.7 43.7 72.8l194.8 48.7c32.1 8 64.7-11.5 72.8-43.7l20.5-82.1 352.1 88.3c37.3 9.4 67.9-14.5 67.9-53v-531c-.1-38.4-30.7-62.3-68-52.9zM476.4 893l-194.7-48.6s0-.1-.1-.1l20.6-82.3 194.7 49-20.5 82z"></path></svg> News
            </td>
            <td data-label="Title">
                Electronic Mortgage Closings Can Benefit Consumers
            </td>
            <td data-label="Date">
                AUG 5, 2015
            </td>
        </tr>
    <tr>
            <td colspan="3" style="text-align: center; font-weight: bold;">
                (18 more rows)
            </td>
        </tr>
        <tr>
            <td data-label="Type">
                <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 825.1 1200" class="cf-icon-svg"><path d="M795.1 263.9H30c-16.5 0-30 13.5-30 30v539.5c0 16.5 13.5 30 30 30h95.3v144.5c0 17.7 8.5 31.8 22.7 37.7 4.2 1.8 8.7 2.7 13.3 2.7 10.3 0 20.6-4.6 29.4-13.3l171.5-171.6h432.9c16.5 0 30-13.5 30-30V293.9c-.1-16.6-13.5-30-30-30zm-90 409H120v-60h585.1v60zm0-158.6H120v-60h585.1v60z"></path></svg> Blog
            </td>
            <td data-label="Title">
                National Day of Civic Hacking 2015
            </td>
            <td data-label="Date">
                JUL 29, 2015
            </td>
        </tr>
    </tbody>
</table>

<nav class="m-pagination" role="navigation" aria-label="Pagination">
    <a class="a-btn
              a-btn__disabled
              m-pagination_btn-prev">
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 559.6 1200" class="cf-icon-svg"><path d="M494.5 1090.7c-17.3 0-33.8-6.8-46-19L19 642.1c-25.4-25.4-25.4-66.5 0-91.9l429.5-429.5c25.6-25.1 66.8-24.8 91.9.8 24.8 25.3 24.8 65.8 0 91.1L156.9 596.2l383.6 383.6c25.4 25.4 25.4 66.5.1 91.9-12.3 12.2-28.8 19-46.1 19z"></path></svg>
        Newer
    </a>

    <a class="a-btn
              m-pagination_btn-next" href="#">
        Older
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 559.6 1200" class="cf-icon-svg"><path d="M65.1 1090.2c-35.9 0-65-29-65.1-64.9 0-17.3 6.8-33.9 19.1-46.1l383.6-383.5L19.1 212.2c-25.1-25.6-24.8-66.8.9-92 25.3-24.8 65.8-24.8 91.1 0l429.5 429.5c25.4 25.4 25.4 66.5 0 91.9L111 1071.2c-12.1 12.2-28.7 19.1-45.9 19z"></path></svg>
    </a>
    <form class="m-pagination_form" action="#">
        <label class="m-pagination_label" for="m-pagination_current-page">
            Page
            <span class="u-visually-hidden">
                number out of 3 total pages
            </span>
            <input class="m-pagination_current-page" id="m-pagination_current-page" name="page" type="number" min="1" max="3" inputmode="numeric" value="1">
            of 3
        </label>
        <button class="a-btn
                       a-btn__link
                       m-pagination_submit-btn" id="pagination_submit" type="submit">Go</button>
    </form>
</nav>
-->

Fixed-width column tables

Column widths are automatically set by browsers by default. If needed, some or all columns can be set to specific widths instead to accommodate longer data or labels.

Fixed-width columns at the 600 px breakpoint and less lose their custom widths and expand to full width. This is the same responsive pattern used for default tables at small screens.

County Lien status Active?
Abbeville Secured Yes
Abbey Secured No

HTML code snippet

<table class="o-table o-table__stack-on-small">
    <thead>
        <tr>
            <th class="u-w20pct">
                County
            </th>
            <th class="u-w60pct">
                Lien status
            </th>
            <th class="u-w20pct">
                Active?
            </th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td data-label="County">
                Abbeville
            </td>
            <td data-label="Lien status">
                Secured
            </td>
            <td data-label="Active?">
                Yes
            </td>
        </tr>
        <tr>
            <td data-label="County">
                Abbey
            </td>
            <td data-label="Lien status">
                Secured
            </td>
            <td data-label="Active?">
                No
            </td>
        </tr>
    </tbody>
</table>