`
* absorbs `data-size` / `data-variant` / `data-color` / `data-block` /
* `data-striped` / `data-hoverable` / `data-sticky-header` so the table
* itself can stay clean `
` semantics.
*
* Sizes — xs..xl on the wrapper; cascades to row block-size, cell
* padding and font-size.
*
* Variant `'surface' | 'outline' | 'ghost'` (ControlVariant).
* - surface: card chrome around the whole table
* - outline: border only, transparent background
* - ghost: no chrome
*
* Color cascades the accent for selected rows + sort indicator + focus.
*/
[data-table-root] {
--_table-radius: var(--radius-md);
--_table-row-block-size: var(--control-height-md);
--_table-cell-padding-inline: var(--space-3);
--_table-cell-padding-block: var(--space-2);
--_table-font-size: var(--font-size-sm);
--_table-header-bg: var(--color-surface-muted);
--_table-row-hover-bg: var(--color-surface-overlay);
--_table-row-striped-bg: var(--color-surface-muted);
--_table-divider: var(--color-border-default);
position: relative;
display: block;
font-family: var(--style-label-font-family);
color: var(--color-content-primary);
border-radius: var(--_table-radius);
overflow: hidden;
}
[data-table-root][data-block] {
inline-size: 100%;
}
/* ── Variant — surface (default) ─ */
[data-table-root][data-variant='surface'] {
border: var(--border-width) solid var(--_table-divider);
background: var(--color-surface-default);
}
[data-table-root][data-variant='outline'] {
border: var(--border-width) solid var(--_table-divider);
background: transparent;
}
[data-table-root][data-variant='ghost'] {
border: var(--border-width) solid transparent;
background: transparent;
}
/* ── Sizes ─ */
[data-table-root][data-size='xs'] {
--_table-row-block-size: var(--control-height-xs);
--_table-cell-padding-inline: var(--space-2);
--_table-cell-padding-block: var(--space-1);
--_table-font-size: var(--font-size-xs);
}
[data-table-root][data-size='sm'] {
--_table-row-block-size: var(--control-height-sm);
--_table-cell-padding-inline: var(--space-2);
--_table-cell-padding-block: var(--space-1);
--_table-font-size: var(--font-size-sm);
}
[data-table-root][data-size='lg'] {
--_table-row-block-size: var(--control-height-lg);
--_table-cell-padding-inline: var(--space-4);
--_table-cell-padding-block: var(--space-3);
--_table-font-size: var(--font-size-md);
}
[data-table-root][data-size='xl'] {
--_table-row-block-size: var(--control-height-xl);
--_table-cell-padding-inline: var(--space-5);
--_table-cell-padding-block: var(--space-3);
--_table-font-size: var(--font-size-lg);
}
/*
* Scrolling region — only when consumer sets `maxHeight`. Pure CSS
* overflow auto with overscroll containment so wheel scrolling inside
* the table doesn't bubble to the page.
*/
[data-table-root][data-scrollable] {
overflow: auto;
overscroll-behavior: contain;
}
/*
* Stable rows — reserve a vertical floor of `stableRows` row-heights
* (plus the header). Keeps the wrapper height steady so the surrounding
* layout (pagination, sticky footers, sibling cards) doesn't jump as
* filters / pageSize change the visible row count. Ignored when the
* wrapper is already capped by `maxHeight` (scroll region).
*
* The consumer sets `--_table-stable-rows` via inline style; the recipe
* multiplies by `--_table-row-block-size` (already scaled by `data-size`)
* and adds one row for the header.
*/
[data-table-root][data-stable-rows] {
/*
* Real row block-size at render = `--_table-row-block-size` (control
* height, the centred content) + 2 × `--_table-cell-padding-block` (cell vertical
* padding) + 1px (cell `border-block-end`). Sum × (rows + 1 header).
*/
min-block-size: calc(
(var(--_table-row-block-size) + var(--_table-cell-padding-block) * 2 + 1px)
* (var(--_table-stable-rows, 0) + 1)
);
}
[data-table-root][data-disabled] {
opacity: var(--opacity-disabled);
pointer-events: none;
}
/* ── Table element ─ */
[data-table] {
inline-size: 100%;
border-collapse: separate;
border-spacing: 0;
font-size: var(--_table-font-size);
line-height: var(--leading-ui);
color: inherit;
caption-side: top;
}
/* ── Header (thead) ─ */
[data-table-header] {
background: var(--_table-header-bg);
}
/*
* Sticky header — when the wrapper is scrollable AND `stickyHeader` is on,
* the `| ` cells stick to the top of the wrapper. Position is set on
* ` | ` (not ``) because `` is not a valid containing
* block for `position: sticky` in legacy rendering paths.
*/
[data-table-root][data-sticky-header] [data-table-column-header] {
position: sticky;
inset-block-start: 0;
z-index: 2;
background: var(--_table-header-bg);
}
/* ── ColumnHeader (th) ─ */
[data-table-column-header] {
box-sizing: border-box;
padding-block: var(--_table-cell-padding-block);
padding-inline: var(--_table-cell-padding-inline);
text-align: start;
font-weight: var(--font-weight-semibold, 600);
color: var(--color-content-primary);
border-block-end: var(--border-width) solid var(--_table-divider);
white-space: nowrap;
vertical-align: middle;
user-select: none;
}
[data-table-column-header][data-sortable] {
cursor: pointer;
}
[data-table-column-header][data-sorted] {
color: var(--_table-palette-solid);
}
[data-table-column-header][data-pinned] {
background: var(--_table-header-bg);
}
/* ── Body (tbody) ─ */
[data-table-body] [data-table-row] {
background: var(--color-surface-default);
transition: background var(--duration-fast) var(--ease-default);
}
[data-table-root][data-variant='ghost'] [data-table-body] [data-table-row] {
background: transparent;
}
/* Striped — alternate body rows. Skip when ghost (no chrome). */
[data-table-root][data-striped]:not([data-variant='ghost'])
[data-table-body]
[data-table-row]:nth-of-type(even) {
background: var(--_table-row-striped-bg);
}
/* Hoverable — row hover highlight. Drop when row is selected. */
[data-table-root][data-hoverable]
[data-table-body]
[data-table-row]:not([data-selected]):hover {
background: var(--_table-row-hover-bg);
}
/* Selected row — accent tint. Overrides hover + striped. */
[data-table-body] [data-table-row][data-selected] {
background: var(--_table-palette-element);
color: var(--color-content-primary);
}
/* Last row has no bottom divider — the wrapper border handles the edge. */
[data-table-body] [data-table-row]:last-of-type [data-table-cell] {
border-block-end: 0;
}
/* ── Row (tr) ─ */
[data-table-row] {
outline: none;
}
[data-table-row]:focus-visible {
outline: var(--focus-ring-width) solid var(--focus-ring-color);
outline-offset: -1px;
}
/* ── Cell (td) ─ */
[data-table-cell] {
box-sizing: border-box;
padding-block: var(--_table-cell-padding-block);
padding-inline: var(--_table-cell-padding-inline);
border-block-end: var(--border-width) solid var(--_table-divider);
vertical-align: middle;
color: inherit;
}
/*
* Pinned cells take the row's background so the sticky offset doesn't
* reveal content behind them. Cascade from `data-pinned` on either the
* cell or the header.
*/
[data-table-cell][data-pinned] {
background: inherit;
}
/* ── Footer (tfoot) ─ */
[data-table-footer] {
background: var(--_table-header-bg);
}
[data-table-footer] [data-table-cell] {
font-weight: var(--font-weight-semibold, 600);
border-block-end: 0;
border-block-start: var(--border-width) solid var(--_table-divider);
}
/* ── RowDetail (disclosure) ─ */
[data-table-row-detail] {
background: var(--color-surface-muted);
}
[data-table-row-detail][data-state='closed'] {
display: none;
}
[data-table-row-detail] > td {
padding: var(--space-3) var(--_table-cell-padding-inline);
border-block-end: var(--border-width) solid var(--_table-divider);
color: var(--color-content-secondary);
}
/* ── SortButton (eidos helper) ─ */
[data-table-sort-trigger] {
display: inline-flex;
align-items: center;
gap: var(--space-1);
padding: 0;
margin: 0;
border: 0;
background: transparent;
color: inherit;
cursor: pointer;
font: inherit;
user-select: none;
border-radius: var(--radius-sm);
}
[data-table-sort-trigger]:focus-visible {
outline: var(--focus-ring-width) solid var(--focus-ring-color);
outline-offset: 2px;
}
[data-table-sort-trigger][data-sorted] {
color: var(--_table-palette-solid);
}
[data-table-sort-indicator] {
display: inline-flex;
align-items: center;
justify-content: center;
inline-size: 1em;
block-size: 1em;
opacity: var(--opacity-disabled);
transition: opacity var(--duration-fast) var(--ease-default);
}
[data-table-sort-trigger][data-sorted] [data-table-sort-indicator] {
opacity: 1;
}
|