# Theming

> Customize @toolbox-web/grid with CSS custom properties — colors, spacing, typography, dark mode, pre-built themes, and cascade layers.

The `@toolbox-web/grid` component is fully themeable via CSS custom properties. Customize colors, spacing, typography, and more without modifying source code.

## Quick Start

Override CSS custom properties on the grid element. Use the combined
`[data-tbw-grid], tbw-grid` selector — it matches the canonical `<tbw-grid>`
tag *and* version-suffixed tags (e.g. `<tbw-grid-v2-14-0>`) emitted when
[multiple grid versions](./multi-version) share the page:

```css
[data-tbw-grid],
tbw-grid {
  --tbw-color-bg: #1a1a2e;
  --tbw-color-fg: #eaeaea;
  --tbw-color-border: #16213e;
  --tbw-color-header-bg: #0f3460;
  --tbw-color-row-hover: #1a1a4e;
}
```

:::caution[Themes targeting only `tbw-grid` break in micro-frontends]
If your theme might ever be loaded into a micro-frontend host where another
bundle already owns `tbw-grid`, your bundle will register itself under a
suffixed tag (e.g. `tbw-grid-v2-14-0`) and any rule keyed on the bare
`tbw-grid` selector will silently miss those grids. **Always include
`[data-tbw-grid]` in custom theme selectors** — every grid sets that
attribute on its host regardless of the registered tag. The bundled
themes (`@toolbox-web/grid/themes/dg-theme-*.css`) already follow this
convention. See [Multi-version coexistence](./multi-version) for details.
:::

## Scaling with Font Size

All sizing uses `em` units, so the grid scales proportionally with `font-size`:

```css
tbw-grid { font-size: 1.25em; }           /* 25% larger */
tbw-grid.compact { font-size: 0.875em; }  /* Compact */
```

## Pre-built Themes

Import a pre-built theme CSS file:

```typescript
import '@toolbox-web/grid/themes/dg-theme-material.css';
```

| Theme | Description |
| --- | --- |
| **Standard** | Polished, balanced look |
| **Material** | Material Design 3 inspired |
| **Bootstrap** | Bootstrap 5 styling |
| **Vibrant** | Bold purple accents |
| **Contrast** | High contrast for accessibility |
| **Large** | Larger fonts and spacing |

## Dark Mode Support

The grid uses `light-dark()` for automatic theme support:

```css
tbw-grid { color-scheme: light dark; }  /* Auto-adapt */
tbw-grid { color-scheme: dark; }        /* Force dark */
```

All built-in color variables use `light-dark()` internally, so they automatically provide appropriate colors for both modes.

## CSS Cascade Layers

The grid organizes its styles into CSS cascade layers:

```css
@layer tbw-base, tbw-plugins, tbw-theme;
```

Your unlayered CSS always wins — no `!important` needed. This makes theming predictable:

- `tbw-base` — Core grid styles (structure, layout)
- `tbw-plugins` — Plugin-contributed styles (selection highlighting, filter icons, etc.)
- `tbw-theme` — Theme overrides (pre-built themes go here)
- *(unlayered)* — Your custom CSS — always highest priority

## Interactive Theme Builder

Use the theme builder below to customize every CSS variable in real-time — including core tokens and plugin-specific variables across all categories. The preview grid updates instantly as you tweak values. Export your theme as a `.css` file when you're done.

## CSS Variable Reference

The tables below list **all 228 CSS custom properties** across core styles and every plugin, with their **live computed values** in this page. Toggle between light and dark mode to see how values change.

### Core Colors

| Variable | Description |
| --- | --- |
| `--tbw-color-bg` | Grid background |
| `--tbw-color-panel-bg` | Panel backgrounds |
| `--tbw-color-fg` | Primary text color |
| `--tbw-color-fg-muted` | Secondary text |
| `--tbw-color-accent` | Accent color (focus, selection) |
| `--tbw-color-accent-fg` | Text on accent |
| `--tbw-color-success` | Success state |
| `--tbw-color-warning` | Warning state |
| `--tbw-color-error` | Error state |
| `--tbw-color-shadow` | Box‑shadow color |

