Skip to content

Commit d2fdc1f

Browse files
committed
Add sticky table headers and tidy table docs
Add a `.thead-sticky` class so a `<thead>` stays visible while the `<tbody>` scrolls. Add `--table-thead-sticky-top` and `--table-thead-sticky-zindex` tokens to offset fixed headers and control stacking. Document the class and shorten several table headings.
1 parent 4bacc48 commit d2fdc1f

2 files changed

Lines changed: 87 additions & 4 deletions

File tree

scss/content/_tables.scss

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ $table-tokens: defaults(
2929
--table-hover-color: var(--table-color),
3030
--table-hover-bg-factor: 7.5%,
3131
--table-hover-bg: color-mix(in srgb, var(--table-color) var(--table-hover-bg-factor), transparent),
32+
--table-thead-sticky-top: 0,
33+
--table-thead-sticky-zindex: var(--z-3),
3234
),
3335
$table-tokens
3436
);
@@ -176,6 +178,17 @@ $table-striped-columns-order: even !default;
176178
}
177179
}
178180

181+
// Sticky table headers
182+
//
183+
// Add `.thead-sticky` to a `<thead>` to keep it in view while the `<tbody>`
184+
// scrolls. Set `--table-thead-sticky-top` to offset any fixed headers.
185+
186+
.thead-sticky {
187+
position: sticky;
188+
top: var(--table-thead-sticky-top);
189+
z-index: var(--table-thead-sticky-zindex);
190+
}
191+
179192
// Responsive tables
180193
//
181194
// Generate `.table-responsive` classes that act as container query contexts

site/src/content/docs/content/tables.mdx

Lines changed: 74 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ Highlight a table row or cell by adding a `.table-active` class.
205205
</table>
206206
`} />
207207

208-
## How do the variants and accented tables work?
208+
## Variants explained
209209

210210
For the accented tables ([striped rows](#striped-rows), [striped columns](#striped-columns), [hoverable rows](#hoverable-rows), and [active tables](#active-tables)), we used some techniques to make these effects work for all our [table variants](#variants):
211211

@@ -225,7 +225,7 @@ Behind the scenes it looks like this:
225225

226226
## Table borders
227227

228-
### Bordered tables
228+
### Bordered
229229

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

@@ -235,7 +235,7 @@ Add `.table-bordered` for borders on all sides of the table and cells.
235235

236236
<Table class="table table-bordered border-primary" />
237237

238-
### Tables without borders
238+
### No borders
239239

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

@@ -427,7 +427,7 @@ Border styles, active styles, and table variants are not inherited by nested tab
427427
</table>
428428
`} />
429429

430-
## How nesting works
430+
### How nesting works
431431

432432
To prevent *any* styles from leaking to nested tables, we use the child combinator (`>`) selector in our CSS. Since we need to target all the `td`s and `th`s in the `thead`, `tbody`, and `tfoot`, our selector would look pretty long without it. As such, we use the rather odd looking `.table > :not(caption) > * > *` selector to target all `td`s and `th`s of the `.table`, but none of any potential nested tables.
433433

@@ -619,6 +619,76 @@ Both `.table-stacked` and `.table-responsive` use container queries, so the `.ta
619619
</div>
620620
```
621621

622+
## Sticky table headers
623+
624+
Add `.thead-sticky` to a `<thead>` to keep it in view while the `<tbody>` contents scroll. The table needs a scrollable parent, such as a container with a fixed height. Set the `--bs-table-thead-sticky-top` CSS variable to offset any fixed headers or navigation above the table.
625+
626+
<Example code={`<div style="max-height: 300px; overflow-y: auto;">
627+
<table class="table" style="--bs-table-thead-sticky-top: 0;">
628+
<thead class="thead-sticky">
629+
<tr>
630+
<th scope="col">#</th>
631+
<th scope="col">First</th>
632+
<th scope="col">Last</th>
633+
<th scope="col">Handle</th>
634+
</tr>
635+
</thead>
636+
<tbody>
637+
<tr>
638+
<th scope="row">1</th>
639+
<td>Mark</td>
640+
<td>Otto</td>
641+
<td>@mdo</td>
642+
</tr>
643+
<tr>
644+
<th scope="row">2</th>
645+
<td>Jacob</td>
646+
<td>Thornton</td>
647+
<td>@fat</td>
648+
</tr>
649+
<tr>
650+
<th scope="row">3</th>
651+
<td colspan="2">Larry the Bird</td>
652+
<td>@twitter</td>
653+
</tr>
654+
<tr>
655+
<th scope="row">4</th>
656+
<td>Mark</td>
657+
<td>Otto</td>
658+
<td>@mdo</td>
659+
</tr>
660+
<tr>
661+
<th scope="row">5</th>
662+
<td>Jacob</td>
663+
<td>Thornton</td>
664+
<td>@fat</td>
665+
</tr>
666+
<tr>
667+
<th scope="row">6</th>
668+
<td colspan="2">Larry the Bird</td>
669+
<td>@twitter</td>
670+
</tr>
671+
<tr>
672+
<th scope="row">7</th>
673+
<td>Mark</td>
674+
<td>Otto</td>
675+
<td>@mdo</td>
676+
</tr>
677+
<tr>
678+
<th scope="row">8</th>
679+
<td>Jacob</td>
680+
<td>Thornton</td>
681+
<td>@fat</td>
682+
</tr>
683+
<tr>
684+
<th scope="row">9</th>
685+
<td colspan="2">Larry the Bird</td>
686+
<td>@twitter</td>
687+
</tr>
688+
</tbody>
689+
</table>
690+
</div>`} />
691+
622692
## Responsive tables
623693

624694
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 `.{sm|md|lg|xl|2xl}:table-responsive`.

0 commit comments

Comments
 (0)