Any table that has clear and understandable information is successful. Our table styles strive for flexibility, so there are several options to choose from. However, each follows a similar structure and pattern, with clear headings with high contrast, proper spacing between rows, and easy to read and large text to display information.

Tables can be left or center aligned with the column header. Our tables support a variety of actions, both individual and bulk. It’s important to note that we use zebra striping only for tables that have no action.

Examples

Due to the widespread use of tables across third-party widgets like calendars and date pickers, we've designed our tables to be opt-in. Just add the base class `.table` to any `table`, then extend with custom styles or our various included modifier classes.

Using the most basic table markup, here's how `.table`-based tables look in Cirrus. All table styles are inherited in Cirrus, meaning any nested tables will be styled in the same manner as the parent.

# First Last Handle
1 Mark Otto @mdo
2 Jacob Thornton @fat
3 Larry the Bird @twitter
<div class="table-container table-dark">
  <table class="table table-striped">
    <thead>
    <tr>
      <th scope="col">#</th>
      <th scope="col">First</th>
      <th scope="col">Last</th>
      <th scope="col">Handle</th>
    </tr>
    </thead>
    <tbody>
    <tr>
      <th scope="row">1</th>
      <td>Mark</td>
      <td>Otto</td>
      <td>@mdo</td>
    </tr>
    <tr>
      <th scope="row">2</th>
      <td>Jacob</td>
      <td>Thornton</td>
      <td>@fat</td>
    </tr>
    <tr>
      <th scope="row">3</th>
      <td>Larry</td>
      <td>the Bird</td>
      <td>@twitter</td>
    </tr>
    </tbody>
  </table>
</div><!-- end table container -->

Table head options

Use the modifier classes `.thead-light`, `.thead-dark` to change the header appearance.

Dark

# First Last Handle
1 Mark Otto @mdo
2 Jacob Thornton @fat
3 Larry the Bird @twitter

Light

# First Last Handle
1 Mark Otto @mdo
2 Jacob Thornton @fat
3 Larry the Bird @twitter

Clean

# First Last Handle
1 Mark Otto @mdo
2 Jacob Thornton @fat
3 Larry the Bird @twitter
<h3>Dark</h3>
<div class="table-container table-dark mb-5">
  <table class="table">
    <thead>
    <tr>
      <th scope="col">#</th>
      <th scope="col">First</th>
      <th scope="col">Last</th>
      <th scope="col">Handle</th>
    </tr>
    </thead>
    <tbody>
    <tr>
      <th scope="row">1</th>
      <td>Mark</td>
      <td>Otto</td>
      <td>@mdo</td>
    </tr>
    <tr>
      <th scope="row">2</th>
      <td>Jacob</td>
      <td>Thornton</td>
      <td>@fat</td>
    </tr>
    <tr>
      <th scope="row">3</th>
      <td>Larry</td>
      <td>the Bird</td>
      <td>@twitter</td>
    </tr>
    </tbody>
  </table>
</div><!-- end table container -->

<h3>Light</h3>
<div class="table-container table-light mb-5">
  <table class="table">
    <thead>
    <tr>
      <th scope="col">#</th>
      <th scope="col">First</th>
      <th scope="col">Last</th>
      <th scope="col">Handle</th>
    </tr>
    </thead>
    <tbody>
    <tr>
      <th scope="row">1</th>
      <td>Mark</td>
      <td>Otto</td>
      <td>@mdo</td>
    </tr>
    <tr>
      <th scope="row">2</th>
      <td>Jacob</td>
      <td>Thornton</td>
      <td>@fat</td>
    </tr>
    <tr>
      <th scope="row">3</th>
      <td>Larry</td>
      <td>the Bird</td>
      <td>@twitter</td>
    </tr>
    </tbody>
  </table>
</div><!-- end table container -->

<h3>Clean</h3>
<table class="table">
  <thead>
  <tr>
    <th scope="col">#</th>
    <th scope="col">First</th>
    <th scope="col">Last</th>
    <th scope="col">Handle</th>
  </tr>
  </thead>
  <tbody>
  <tr>
    <th scope="row">1</th>
    <td>Mark</td>
    <td>Otto</td>
    <td>@mdo</td>
  </tr>
  <tr>
    <th scope="row">2</th>
    <td>Jacob</td>
    <td>Thornton</td>
    <td>@fat</td>
  </tr>
  <tr>
    <th scope="row">3</th>
    <td>Larry</td>
    <td>the Bird</td>
    <td>@twitter</td>
  </tr>
  </tbody>