### Row & Cell Colors

| Variable | Description |
| --- | --- |
| `--tbw-color-selection` | Selection background |
| `--tbw-color-row-alt` | Alternating row color |
| `--tbw-color-row-hover` | Row hover color |
| `--tbw-color-active-row-bg` | Active row background |

### Header

| Variable | Description |
| --- | --- |
| `--tbw-color-header-bg` | Header background |
| `--tbw-color-header-fg` | Header text color |
| `--tbw-color-header-separator` | Header column separator |
| `--tbw-color-header-group-fg` | Column group header text |
| `--tbw-header-height` | Header row height |
| `--tbw-font-size-header` | Header font size |
| `--tbw-font-weight-header` | Header font weight |
| `--tbw-font-weight-header-group` | Column group font weight |
| `--tbw-header-text-transform` | Header text transform |
| `--tbw-header-letter-spacing` | Header letter spacing |
| `--tbw-align-header` | Header content alignment |
| `--tbw-align-header-group` | Column group alignment |

### Borders

| Variable | Description |
| --- | --- |
| `--tbw-color-border` | Default border color |
| `--tbw-color-border-strong` | Strong border color |
| `--tbw-color-border-cell` | Cell border color |
| `--tbw-color-border-header` | Header border color |
| `--tbw-border-radius` | Border radius |
| `--tbw-border-width` | Default border width |
| `--tbw-border-style` | Default border style |
| `--tbw-border-input` | Input border shorthand |
| `--tbw-border-header` | Header border shorthand |
| `--tbw-row-divider` | Row divider border |
| `--tbw-row-hover-outline` | Row hover outline |
| `--tbw-active-row-outline` | Active row outline |

### Typography

| Variable | Description |
| --- | --- |
| `--tbw-font-family` | Font family |
| `--tbw-font-size` | Base font size |
| `--tbw-font-size-sm` | Small font size |
| `--tbw-font-size-xs` | Extra small font size |
| `--tbw-font-size-2xs` | Extra‑extra small font size |

### Spacing

| Variable | Description |
| --- | --- |
| `--tbw-spacing-xs` | Extra small spacing |
| `--tbw-spacing-sm` | Small spacing |
| `--tbw-spacing-md` | Medium spacing |
| `--tbw-spacing-lg` | Large spacing |
| `--tbw-spacing-xl` | Extra large spacing |
| `--tbw-cell-padding` | Cell padding |
| `--tbw-cell-padding-v` | Cell vertical padding |
| `--tbw-cell-padding-h` | Cell horizontal padding |
| `--tbw-cell-padding-header` | Header cell padding |
| `--tbw-cell-padding-input` | Input cell padding |

### Row & Cell Dimensions

| Variable | Description |
| --- | --- |
| `--tbw-row-height` | Row height |
| `--tbw-cell-white-space` | Cell text wrapping |
| `--tbw-density-scale` | Density multiplier |

### Focus & Selection

| Variable | Description |
| --- | --- |
| `--tbw-focus-outline-width` | Focus ring width |
| `--tbw-focus-outline` | Focus ring style |
| `--tbw-focus-outline-offset` | Focus ring offset |
| `--tbw-focus-background` | Focused cell background tint |
| `--tbw-range-border-color` | Range selection border |
| `--tbw-range-selection-bg` | Range selection background |

### Icons

| Variable | Description |
| --- | --- |
| `--tbw-base-icon-size` | Base icon size (bulk override) |
| `--tbw-icon-size` | Icon size |
| `--tbw-icon-size-sm` | Small icon size |
| `--tbw-checkbox-size` | Checkbox size |
| `--tbw-toggle-size` | Toggle icon size |

### Resize Handle

