Table

Tables lay out rows of data, with variants for responsive, sortable, selectable and sticky-header tables.

Basic table

The basic table design has light padding and the presented data is separated with horizontal dividers. It helps provide users with all the necessary information, without overwhelming them with visuals.

The .table class adds basic styling to a table:

NameTitleEmailRole
Paweł KunaUI Designer, Training[email protected]UserEdit
Jeffie LewzeyChemical Engineer, Support[email protected]AdminEdit
Mallory HulmeGeologist IV, Support[email protected]UserEdit
Dunn SlaneResearch Nurse, Sales[email protected]OwnerEdit
Emmy LevetVP Product Management, Accounting[email protected]AdminEdit
<div class="table-responsive">
  <table class="table table-vcenter">
    <thead>
      <tr>
        <th>Name</th>
        <th>Title</th>
        <th>Email</th>
        <th>Role</th>
        <th class="w-1"></th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>Paweł Kuna</td>
        <td class="text-secondary">UI Designer, Training</td>
        <td class="text-secondary">
          <a href="#" class="text-reset">
            <a href="mailto:[email protected]">[email protected]</a>
          </a>
        </td>
        <td class="text-secondary">User</td>
        <td>
          <a href="#">Edit</a>
        </td>
      </tr>
      <tr>
        <td>Jeffie Lewzey</td>
        <td class="text-secondary">Chemical Engineer, Support</td>
        <td class="text-secondary">
          <a href="#" class="text-reset">
            <a href="mailto:[email protected]">[email protected]</a>
          </a>
        </td>
        <td class="text-secondary">Admin</td>
        <td>
          <a href="#">Edit</a>
        </td>
      </tr>
      <tr>
        <td>Mallory Hulme</td>
        <td class="text-secondary">Geologist IV, Support</td>
        <td class="text-secondary">
          <a href="#" class="text-reset">
            <a href="mailto:[email protected]">[email protected]</a>
          </a>
        </td>
        <td class="text-secondary">User</td>
        <td>
          <a href="#">Edit</a>
        </td>
      </tr>
      <tr>
        <td>Dunn Slane</td>
        <td class="text-secondary">Research Nurse, Sales</td>
        <td class="text-secondary">
          <a href="#" class="text-reset">
            <a href="mailto:[email protected]">[email protected]</a>
          </a>
        </td>
        <td class="text-secondary">Owner</td>
        <td>
          <a href="#">Edit</a>
        </td>
      </tr>
      <tr>
        <td>Emmy Levet</td>
        <td class="text-secondary">VP Product Management, Accounting</td>
        <td class="text-secondary">
          <a href="#" class="text-reset">
            <a href="mailto:[email protected]">[email protected]</a>
          </a>
        </td>
        <td class="text-secondary">Admin</td>
        <td>
          <a href="#">Edit</a>
        </td>
      </tr>
    </tbody>
  </table>
</div>

Responsive tables

Use the .table-responsive class across each breakpoint for horizontal scrolling tables. If you want to create responsive tables up to a specific breakpoint, use .table-responsive{-sm|-md|-lg|-xl}. From that breakpoint and up, the table will behave normally, rather than scroll horizontally.

#Heading 1Heading 2Heading 3Heading 4Heading 5Heading 6Heading 7Heading 8Heading 9Heading 10
1CellCellCellCellCellCellCellCellCellCell
2CellCellCellCellCellCellCellCellCellCell
<table class="table table-responsive">
  <thead>
    <tr>
      <th>#</th>
      <th class="text-nowrap">Heading 1</th>
      <th class="text-nowrap">Heading 2</th>
      <th class="text-nowrap">Heading 3</th>
      <th class="text-nowrap">Heading 4</th>
      <th class="text-nowrap">Heading 5</th>
      <th class="text-nowrap">Heading 6</th>
      <th class="text-nowrap">Heading 7</th>
      <th class="text-nowrap">Heading 8</th>
      <th class="text-nowrap">Heading 9</th>
      <th class="text-nowrap">Heading 10</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>1</th>
      <td>Cell</td>
      <td>Cell</td>
      <td>Cell</td>
      <td>Cell</td>
      <td>Cell</td>
      <td>Cell</td>
      <td>Cell</td>
      <td>Cell</td>
      <td>Cell</td>
      <td>Cell</td>
    </tr>
    <tr>
      <th>2</th>
      <td>Cell</td>
      <td>Cell</td>
      <td>Cell</td>
      <td>Cell</td>
      <td>Cell</td>
      <td>Cell</td>
      <td>Cell</td>
      <td>Cell</td>
      <td>Cell</td>
      <td>Cell</td>
    </tr>
  </tbody>
</table>