</table>

Striped rows

Striping on tables should always be done through CSS. This allows us to filter, modify, add, remove, and change rows without causing weird visual issues.

Use `.table-striped` to add zebra-striping to any table row within the `tbody`.

# First Last Handle
1 Mark Otto @mdo
2 Jacob Thornton @fat
3 Larry the Bird @twitter
<table class="table table-striped">
  <thead>
    <tr>
      <th scope="col">#</th>
      <th scope="col">First</th>
      <th scope="col">Last</th>
      <th scope="col">Handle</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">1</th>
      <td>Mark</td>
      <td>Otto</td>
      <td>@mdo</td>
    </tr>
    <tr>
      <th scope="row">2</th>
      <td>Jacob</td>
      <td>Thornton</td>
      <td>@fat</td>
    </tr>
    <tr>
      <th scope="row">3</th>
      <td>Larry</td>
      <td>the Bird</td>
      <td>@twitter</td>
    </tr>
  </tbody>
</table>

Bordered table

Add `.table-bordered` for borders on all sides of the table and cells.

# First Last Handle
1 Mark Otto @mdo
2 Jacob Thornton @fat
3 Larry the Bird @twitter
<table class="table table-bordered">
  <thead>
    <tr>
      <th scope="col">#</th>
      <th scope="col">First</th>
      <th scope="col">Last</th>
      <th scope="col">Handle</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">1</th>
      <td>Mark</td>
      <td>Otto</td>
      <td>@mdo</td>
    </tr>
    <tr>
      <th scope="row">2</th>
      <td>Jacob</td>
      <td>Thornton</td>
      <td>@fat</td>
    </tr>
    <tr>
      <th scope="row">3</th>
      <td colspan="2">Larry the Bird</td>
      <td>@twitter</td>
    </tr>
  </tbody>
</table>

Borderless table

Add `.table-borderless` for a table without borders.

# First Last Handle
1 Mark Otto @mdo
2 Jacob Thornton @fat
3 Larry the Bird @twitter
<table class="table table-borderless">
  <thead>
    <tr>
      <th scope="col">#</th>
      <th scope="col">First</th>
      <th scope="col">Last</th>
      <th scope="col">Handle</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">1</th>
      <td>Mark</td>
      <td>Otto</td>
      <td>@mdo</td>
    </tr>
    <tr>
      <th scope="row">2</th>
      <td>Jacob</td>
      <td>Thornton</td>
      <td>@fat</td>
    </tr>
    <tr>
      <th scope="row">3</th>
      <td colspan="2">Larry the Bird</td>
      <td>@twitter</td>
    </tr>
  </tbody>
</table>

Hoverable rows

Add `.table-hover` to enable a hover state on table rows within a `tbody`.

# First Last Handle
1 Mark Otto @mdo
2 Jacob Thornton @fat
3 Larry the Bird @twitter
<table class="table table-hover">
  <thead>
    <tr>
      <th scope="col">#</th>
      <th scope="col">First</th>
      <th scope="col">Last</th>
      <th scope="col">Handle</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">1</th>
      <td>Mark</td>
      <td>Otto</td>
      <td>@mdo</td>
    </tr>
    <tr>
      <th scope="row">2</th>
      <td>Jacob</td>
      <td>Thornton</td>
      <td>@fat</td>
    </tr>
    <tr>
      <th scope="row">3</th>
      <td colspan="2">Larry the Bird</td>
      <td>@twitter</td>
    </tr>
  </tbody>
</table>

Small table

Add `.table-sm` to make tables more compact by cutting cell padding in half.

# First Last Handle
1 Mark Otto @mdo
2 Jacob Thornton @fat
3 Larry the Bird @twitter
<table class="table table-sm">
  <thead>
    <tr>
      <th scope="col">#</th>
      <th scope="col">First</th>
      <th scope="col">Last</th>
      <th scope="col">Handle</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">1</th>
      <td>Mark</td>
      <td>Otto</td>
      <td>@mdo</td>
    </tr>
    <tr>
      <th scope="row">2</th>
      <td>Jacob</td>
      <td>Thornton</td>
      <td>@fat</td>
    </tr>
    <tr>
      <th scope="row">3</th>
      <td colspan="2">Larry the Bird</td>
      <td>@twitter</td>
    </tr>
  </tbody>