| Variable | Description |
| --- | --- |
| `--tbw-resize-handle-width` | Resize handle width |
| `--tbw-resize-handle-color` | Resize handle color |
| `--tbw-resize-handle-color-hover` | Resize handle hover color |
| `--tbw-resize-handle-border-radius` | Resize handle corner radius |
| `--tbw-resize-indicator-width` | Resize indicator width |
| `--tbw-resize-indicator-color` | Resize indicator color |
| `--tbw-resize-indicator-opacity` | Resize indicator opacity |
| `--tbw-resize-hit-area` | Resize handle clickable area |

### Animation

| Variable | Description |
| --- | --- |
| `--tbw-transition-duration` | Transition duration |
| `--tbw-transition-ease` | Transition easing |
| `--tbw-animation-duration` | Animation duration |
| `--tbw-animation-easing` | Animation easing |
| `--tbw-animation-enabled` | Enable animations (0 to disable) |
| `--tbw-row-change-duration` | Row change highlight duration |
| `--tbw-row-insert-duration` | Row insert animation duration |
| `--tbw-row-remove-duration` | Row remove animation duration |
| `--tbw-row-change-color` | Row change highlight color |

### Sorting Indicators

| Variable | Description |
| --- | --- |
| `--tbw-sort-indicator-color` | Sort indicator color |
| `--tbw-sort-indicator-active-color` | Active sort indicator |
| `--tbw-sort-indicator-display` | Sort indicator display |
| `--tbw-sort-indicator-visibility` | Sort indicator visibility |

### Shell & Panels

| Variable | Description |
| --- | --- |
| `--tbw-shell-header-height` | Shell header height |
| `--tbw-shell-header-bg` | Shell header background |
| `--tbw-shell-header-border` | Shell header border color |
| `--tbw-shell-title-font-size` | Shell title font size |
| `--tbw-shell-title-font-weight` | Shell title font weight |
| `--tbw-tool-panel-width` | Tool panel width |
| `--tbw-tool-panel-bg` | Tool panel background |
| `--tbw-tool-panel-border` | Tool panel border color |
| `--tbw-tool-panel-header-height` | Tool panel header height |
| `--tbw-tool-panel-transition` | Tool panel open/close transition |
| `--tbw-toolbar-button-size` | Toolbar button size |
| `--tbw-toolbar-button-gap` | Toolbar button gap |

### Component Shortcuts

| Variable | Description |
| --- | --- |
| `--tbw-panel-padding` | Panel content padding |
| `--tbw-panel-gap` | Panel content gap |
| `--tbw-menu-item-padding` | Menu item padding |
| `--tbw-menu-item-gap` | Menu item gap |
| `--tbw-menu-min-width` | Menu minimum width |
| `--tbw-button-padding` | Button padding |
| `--tbw-button-padding-sm` | Small button padding |
| `--tbw-input-height` | Input height |
| `--tbw-input-padding` | Input padding |
| `--tbw-detail-padding` | Detail row padding |
| `--tbw-detail-max-height` | Detail row max height |
| `--tbw-indicator-size` | Indicator dot size |

### Scrollbar

| Variable | Description |
| --- | --- |
| `--tbw-scrollbar-thumb` | Scrollbar thumb color |
| `--tbw-scrollbar-track` | Scrollbar track color |

### Loading Spinner

| Variable | Description |
| --- | --- |
| `--tbw-spinner-size` | Spinner size (grid-level) |
| `--tbw-spinner-border-width` | Spinner border thickness |
| `--tbw-spinner-color` | Spinner active color |
| `--tbw-spinner-track-color` | Spinner track color |

### Context Menu (Plugin)

