Table styling
Table styling is wrapper-first. Use CSS variables for component-scoped layout changes such as scroll height, overflow, table width, and header background. Use stable data-slot hooks for shared global CSS.
| Hook | Use |
|---|---|
[data-slot='table-scroll'] | Outer border, radius, background, max height, and scroll wrapper state. Reflects data-scroll-axis and data-sticky-header. |
[data-slot='table'] | Typography, table layout, min width, density, and hover mode state. |
[data-slot='table-header-cell'] | Header background, sort affordance, focus ring, and sticky presentation. |
[data-slot='table-cell'] | Body cell padding, borders, alignment, truncation, and hover state. |
[data-slot='table-state-cell'] | Loading, error, and empty states. |
Row and cell styling
For data-driven styling, attach your own classes through the rowClass input and the column-level cellClass / headerClass hooks. For component-scoped dynamic styling, use rowStyle, cellStyle, and headerStyle; these apply inline styles and CSS custom properties directly to the internal table elements.
Class hooks are best for global CSS, Tailwind utilities, or shared library classes. Style hooks are the component-CSS-friendly path because Angular scoped styles cannot select the table's internal rows and cells without ::ng-deep.
| Hook | Applies to |
|---|---|
rowClass(row, index) | Extra classes for each body <tr>, evaluated per row. |
rowStyle(row, index) | Inline styles/custom properties for each body <tr>. Use --tng-table-row-bg for row backgrounds. |
column.cellClass | Body cells of one column (static or a (row, value, index) predicate). |
column.cellStyle | Inline styles for body cells of one column (static or predicate). |
column.headerClass | The header cell of a leaf or group column. |
column.headerStyle | Inline styles for a leaf or group header cell. |
[data-group-position] | Row attribute (first | middle | last | single) for styling groupBy blocks, e.g. dividers between groups. |
// component.ts
protected rowStyle = (row: Order) =>
row.status === 'overdue'
? { '--tng-table-row-bg': 'var(--orders-overdue-row-bg)' }
: null;
protected columns: TngTableColumn<Order>[] = [
{ id: 'name', label: 'Name' },
{
id: 'total',
label: 'Total',
align: 'end',
cellStyle: (_row, value) =>
Number(value) < 0 ? { color: 'var(--orders-negative-fg)' } : null,
},
];
/* component.css */
tng-table {
--orders-overdue-row-bg: color-mix(
in srgb,
var(--tng-semantic-accent-danger) 12%,
var(--tng-semantic-background-surface)
);
--orders-negative-fg: var(--tng-semantic-accent-danger);
}
Scroll and sizing
scrollAxis enables the primitive scroll axes. CSS variables define the wrapper constraints and the native table's minimum width.
<!-- component.html -->
<tng-table
class="statement-preview-table"
scrollAxis="both"
[stickyHeader]="true"
[columns]="columns"
[items]="rows"
/>
/* component.css */
.statement-preview-table {
--tng-table-scroll-max-height: min(14rem, 30vh);
--tng-table-min-width: 84rem;
--tng-table-header-bg: var(--tng-semantic-background-surface);
}CSS starter
tng-table {
--tng-table-border: var(--tng-semantic-border-subtle);
--tng-table-radius: 0.75rem;
--tng-table-cell-px: 1rem;
--tng-table-cell-py: 0.75rem;
--tng-table-header-bg: var(--tng-semantic-background-muted);
--tng-table-scroll-max-height: none;
--tng-table-scroll-overflow-x: auto;
--tng-table-scroll-overflow-y: auto;
--tng-table-min-width: 100%;
--tng-table-header-z-index: 2;
}