No wrap

If you don't want the table cell content to wrap to another line, use the table-nowrap class.

NameTitleEmailRole
Paweł KunaUI Designer, Training[email protected]User Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi, commodi cupiditate debitis deserunt expedita hic incidunt iste modi molestiae nesciunt non nostrum perferendis perspiciatis placeat praesentium quaerat quo repellendus, voluptates. Edit
<div class="table-responsive">
  <table class="table table-vcenter table-nowrap">
    <thead>
      <tr>
        <th>Name</th>
        <th>Title</th>
        <th>Email</th>
        <th>Role</th>
        <th></th>
        <th class="w-1"></th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>Paweł Kuna</td>
        <td class="text-secondary">UI Designer, Training</td>
        <td class="text-secondary">
          <a href="#" class="text-reset">
            <a href="mailto:[email protected]">[email protected]</a>
          </a>
        </td>
        <td class="text-secondary">User</td>
        <td> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi, commodi cupiditate debitis deserunt expedita hic incidunt iste modi molestiae nesciunt non nostrum perferendis perspiciatis placeat praesentium quaerat quo repellendus, voluptates. </td>
        <td>
          <a href="#">Edit</a>
        </td>
      </tr>
    </tbody>
  </table>
</div>

Table variants

Use contextual classes such as .table-primary or .table-danger on a <tr> element to color rows and highlight their meaning.

ClassHeadingHeading
DefaultCellCell
PrimaryCellCell
SecondaryCellCell
SuccessCellCell
DangerCellCell
WarningCellCell
InfoCellCell
LightCellCell
DarkCellCell
<table class="table">
  <thead>
    <tr>
      <th scope="col">Class</th>
      <th scope="col">Heading</th>
      <th scope="col">Heading</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">Default</th>
      <td>Cell</td>
      <td>Cell</td>
    </tr>
    <tr class="table-primary">
      <th scope="row">Primary</th>
      <td>Cell</td>
      <td>Cell</td>
    </tr>
    <tr class="table-secondary">
      <th scope="row">Secondary</th>
      <td>Cell</td>
      <td>Cell</td>
    </tr>
    <tr class="table-success">
      <th scope="row">Success</th>
      <td>Cell</td>
      <td>Cell</td>
    </tr>
    <tr class="table-danger">
      <th scope="row">Danger</th>
      <td>Cell</td>
      <td>Cell</td>
    </tr>
    <tr class="table-warning">
      <th scope="row">Warning</th>
      <td>Cell</td>
      <td>Cell</td>
    </tr>
    <tr class="table-info">
      <th scope="row">Info</th>
      <td>Cell</td>
      <td>Cell</td>
    </tr>
    <tr class="table-light">
      <th scope="row">Light</th>
      <td>Cell</td>
      <td>Cell</td>
    </tr>
    <tr class="table-dark">
      <th scope="row">Dark</th>
      <td>Cell</td>
      <td>Cell</td>
    </tr>
  </tbody>
</table>

Table with sticky header

Add the .sticky-top class to the <thead> element to keep the header row visible while users scroll through a long table.

ClassHeadingHeading
DefaultCellCell
PrimaryCellCell
SecondaryCellCell
SuccessCellCell
DangerCellCell
WarningCellCell
InfoCellCell
LightCellCell
DarkCellCell
DefaultCellCell
PrimaryCellCell
SecondaryCellCell
SuccessCellCell
DangerCellCell
WarningCellCell
InfoCellCell
LightCellCell
DarkCellCell
<table class="table">
  <thead class="sticky-top">
    <tr>
      <th scope="col">Class</th>
      <th scope="col">Heading</th>
      <th scope="col">Heading</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">Default</th>
      <td>Cell</td>
      <td>Cell</td>
    </tr>
    <tr>
      <th scope="row">Primary</th>
      <td>Cell</td>
      <td>Cell</td>
    </tr>
    <tr>
      <th scope="row">Secondary</th>
      <td>Cell</td>
      <td>Cell</td>
    </tr>
    <tr>
      <th scope="row">Success</th>
      <td>Cell</td>
      <td>Cell</td>
    </tr>
    <tr>
      <th scope="row">Danger</th>
      <td>Cell</td>
      <td>Cell</td>
    </tr>
    <tr>
      <th scope="row">Warning</th>
      <td>Cell</td>
      <td>Cell</td>
    </tr>
    <tr>
      <th scope="row">Info</th>
      <td>Cell</td>
      <td>Cell</td>
    </tr>
    <tr>
      <th scope="row">Light</th>
      <td>Cell</td>
      <td>Cell</td>
    </tr>
    <tr class="table-dark">
      <th scope="row">Dark</th>
      <td>Cell</td>
      <td>Cell</td>
    </tr>
    <tr>
      <th scope="row">Default</th>
      <td>Cell</td>
      <td>Cell</td>
    </tr>
    <tr>
      <th scope="row">Primary</th>
      <td>Cell</td>
      <td>Cell</td>
    </tr>
    <tr>
      <th scope="row">Secondary</th>
      <td>Cell</td>
      <td>Cell</td>
    </tr>
    <tr>
      <th scope="row">Success</th>
      <td>Cell</td>
      <td>Cell</td>
    </tr>
    <tr>
      <th scope="row">Danger</th>
      <td>Cell</td>
      <td>Cell</td>
    </tr>
    <tr>
      <th scope="row">Warning</th>
      <td>Cell</td>
      <td>Cell</td>
    </tr>
    <tr>
      <th scope="row">Info</th>
      <td>Cell</td>
      <td>Cell</td>
    </tr>
    <tr>
      <th scope="row">Light</th>
      <td>Cell</td>
      <td>Cell</td>
    </tr>
    <tr class="table-dark">
      <th scope="row">Dark</th>
      <td>Cell</td>
      <td>Cell</td>
    </tr>
  </tbody>