</table>
Conveying meaning to assistive technologies

Using color to add meaning only provides a visual indication, which will not be conveyed to users of assistive technologies – such as screen readers. Ensure that information denoted by the color is either obvious from the content itself (e.g. the visible text), or is included through alternative means, such as additional text hidden with the .sr-only class.

Captions

A `caption` functions like a heading for a table. It helps users with screen readers to find a table and understand what it's about and decide if they want to read it.

List of users
# First Last Handle
1 Mark Otto @mdo
2 Jacob Thornton @fat
3 Larry the Bird @twitter
<table class="table">
  <caption>List of users</caption>
  <thead>
    <tr>
      <th scope="col">#</th>
      <th scope="col">First</th>
      <th scope="col">Last</th>
      <th scope="col">Handle</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">1</th>
      <td>Mark</td>
      <td>Otto</td>
      <td>@mdo</td>
    </tr>
    <tr>
      <th scope="row">2</th>
      <td>Jacob</td>
      <td>Thornton</td>
      <td>@fat</td>
    </tr>
    <tr>
      <th scope="row">3</th>
      <td>Larry</td>
      <td>the Bird</td>
      <td>@twitter</td>
    </tr>
  </tbody>
</table>

Interactive Table

Since tables will be custom per project, there are no "pre-build" functionality of the below table. Clicking the buttons will only show the UI and not change the structure.

Important! If you use an interactive table that submits data somewhere through AJAX/Fetch, then the table should be wrapped in a form tag to be as semantic as possible.

Choose your option First Last Handle Delete this row
Mark Otto @mdo
Jacob Thornton @fat
Larry the Bird @twitter
<form>
  <div class="table-container table-dark mb-2">
  <table class="table table-striped custom-table-interactive">
    <thead>
    <tr>
      <th scope="col" style="width: 60px"><span class="sr-only">Choose your option</span></th>
      <th scope="col">First</th>
      <th scope="col">Last</th>
      <th scope="col">Handle</th>
      <th scope="col" style="width: 40px"><span class="sr-only">Delete this row</span></th>
    </tr>
    </thead>
    <tbody>
    <tr>
      <th class="align-middle" scope="row">
        <div class="custom-control custom-checkbox ml-2">
          <input type="checkbox" class="custom-control-input" id="customCheck1">
          <label class="custom-control-label" for="customCheck1"><span class="sr-only">Select this row</span></label>
        </div>
      </th>
      <td class="align-middle">Mark</td>
      <td class="align-middle">Otto</td>
      <td class="align-middle">@mdo</td>
      <td class="align-middle"><button class="btn btn-icon custom-btn-delete-row" type="button" aria-label="Delete Row"><i class="far fa-trash-alt"></i></button></td>
    </tr>
    <tr>
      <th class="align-middle" scope="row">
        <div class="custom-control custom-checkbox ml-2">
          <input type="checkbox" class="custom-control-input" id="customCheck2">
          <label class="custom-control-label" for="customCheck2"><span class="sr-only">Select this row</span></label>
        </div>
      </th>
      <td class="align-middle">Jacob</td>
      <td class="align-middle">Thornton</td>
      <td class="align-middle">@fat</td>
      <td class="align-middle"><button class="btn btn-icon custom-btn-delete-row" type="button" aria-label="Delete Row"><i class="far fa-trash-alt"></i></button></td>
    </tr>
    <tr>
      <th class="align-middle" scope="row">
        <div class="custom-control custom-checkbox ml-2">
          <input type="checkbox" class="custom-control-input" id="customCheck3">
          <label class="custom-control-label" for="customCheck3"><span class="sr-only">Select this row</span></label>
        </div>
      </th>
      <td class="align-middle">Larry</td>
      <td class="align-middle">the Bird</td>
      <td class="align-middle">@twitter</td>
      <td class="align-middle"><button class="btn btn-icon custom-btn-delete-row" type="button" aria-label="Delete Row"><i class="far fa-trash-alt"></i></button></td>
    </tr>
    </tbody>
  </table>
  </div><!-- end table container -->

  <div class="dropdown">
    <button class="btn btn-secondary" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Bulk Actions <i class="far fa-chevron-down"></i></button>
    <div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
      <button class="dropdown-item" type="button"><i class="fal fa-pencil-alt mr-1"></i> Edit</button>
      <button class="dropdown-item" type="button"><i class="fal fa-copy mr-1"></i> Copy</button>
      <button class="dropdown-item" type="button"><i class="fal fa-trash-alt mr-1"></i> Delete</button>
    </div>
  </div>