| Variable | Description |
| --- | --- |
| `--tbw-context-menu-bg` | Context menu background |
| `--tbw-context-menu-fg` | Context menu text color |
| `--tbw-context-menu-border` | Context menu border color |
| `--tbw-context-menu-hover` | Context menu item hover |
| `--tbw-context-menu-muted` | Muted text (shortcuts) |
| `--tbw-context-menu-danger` | Danger action color |
| `--tbw-context-menu-radius` | Menu border radius |
| `--tbw-context-menu-shadow` | Menu box shadow |
| `--tbw-context-menu-min-width` | Minimum menu width |
| `--tbw-context-menu-font-size` | Menu font size |
| `--tbw-context-menu-font-family` | Menu font family |
| `--tbw-context-menu-item-padding` | Menu item padding |
| `--tbw-context-menu-item-gap` | Menu item gap |
| `--tbw-context-menu-icon-size` | Menu icon size |
| `--tbw-context-menu-shortcut-size` | Shortcut text size |
| `--tbw-context-menu-arrow-size` | Submenu arrow size |

### Filtering (Plugin)

| Variable | Description |
| --- | --- |
| `--tbw-filter-panel-bg` | Filter panel background |
| `--tbw-filter-panel-fg` | Filter panel text color |
| `--tbw-filter-panel-border` | Filter panel border |
| `--tbw-filter-panel-radius` | Filter panel radius |
| `--tbw-filter-panel-shadow` | Filter panel shadow color |
| `--tbw-filter-accent` | Filter accent color |
| `--tbw-filter-accent-fg` | Filter accent text color |
| `--tbw-filter-hover` | Filter item hover |
| `--tbw-filter-muted` | Filter muted text |
| `--tbw-filter-divider` | Filter divider color |
| `--tbw-filter-input-bg` | Filter input background |
| `--tbw-filter-input-border` | Filter input border color |
| `--tbw-filter-input-radius` | Filter input radius |
| `--tbw-filter-item-height` | Filter list item height |
| `--tbw-filter-search-padding` | Filter search input padding |
| `--tbw-filter-btn-padding` | Filter button padding |
| `--tbw-filter-btn-font-weight` | Filter button font weight |
| `--tbw-filter-btn-min-height` | Filter button min height |
| `--tbw-filter-btn-display` | Header filter button display |
| `--tbw-filter-btn-visibility` | Header filter button visibility |

### Selection (Plugin)

| Variable | Description |
| --- | --- |
| `--tbw-selection-border-style` | Selection border style |
| `--tbw-selection-border-width` | Selection border width |
| `--tbw-selection-warning-bg` | Invalid selection background |

### Editing (Plugin)

| Variable | Description |
| --- | --- |
| `--tbw-editing-bg` | Editing cell background |
| `--tbw-editing-row-bg` | Editing row background |
| `--tbw-editing-border` | Editor input border |
| `--tbw-padding-editing-input` | Editor input padding |
| `--tbw-font-size-editor` | Editor font size |
| `--tbw-editing-row-outline-color` | Editing row outline color |
| `--tbw-editing-row-outline-width` | Editing row outline width |
| `--tbw-invalid-bg` | Invalid cell background |
| `--tbw-invalid-border-color` | Invalid cell border color |

### Row Grouping (Plugin)

| Variable | Description |
| --- | --- |
| `--tbw-grouping-rows-bg` | Group row background |
| `--tbw-grouping-rows-bg-hover` | Group row hover bg |
| `--tbw-grouping-rows-toggle-hover` | Toggle button hover |
| `--tbw-grouping-rows-count-color` | Group count text color |
| `--tbw-grouping-rows-aggregate-color` | Aggregate value color |
| `--tbw-group-indent-width` | Group indent per level |

### Grouping Columns (Plugin)

| Variable | Description |
| --- | --- |
| `--tbw-grouping-columns-header-bg` | Column group header bg |
| `--tbw-grouping-columns-border` | Column group border |
| `--tbw-grouping-columns-separator` | Column group separator |

### Tree (Plugin)

| Variable | Description |
| --- | --- |
| `--tbw-tree-indent-width` | Tree indentation width |
| `--tbw-tree-toggle-size` | Tree toggle icon size |
| `--tbw-tree-accent` | Tree expand/collapse accent |

### Master-Detail (Plugin)

| Variable | Description |
| --- | --- |
| `--tbw-master-detail-bg` | Detail row background |
| `--tbw-master-detail-border` | Detail row border |