</table>

Sortable headers

Put a .table-sort button inside a th to get a sortable-looking header. The button shows a neutral arrow, and adding .asc or .desc marks the current direction.

Sorting itself is up to you - the classes only style the header. Tabler's own demo uses List.js and passes the field through data-sort.

Elliot FisherAdelaide92
Beverly MillsBristol78
<table class="table">
  <thead>
    <tr>
      <th>
        <button class="table-sort" data-sort="sort-name">Name</button>
      </th>
      <th>
        <button class="table-sort asc" data-sort="sort-city">City</button>
      </th>
      <th>
        <button class="table-sort" data-sort="sort-score">Score</button>
      </th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Elliot Fisher</td>
      <td>Adelaide</td>
      <td>92</td>
    </tr>
    <tr>
      <td>Beverly Mills</td>
      <td>Bristol</td>
      <td>78</td>
    </tr>
  </tbody>
</table>

Selectable rows

Add .table-selectable to the table and .table-selectable-check to each checkbox. A checked row gets a highlighted background, with no JavaScript involved.

Inside such a row you can swap content with .on-checked and .on-unchecked: the first only shows while the row is selected, the second while it is not.

TaskStatus
Prepare the release notesSelectedNot selected
Review the pull requestSelectedNot selected
<table class="table table-selectable">
  <thead>
    <tr>
      <th class="w-1">
        <input type="checkbox" class="form-check-input table-selectable-check" aria-label="Select all rows" />
      </th>
      <th>Task</th>
      <th>Status</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>
        <input type="checkbox" class="form-check-input table-selectable-check" aria-label="Select task" checked />
      </td>
      <td>Prepare the release notes</td>
      <td>
        <span class="on-checked">Selected</span>
        <span class="on-unchecked text-secondary">Not selected</span>
      </td>
    </tr>
    <tr>
      <td>
        <input type="checkbox" class="form-check-input table-selectable-check" aria-label="Select task" />
      </td>
      <td>Review the pull request</td>
      <td>
        <span class="on-checked">Selected</span>
        <span class="on-unchecked text-secondary">Not selected</span>
      </td>
    </tr>
  </tbody>
</table>

Stacked table on small screens

A wide table can stack into a list instead of scrolling sideways. Use .table-mobile-{breakpoint} - .table-mobile-md stacks below md - and give every cell a data-label, which becomes the label above its value.

NameCityScore
Elliot FisherAdelaide92
Beverly MillsBristol78
<table class="table table-mobile-md">
  <thead>
    <tr>
      <th>Name</th>
      <th>City</th>
      <th>Score</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td data-label="Name">Elliot Fisher</td>
      <td data-label="City">Adelaide</td>
      <td data-label="Score">92</td>
    </tr>
    <tr>
      <td data-label="Name">Beverly Mills</td>
      <td data-label="City">Bristol</td>
      <td data-label="Score">78</td>
    </tr>
  </tbody>
</table>

Borderless, centered and transparent tables

.table-borderless removes the header background, .table-transparent clears the header and body backgrounds, and .table-center centers every cell.

PlanSeatsPrice
Starter3$9
Team10$29
<table class="table table-borderless table-center">
  <thead>
    <tr>
      <th>Plan</th>
      <th>Seats</th>
      <th>Price</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Starter</td>
      <td>3</td>
      <td>$9</td>
    </tr>
    <tr>
      <td>Team</td>
      <td>10</td>
      <td>$29</td>
    </tr>
  </tbody>