</form>

Responsive tables

Mobile tables are extremely dependent upon the information being displayed. We use a card structure, as exemplified in the Cards & Tiles section. Make sure that destructive actions are away from a user would be doing a majority of their scrolling, such as the center of the screen. However, certain designs may have to make concessions based on content, so use your best judgment when laying out a table for mobile.

If you can’t or don’t want to use cards, make sure to clearly separate rows to draw a distinction between different rows of information.

This is an example of what a table could reduce down to. Every row has a data-title attribute that has the name of the column header. This is then shown when the table reduces down to a specific size. This layout does not exist in the core code and is for demonstration purposes only.

Responsive Table CSS Example

This isn't using media queries but could easily be dropped in one using the built in grid system. Boxes should be arranged to fit their appropriate content. Work closely with the designers when building mobile versions of table to make sure that all data is accounted for.

  #custom-responsive-table thead {
    display: none;
  }

  #custom-responsive-table tbody tr {
    display: block;
    position: relative;
    padding-left: 60px;
    padding-right: 60px;
  }

  #custom-responsive-table tbody th,
  #custom-responsive-table tbody td {
    display: inline-block;
    width: 100%;
  }

  #custom-responsive-table.size576 tbody th,
  #custom-responsive-table.size576 tbody td {
    width: 49%;
  }

  #custom-responsive-table.size768 tbody th,
  #custom-responsive-table.size768 tbody td {
    width: 31%;
  }

  #custom-responsive-table tbody tr th {
    position: absolute;
    top: calc(50% - 24px);
    left: 0;
    width: auto;
  }

  #custom-responsive-table tbody tr td:last-of-type {
    position: absolute;
    top: calc(50% - 32px);
    right: 0;
    width: auto;
  }

  #custom-responsive-table tbody tr td::before {
    content: attr(data-title);
    display: block;
    font-weight: bold;
  }
  

Mobile Screen Size Magic Toggle

(MSSMT for short)

Choose your option First Last Handle Delete this row
Mark Otto @mdo 1/2/2000 Heating $500,000
Jacob Thornton @fat 2/4/2004 Cooling $1,000,000
Larry the Bird @twitter 4/6/2008 Neither $1,000
  <form>
    <div class="table-container table-dark mb-2">
    <table id="custom-responsive-table" class="table table-striped">
      <thead>
      <tr>
        <th scope="col" style="width: 60px"><span class="sr-only">Choose your option</span></th>
        <th scope="col">First</th>
        <th scope="col">Last</th>
        <th scope="col">Handle</th>
        <th scope="col" style="width: 40px"><span class="sr-only">Delete this row</span></th>
      </tr>
      </thead>
      <tbody>
      <tr>
        <th class="align-middle" scope="row">
          <div class="custom-control custom-checkbox ml-2">
            <input type="checkbox" class="custom-control-input" id="customCheck10">
            <label class="custom-control-label" for="customCheck10"><span class="sr-only">Select this row</span></label>
          </div>
        </th>
        <td class="align-middle" data-title="First Name">Mark</td>
        <td class="align-middle" data-title="Last Name">Otto</td>
        <td class="align-middle" data-title="Handle">@mdo</td>
        <td class="align-middle" data-title="Birthday">1/2/2000</td>
        <td class="align-middle" data-title="System">Heating</td>
        <td class="align-middle" data-title="Credit Line">$500,000</td>
        <td class="align-middle"><button class="btn btn-icon" type="button" aria-label="Delete Row"><i class="far fa-trash-alt"></i></button></td>
      </tr>
      <tr>
        <th class="align-middle" scope="row">
          <div class="custom-control custom-checkbox ml-2">
            <input type="checkbox" class="custom-control-input" id="customCheck20">
            <label class="custom-control-label" for="customCheck20"><span class="sr-only">Select this row</span></label>
          </div>
        </th>
        <td class="align-middle" data-title="First Name">Jacob</td>
        <td class="align-middle" data-title="Last Name">Thornton</td>
        <td class="align-middle" data-title="Handle">@fat</td>
        <td class="align-middle" data-title="Birthday">2/4/2004</td>
        <td class="align-middle" data-title="System">Cooling</td>
        <td class="align-middle" data-title="Credit Line">$1,000,000</td>
        <td class="align-middle"><button class="btn btn-icon" type="button" aria-label="Delete Row"><i class="far fa-trash-alt"></i></button></td>
      </tr>
      <tr>
        <th class="align-middle" scope="row">
          <div class="custom-control custom-checkbox ml-2">
            <input type="checkbox" class="custom-control-input" id="customCheck30">
            <label class="custom-control-label" for="customCheck30"><span class="sr-only">Select this row</span></label>
          </div>
        </th>
        <td class="align-middle" data-title="First Name">Larry</td>
        <td class="align-middle" data-title="Last Name">the Bird</td>
        <td class="align-middle" data-title="Handle">@twitter</td>
        <td class="align-middle" data-title="Birthday">4/6/2008</td>
        <td class="align-middle" data-title="System">Neither</td>
        <td class="align-middle" data-title="Credit Line">$1,000</td>
        <td class="align-middle"><button class="btn btn-icon" type="button" aria-label="Delete Row"><i class="far fa-trash-alt"></i></button></td>
      </tr>
      </tbody>
    </table>
    </div><!-- end table container -->
  </form>
  
