mirror of
https://github.com/tabler/tabler.git
synced 2026-10-12 21:27:06 +04:00
528 lines
14 KiB
Plaintext
528 lines
14 KiB
Plaintext
---
|
|
title: Table
|
|
summary: Tables lay out rows of data, with variants for responsive, sortable, selectable and sticky-header tables.
|
|
description: Present data in clean, responsive tables. Add hover states, striped rows, sorting, and other options to improve readability.
|
|
related: [/ui/components/datagrid, /ui/components/pagination]
|
|
source: core/scss/ui/_tables.scss
|
|
css-vars: table
|
|
classnames:
|
|
component:
|
|
- class: table
|
|
desc: Container element
|
|
part:
|
|
- class: td-truncate
|
|
desc: Cell whose content is cut with an ellipsis instead of stretching the table
|
|
style:
|
|
- class: table-striped
|
|
desc: Shades every other row
|
|
- class: table-bordered
|
|
desc: Border on every cell
|
|
- class: table-borderless
|
|
desc: Removes all borders
|
|
- class: table-transparent
|
|
desc: Removes the background
|
|
modifier:
|
|
- class: table-responsive
|
|
desc: Scrolls sideways; table-responsive-{breakpoint} only below that width
|
|
- class: table-mobile-{breakpoint}
|
|
desc: Stacks rows into blocks below the breakpoint, using data-label on each cell
|
|
- class: table-vcenter
|
|
desc: Centers cell content vertically
|
|
- class: table-center
|
|
desc: Centers cell content horizontally
|
|
- class: table-nowrap
|
|
desc: Stops cell text from wrapping
|
|
behavior:
|
|
- class: table-hover
|
|
desc: Highlights the row under the cursor
|
|
- class: table-selectable
|
|
desc: Rows with a checkbox, highlighted when checked
|
|
- class: table-sort
|
|
desc: Sortable header cell
|
|
color:
|
|
- class: table-{color}
|
|
desc: Tints a row or a cell, for example table-success
|
|
size:
|
|
- class: table-sm
|
|
desc: Tighter cell padding
|
|
---
|
|
import Example from '@components/Example.astro';
|
|
|
|
## 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:
|
|
|
|
<Example>
|
|
<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">paweluna@howstuffworks.com</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">jlewzey1@seesaa.net</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">mhulme2@domainmarket.com</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">dslane3@epa.gov</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">elevet4@senate.gov</a></td>
|
|
<td class="text-secondary">Admin</td>
|
|
<td><a href="#">Edit</a></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</Example>
|
|
|
|
## 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.
|
|
|
|
<Example>
|
|
<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>
|
|
</Example>
|
|
|
|
## No wrap
|
|
|
|
If you don't want the table cell content to wrap to another line, use the `table-nowrap` class.
|
|
|
|
<Example>
|
|
<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">paweluna@howstuffworks.com</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>
|
|
</Example>
|
|
|
|
## Table variants
|
|
|
|
Use contextual classes such as `.table-primary` or `.table-danger` on a `<tr>` element to color rows and highlight their meaning.
|
|
|
|
<Example>
|
|
<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>
|
|
</Example>
|
|
|
|
## 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.
|
|
|
|
<Example height="42rem">
|
|
<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>
|
|
</Example>
|
|
|
|
## 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](https://listjs.com) and passes the field through `data-sort`.
|
|
|
|
<Example>
|
|
<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>
|
|
</Example>
|
|
|
|
## 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.
|
|
|
|
<Example>
|
|
<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>
|
|
</Example>
|
|
|
|
## 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.
|
|
|
|
<Example>
|
|
<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>
|
|
</Example>
|
|
|
|
## 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.
|
|
|
|
<Example>
|
|
<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>
|
|
</Example>
|
|
|
|
## 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.
|
|
|
|
<Example>
|
|
<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>
|
|
</Example>
|
|
|
|
## 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.
|