### Pivot (Plugin)

| Variable | Description |
| --- | --- |
| `--tbw-pivot-group-bg` | Pivot group row bg |
| `--tbw-pivot-group-hover` | Pivot group hover bg |
| `--tbw-pivot-leaf-bg` | Pivot leaf row bg |
| `--tbw-pivot-grand-total-bg` | Grand total row bg |
| `--tbw-pivot-toggle-size` | Pivot toggle icon size |
| `--tbw-pivot-toggle-color` | Pivot toggle color |
| `--tbw-pivot-toggle-hover-bg` | Pivot toggle hover bg |
| `--tbw-pivot-toggle-hover-color` | Pivot toggle hover color |
| `--tbw-pivot-count-color` | Pivot count text color |
| `--tbw-pivot-border` | Pivot section border |
| `--tbw-pivot-section-bg` | Pivot configurator bg |
| `--tbw-pivot-header-bg` | Pivot configurator header bg |
| `--tbw-pivot-drop-border` | Drop zone border |
| `--tbw-pivot-drop-bg` | Drop zone background |
| `--tbw-pivot-drop-active` | Active drop zone bg |
| `--tbw-pivot-chip-bg` | Pivot chip background |
| `--tbw-pivot-chip-border` | Pivot chip border |
| `--tbw-pivot-chip-hover` | Pivot chip hover bg |
| `--tbw-pivot-chip-remove-hover-bg` | Chip remove button hover bg |
| `--tbw-pivot-chip-remove-hover-fg` | Chip remove button hover text |

### Multi-Sort (Plugin)

| Variable | Description |
| --- | --- |
| `--tbw-multi-sort-badge-bg` | Sort badge background |
| `--tbw-multi-sort-badge-color` | Sort badge text color |
| `--tbw-multi-sort-badge-size` | Sort badge size |

### Visibility Panel (Plugin)

| Variable | Description |
| --- | --- |
| `--tbw-visibility-hover` | Visibility item hover |
| `--tbw-visibility-indicator` | Visibility indicator |
| `--tbw-visibility-border` | Visibility panel border |
| `--tbw-visibility-btn-bg` | Visibility button bg |

### Pinned Rows (Plugin)

| Variable | Description |
| --- | --- |
| `--tbw-pinned-rows-bg` | Pinned rows background |
| `--tbw-pinned-rows-border` | Pinned rows border |
| `--tbw-pinned-rows-color` | Pinned rows text color |
| `--tbw-aggregation-bg` | Aggregation row background |
| `--tbw-aggregation-border` | Aggregation row border |
| `--tbw-aggregation-font-size` | Aggregation font size |
| `--tbw-aggregation-font-weight` | Aggregation font weight |

### Responsive (Plugin)

| Variable | Description |
| --- | --- |
| `--tbw-responsive-duration` | Card layout transition |

### Print (Plugin)

| Variable | Description |
| --- | --- |
| `--tbw-print-border` | Print header border |
| `--tbw-print-muted` | Print muted text |
| `--tbw-print-cell-border` | Print cell border |

### Reorder Columns (Plugin)

| Variable | Description |
| --- | --- |
| `--tbw-reorder-indicator` | Column reorder indicator |

### Reorder Rows (Plugin)

| Variable | Description |
| --- | --- |
| `--tbw-row-reorder-handle-color` | Row drag handle color |
| `--tbw-row-reorder-handle-hover` | Row drag handle hover color |
| `--tbw-row-reorder-indicator` | Row reorder drop indicator |
| `--tbw-row-reorder-moving-bg` | Moving row background |
| `--tbw-row-reorder-moving-border` | Moving row border color |

### Z-Index Layers

| Variable | Description |
| --- | --- |
| `--tbw-z-layer-rows` | Row area z-index |
| `--tbw-z-layer-header` | Header z-index |
| `--tbw-z-layer-pinned-rows` | Pinned rows z-index |
| `--tbw-z-layer-toolpanel` | Tool panel z-index |

## Building a Custom Theme