Vertical clipping/truncation

Responsive tables make use of `overflow-y: hidden`, which clips off any content that goes beyond the bottom or top edges of the table. In particular, this can clip off dropdown menus and other third-party widgets.

Scrolling responsive - a last resort

Responsive tables allow tables to be scrolled horizontally with ease. Make any table responsive across all viewports by wrapping a `.table` with `.table-responsive`. Or, pick a maximum breakpoint with which to have a responsive table up to by using `.table-responsive{-sm|-md|-lg|-xl}`.

Across every breakpoint, use `.table-responsive` for horizontally scrolling tables.

# Heading Heading Heading Heading Heading Heading Heading Heading Heading
1 Cell Cell Cell Cell Cell Cell Cell Cell Cell
2 Cell Cell Cell Cell Cell Cell Cell Cell Cell
3 Cell Cell Cell Cell Cell Cell Cell Cell Cell
<div class="table-responsive">
  <table class="table">
    ...
  </table>
</div>

Breakpoint specific

Use `.table-responsive{-sm|-md|-lg|-xl}` as needed to create responsive tables up to a particular breakpoint. From that breakpoint and up, the table will behave normally and not scroll horizontally.

These tables may appear broken until their responsive styles apply at specific viewport widths.

# Heading Heading Heading Heading Heading Heading Heading Heading
1 Cell Cell Cell Cell Cell Cell Cell Cell
2 Cell Cell Cell Cell Cell Cell Cell Cell
3 Cell Cell Cell Cell Cell Cell Cell Cell
<div class="table-responsive-sm">
  <table class="table">
    ...
  </table>
</div>
# Heading Heading Heading Heading Heading Heading Heading Heading
1 Cell Cell Cell Cell Cell Cell Cell Cell
2 Cell Cell Cell Cell Cell Cell Cell Cell
3 Cell Cell Cell Cell Cell Cell Cell Cell
<div class="table-responsive-md">
  <table class="table">
    ...
  </table>
</div>
# Heading Heading Heading Heading Heading Heading Heading Heading
1 Cell Cell Cell Cell Cell Cell Cell Cell
2 Cell Cell Cell Cell Cell Cell Cell Cell
3 Cell Cell Cell Cell Cell Cell Cell Cell
<div class="table-responsive-lg">
  <table class="table">
    ...
  </table>
</div>
# Heading Heading Heading Heading Heading Heading Heading Heading
1 Cell Cell Cell Cell Cell Cell Cell Cell
2 Cell Cell Cell Cell Cell Cell Cell Cell
3 Cell Cell Cell Cell Cell Cell Cell Cell
<div class="table-responsive-xl">
  <table class="table">
    ...
  </table>
</div>
# Heading Heading Heading Heading Heading Heading Heading Heading
1 Cell Cell Cell Cell Cell Cell Cell Cell
2 Cell Cell Cell Cell Cell Cell Cell Cell
3 Cell Cell Cell Cell Cell Cell Cell Cell
<div class="table-responsive-xxl">
  <table class="table">
    ...
  </table>
</div>