</table>

Truncated cell

A long value in one column stretches the whole table. Put td-truncate on that cell and text-truncate on the element inside it, and the text is cut with an ellipsis while the other columns keep their width.

NameNote
Elliot Fisher
A note long enough that it would otherwise push the first column out of the way and stretch the table past the width of the page.
<table class="table">
  <thead>
    <tr>
      <th class="w-1">Name</th>
      <th>Note</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Elliot Fisher</td>
      <td class="td-truncate">
        <div class="text-truncate"> A note long enough that it would otherwise push the first column out of the way and stretch the table past the width of the page. </div>
      </td>
    </tr>
  </tbody>
</table>

Accessibility

A table is read cell by cell, so the structure has to say what each cell means.

  • Use th with scope="col" or scope="row" for headers. Without a scope, a screen reader cannot tie a value back to its column.
  • Add a caption when the table needs a title. It is announced first and stays tied to the table, unlike a heading above it.
  • In a selectable table, give every checkbox its own aria-label - "Select task" is enough, and "Select all rows" for the one in the header.
  • .table-sort is a real button, so it is reachable by keyboard. Once you wire up sorting, also set aria-sort on the th to ascending, descending or none.
  • A stacked .table-mobile-* still keeps its header cells in the markup, so the reading order stays correct while the data-label text carries the column name visually.

SCSS variables

Use these SCSS variables to customize tables. The default values are:

$table-bg: transparent;
$table-color: inherit;
$table-accent-bg: transparent;

$table-cell-padding-x: 0.75rem;
$table-cell-padding-y: 0.75rem;
$table-cell-padding-y-sm: 0.25rem;
$table-cell-padding-x-sm: 0.25rem;
$table-cell-vertical-align: top;

$table-border-factor: 0.2;
$table-border-width: var(--border-width);
$table-border-color: var(--border-color-translucent);

$table-th-padding-x: $table-cell-padding-x;
$table-th-padding-y: 0.5rem;
$table-th-font-weight: null;
$table-th-bg: var(--bg-surface-tertiary);

$table-striped-color: $table-color;
$table-striped-bg-factor: 0.05;
$table-striped-order: even;
$table-striped-bg: var(--bg-surface-tertiary);
$table-striped-columns-order: even;

$table-group-separator-color: var(--border-color-translucent);

$table-active-color: $table-color;
$table-active-bg-factor: 0.1;
$table-active-bg: var(--active-bg);

$table-hover-color: $table-color;
$table-hover-bg-factor: 0.075;
$table-hover-bg: color-mix(in srgb, var(--emphasis-color) #{math.percentage($table-hover-bg-factor)}, transparent);

$table-caption-color: var(--secondary-color);

$table-bg-scale: -80%;

$table-variants: (
  'primary': shift-color($primary, $table-bg-scale),
  'secondary': shift-color($secondary, $table-bg-scale),
  'success': shift-color($success, $table-bg-scale),
  'info': shift-color($info, $table-bg-scale),
  'warning': shift-color($warning, $table-bg-scale),
  'danger': shift-color($danger, $table-bg-scale),
  'light': $light,
  'dark': $dark,
);

$table-sort-bg-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='16' height='16' fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='1'><path d='M5 7l3 -3l3 3'/><path d='M5 10l3 3l3 -3'/></svg>");
$table-sort-asc-bg-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='16' height='16'><path fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='1' d='M5 7l3 3l3 -3'/></svg>");
$table-sort-desc-bg-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' width='16' height='16'><path fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='1' d='M5 10l3 -3l3 3'/></svg>");
$table-sort-icon-size: 1rem;
$table-sort-icon-margin-start: 0.25rem;

Class reference

Every class this component ships, grouped by what it changes. A name in braces stands for a family — {color} is any base color, {breakpoint} any responsive step.

table componentContainer element
td-truncate partCell whose content is cut with an ellipsis instead of stretching the table
table-striped styleShades every other row
table-bordered styleBorder on every cell
table-borderless styleRemoves all borders
table-transparent styleRemoves the background
table-responsive modifierScrolls sideways; table-responsive-{breakpoint} only below that width
table-mobile-{breakpoint} modifierStacks rows into blocks below the breakpoint, using data-label on each cell
table-vcenter modifierCenters cell content vertically
table-center modifierCenters cell content horizontally
table-nowrap modifierStops cell text from wrapping
table-hover behaviorHighlights the row under the cursor
table-selectable behaviorRows with a checkbox, highlighted when checked
table-sort behaviorSortable header cell
table-{color} colorTints a row or a cell, for example table-success
table-sm sizeTighter cell padding

On this page

130 sleek illustrations for your startup's visual identity.