Create a CSS file with your overrides:

```css
/* my-theme.css */
@layer tbw-theme {
  [data-tbw-grid],
  tbw-grid {
    --tbw-color-bg: #fafafa;
    --tbw-color-fg: #333;
    --tbw-color-border: #e0e0e0;
    --tbw-color-header-bg: #f5f5f5;
    --tbw-color-header-fg: #555;
    --tbw-color-row-hover: #e3f2fd;
    --tbw-color-accent: #1976d2;
    --tbw-color-focus-ring: #1976d2;
    --tbw-cell-padding: 0.4em 0.75em;
    --tbw-font-family: 'Inter', sans-serif;
  }
}
```

Import it **after** the grid:

```typescript
import '@toolbox-web/grid';
import './my-theme.css';
```

## Programmatic Styles

Since the grid uses **light DOM**, standard CSS works — global stylesheets, `<style>` in `<head>`, or external CSS files can all target elements inside `<tbw-grid>`.

For styles you need to inject or update **from JavaScript at runtime**, use the `registerStyles()` API:

```typescript
// Inject styles programmatically
grid.registerStyles('my-highlights', `
  .row-warning { background: #fff3e0; }
  .row-error { background: #fce4ec; }
`);

// Remove when no longer needed
grid.unregisterStyles('my-highlights');
```

:::caution
Do not place `<style>` elements as **children of `<tbw-grid>`** — the grid calls `replaceChildren()` during renders, which removes child nodes. This only applies to styles placed *inside* the grid element itself; external CSS is unaffected.
:::

## Plugin Styles

Plugins inject their own CSS via `adoptedStyleSheets` in the `tbw-plugins` cascade layer. You can override any plugin class in your theme:

| Plugin | Key CSS Classes | What They Style |
|--------|----------------|----------------|
| **Selection** | `.tbw-cell-selected`, `.tbw-row-selected` | Selected cells and rows highlight |
| **Editing** | `.tbw-cell-editing`, `.tbw-row-dirty`, `.tbw-row-new` | Active editor and dirty tracking indicators |
| **Filtering** | `.tbw-filter-active` | Filter icon active state |
| **Grouping** | `.tbw-group-row`, `.tbw-group-toggle`, `.tbw-row-expanded` | Group header rows, expand/collapse icons, expanded group |
| **Tree** | `.tbw-row-expanded` | Parent rows whose children are visible |
| **Master/Detail** | `.tbw-row-expanded` | Master rows whose detail panel is showing |
| **Responsive** | `.tbw-card-view`, `.tbw-card-row` | Card layout mode styling |

:::tip[Style expanded rows with `.tbw-row-expanded`, not `[aria-expanded]`]
Tree, GroupingRows, and MasterDetail all toggle `.tbw-row-expanded` on the row element when it is in an expanded state. Use this class for theming. The `aria-expanded` attribute is reserved for assistive technology and may move (MasterDetail puts it on the toggle button, not the row), so styling against `[aria-expanded="true"]` is fragile and framework-specific.
:::

Override in your theme:

```css
@layer tbw-theme {
  tbw-grid .tbw-cell-selected {
    background: rgba(25, 118, 210, 0.15);
  }
  tbw-grid .tbw-row-dirty {
    border-left: 3px solid orange;
  }
  tbw-grid .tbw-row-expanded {
    background: rgba(25, 118, 210, 0.05);
  }
}
```

## Icon Customization

The grid uses a **CSS-first hybrid icon system** with two configuration paths:

| Approach | Best for | How it works |
|----------|----------|-------------|
| **CSS variables** (default) | Themes, static icons, no-JS customization | Override `--tbw-icon-*` properties on `tbw-grid` |
| **JavaScript** (`gridConfig.icons`) | Dynamic icons, icon libraries, runtime changes | Set `icons` in grid config — takes precedence over CSS |

CSS is the **recommended default** — it requires no JavaScript, works with cascade layers, and is tree-shakeable. Use the JS path when you need dynamic icons (e.g., loading from an icon library at runtime) or `HTMLElement` instances.

For the full list of icon keys with their TypeScript signatures, see the [`GridIcons` interface](/grid/api/core/interfaces/gridicons.md).

### JavaScript Path (`gridConfig.icons`)

For programmatic control (e.g., dynamic icon libraries, `HTMLElement` icons, or runtime theme switching), use `gridConfig.icons`. JavaScript values take precedence over CSS variables:

```typescript
grid.gridConfig = {
  icons: {
    sortAsc: '↑',
    sortDesc: '↓',
    expand: '+',
    collapse: '−',
    // Values may also be HTMLElement instances for fully custom markup
  },
};
```

All grid icons (sort indicators, expand/collapse, filter, drag handles, etc.) are rendered via CSS custom properties. The remainder of this section covers the CSS-first approach — override them in your theme.

### Text / Emoji Icons

Set the `--tbw-icon-<key>` variable to any CSS `<string>` value:

```css
@layer tbw-theme {
  tbw-grid {
    --tbw-icon-sort-asc: '↑';
    --tbw-icon-sort-desc: '↓';
    --tbw-icon-expand: '+';
    --tbw-icon-collapse: '−';
    --tbw-icon-size: 1.2em;
  }
}
```

### SVG Mask Icons

The **filter** and **filter-active** icons use SVG masks by default — just override their `-mask` variable:

```css
@layer tbw-theme {
  tbw-grid {
    --tbw-icon-filter: '';
    --tbw-icon-filter-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z'/%3E%3C/svg%3E");
  }
}
```

For **any other icon**, switching to mask mode requires setting the content to `''`, providing a `-mask` URL, and adding `background: currentColor` with explicit dimensions:

```css
@layer tbw-theme {
  tbw-grid {
    /* Set content to '' and provide the mask URL */
    --tbw-icon-sort-asc: '';
    --tbw-icon-sort-asc-mask: url("data:image/svg+xml,...");
  }

  /* Add background + dimensions so the mask is visible (cannot be shipped
     generically because they would affect text/emoji icon layout) */
  tbw-grid [data-icon='sort-asc']:empty::before {
    width: var(--tbw-icon-size, 1em);
    height: var(--tbw-icon-size, 1em);
    background: currentColor;
  }
}
```

The grid ships `mask-image`, `mask-size`, `mask-repeat`, and `mask-position` for every icon — you only need to add `background: currentColor`.

### Available Variables

| Variable | Default | Description |
|----------|---------|-------------|
| `--tbw-icon-expand` | `'▶'` | Tree / group / master-detail expand |
| `--tbw-icon-collapse` | `'▼'` | Tree / group / master-detail collapse |
| `--tbw-icon-sort-asc` | `'▲'` | Sort ascending indicator |
| `--tbw-icon-sort-desc` | `'▼'` | Sort descending indicator |
| `--tbw-icon-sort-none` | `'⇅'` | Unsorted indicator |
| `--tbw-icon-filter` | `''` (mask) | Column filter icon |
| `--tbw-icon-filter-active` | `''` (mask) | Active filter icon |
| `--tbw-icon-submenu-arrow` | `'▶'` | Context menu submenu arrow |
| `--tbw-icon-drag-handle` | `'⋮⋮'` | Row drag handle |
| `--tbw-icon-tool-panel` | `'☰'` | Tool panel toggle |
| `--tbw-icon-print` | `'🖨️'` | Print button |

Each icon also has a `-mask` variant (e.g., `--tbw-icon-sort-asc-mask`) for SVG mask-based rendering with `currentColor`.

## See Also

  - [Core Features](/grid/core.md): Column inference, renderers, row/cell styling, and animation
  - [Accessibility](/grid/guides/accessibility.md): High contrast mode and color requirements
  - [Architecture](/grid/architecture.md): CSS cascade layers and Light DOM design
  - [Responsive Plugin](/grid/plugins/responsive.md): Card layout mode with mobile-friendly responsive styling
