Components

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.
-->

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 layouts are not applied to tables when pages are printed.

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>

Responsive stacked table with header (directory table)

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>

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>

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 $200.02

HTML code snippet

<table class="o-table o-table--stack-on-small">
    <thead>
        <tr>
            <th>Column 1</th>
            <th>Column 2</th>
            <th  class="o-table__cell--right-align">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">$200.02</td>
        </tr>
    </tbody>
</table>
Column 1 Column 2 Column 3
Example 1 Cell A2 Cell A3
Example 2 Cell B2 Cell B3

HTML code snippet

<table class="o-table">
    <thead>
        <tr>
            <th>Column 1</th>
            <th>Column 2</th>
            <th>Column 3</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td data-label="Column 1">
                <a href="https://example.com/">Example 1</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">
                <a href="https://example.com/">Example 2</a>
            </td>
            <td data-label="Column 2">Cell B2</td>
            <td data-label="Column 3">Cell B3</td>
        </tr>
    </tbody>
</table>

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" class="cf-icon-svg cf-icon-svg--speech-bubble" viewBox="0 0 15 19"><path d="M14.032 5.286v7.276a1.112 1.112 0 0 1-1.108 1.108h-.792v1.762c0 .262-.182.362-.403.224L8.546 13.67h-6.47a1.112 1.112 0 0 1-1.108-1.108V5.286a1.112 1.112 0 0 1 1.108-1.108h10.848a1.112 1.112 0 0 1 1.108 1.108zm-1.9 1.677H2.868V8.07h9.264zm0 2.843H2.868v1.108h9.264z"/></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" class="cf-icon-svg cf-icon-svg--speech-bubble" viewBox="0 0 15 19"><path d="M14.032 5.286v7.276a1.112 1.112 0 0 1-1.108 1.108h-.792v1.762c0 .262-.182.362-.403.224L8.546 13.67h-6.47a1.112 1.112 0 0 1-1.108-1.108V5.286a1.112 1.112 0 0 1 1.108-1.108h10.848a1.112 1.112 0 0 1 1.108 1.108zm-1.9 1.677H2.868V8.07h9.264zm0 2.843H2.868v1.108h9.264z"/></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" class="cf-icon-svg cf-icon-svg--speech-bubble" viewBox="0 0 15 19"><path d="M14.032 5.286v7.276a1.112 1.112 0 0 1-1.108 1.108h-.792v1.762c0 .262-.182.362-.403.224L8.546 13.67h-6.47a1.112 1.112 0 0 1-1.108-1.108V5.286a1.112 1.112 0 0 1 1.108-1.108h10.848a1.112 1.112 0 0 1 1.108 1.108zm-1.9 1.677H2.868V8.07h9.264zm0 2.843H2.868v1.108h9.264z"/></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" class="cf-icon-svg cf-icon-svg--left" viewBox="0 0 10 19"><path d="M8.4 17.269a1.026 1.026 0 0 1-.727-.302l-6.801-6.8a1.03 1.03 0 0 1 0-1.456l6.8-6.8a1.03 1.03 0 0 1 1.456 1.455L3.055 9.439l6.073 6.073A1.03 1.03 0 0 1 8.4 17.27z"/></svg>
        Newer
    </a>

    <a class="a-btn
              m-pagination__btn-next" href="#">
        Older
        <svg xmlns="http://www.w3.org/2000/svg" class="cf-icon-svg cf-icon-svg--right" viewBox="0 0 10 19"><path d="M1.6 17.262a1.03 1.03 0 0 1-.728-1.757l6.073-6.073L.872 3.36a1.03 1.03 0 0 1 1.455-1.455l6.8 6.8a1.03 1.03 0 0 1 0 1.456l-6.8 6.8a1.025 1.025 0 0 1-.727.302z"/></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>

Latest Updates

Page last edited:
Show all details
Edit page