---
title: Stable component parts
editUrl: https://github.com/Cratis/Components/edit/main/Documentation/Styling/pass-through.md
description: Customize Components through typed Cratis part keys and documented DOM part values.
---


Components exposes two related styling surfaces:

- **Typed `pt` keys** use camel case and accept ordinary HTML attributes for one component instance.
- **DOM part values** appear in `data-cratis-part` and use kebab case where a name contains several words.

They are documented separately because not every DOM part needs a `pt` key, and the spellings are intentionally different (`headerRow` versus `header-row`).

## Typed pt keys

```tsx
<Dialog
    title='Edit account'
    pt={{
        backdrop: { className: 'account-dialog-backdrop' },
        root: { className: 'account-dialog' },
        content: { className: 'account-dialog-content' },
    }}
>
    Content
</Dialog>
```

| Component/type | Typed `pt` keys | Element types |
| --- | --- | --- |
| `ButtonParts` / `IconButtonParts` | `root`, `icon`, `label`, `spinner` | button, spans |
| `TextInputParts` / `TextAreaParts` | `root` | native input or textarea |
| `NumberInputParts` | `root`, `group`, `input`, `prefix`, `suffix`, `step`, `description`, `error` | owned number-field composition |
| `CheckboxParts` / `RadioParts` | `root`, `input`, `box`, `indicator`, `label` | label, native input, spans |
| `SwitchParts` | `root`, `input`, `control`, `handle`, `label` | label, native input, spans |
| `SurfaceParts` | `root` | div, section, or article |
| `DialogParts` | `backdrop`, `positioner`, `root`, `header`, `title`, `subtitle`, `close`, `content`, `footer`, `confirm`, `cancel` | divs/header/heading/footer/buttons |
| `ToggleGroupParts` | `root`, `option`, `icon`, `label` | group/buttons |
| `TabsParts` | `root`, `list`, `tab`, `panel` | divs/tabs/panels |
| `TagGroupParts` | `root`, `list`, `tag`, `remove`, `input` | div/list/tags/buttons/input |
| `BreadcrumbsParts` | `root`, `item`, `link`, `separator` | nav/ol/li/links |
| `DropdownParts` | `root`, `input`, `select`, `trigger`, `value`, `clear`, `indicator`, `popover`, `listbox`, `option`, `filter`, `multiple` | wrapper, input/button, spans, popover/listbox/options, select |
| `ComboBoxParts` | `root`, `input`, `trigger`, `popover`, `listbox`, `option`, `optionLabel`, `optionDescription`, `loading`, `empty`, `failure`, `action`, `description`, `error` | wrapper, input, button, popover/listbox/options, status text |
| `DatePickerInputPassThrough` | `root`, `group`, `input`, `placeholder`, `segment`, `trigger`, `popover`, `dialog`, `calendar`, `header`, `heading`, `previous`, `next`, `grid`, `cell`, `buttonBar`, `today`, `clear` | divs, segmented field, buttons, calendar grid/cells |
| `DataTableParts` | `root`, `search`, `searchInput`, `tableContainer`, `table`, `head`, `headerRow`, `headerCell`, `body`, `row`, `cell`, `emptyRow`, `emptyCell`, `loadingRow`, `loadingCell`, `failureRow`, `failureCell` | div/input/table sections/rows/cells |
| `ColumnFilterMenuParts` (`Column.filterPt`) | `trigger`, `popover`, `menu`, `matchMode`, `input`, `actions`, `clear`, `apply` | button, overlay/menu, inputs, actions |
| `TablePaginatorParts` | `root`, `range`, `info`, `first`, `previous`, `next`, `last` | navigation div, spans, and Button parts |
| `StepperParts` | `root`, `list`, `step`, `header`, `number`, `title`, `separator`, `panels`, `panel` | div, ordered list, list item, button, spans, section |
| `ChatSidebarParts` | `backdrop`, `root`, `header`, `title`, `back`, `close`, `content` | backdrop/panel divs, header, heading, buttons |
| `EventsViewParts` | `timeline`, `event`, `separator`, `marker`, `connector`, `content` | timeline divs and event elements |
| `ToasterPassThrough` | `region`, `toast`, `icon`, `content`, `title`, `description`, `close`, `action` | region/article/divs/spans/buttons |
| `ToolbarParts` / `ToolbarButtonParts` | toolbar `root`; button `root`, `icon`, `label` | toolbar div and native buttons/spans |
| `ToolbarGroupParts` / `ToolbarLayoutParts` | `root`, `slot`, `incoming`, `outgoing` | group/layout and transition measurement divs |
| `ToolbarSectionParts` | `root`, `context` | animated section and named context divs |
| `ToolbarSeparatorParts` | `root` | native separator div |
| `ToolbarFolderParts` / `ToolbarFanOutParts` | `root`, `trigger`, `panel` | composition div, native trigger, and inert collapsed panel |
| `ActionMenubar` `pt` | the `ButtonParts` keys applied to each action | button and spans |
| Query table / `DataPage` `paginatorPt` | `TablePaginatorParts` | paginator surface |
| `DataPage` `tablePt` | `DataTableParts` | table surface |
| `DataPage` `menubarPt` | `ButtonParts` | action buttons |

Command field part keys:

| Field | Typed keys |
| --- | --- |
| InputText / TextArea | `root` (the native control; see the DOM note below) |
| Number | `root`, `input` |
| NumberInput | `root`, `group`, `input`, `prefix`, `suffix`, `step`, `description`, `error` |
| Checkbox | `root`, `input`, `box`, `indicator` |
| ToggleSwitch | `root`, `input`, `control`, `handle` |
| Password | `root`, `input`, `toggle` |
| RadioButton | `root`, `input`, `box`, `indicator` |
| RadioGroup | `root`, `option`, `input`, `box`, `indicator` |
| Slider | `root`, `input`, `value` |
| Chips | `root`, `item`, `remove`, `input` |
| ColorPicker | `root`, `input`, `value` |
| Rating | `root`, `option`, `input`, `star` |
| Calendar | `DatePickerInputPassThrough` keys |
| Dropdown / MultiSelect | `DropdownParts` keys |

`InputTextParts.root` applies to the native element carrying `data-cratis-part='input'`; `TextAreaParts.root` applies to `data-cratis-part='textarea'`. The typed key is retained for source compatibility, but there is no extra field-root DOM wrapper.

Named behavior props override conflicting part attributes. Part classes and styles merge with component structure. `DropdownParts.input` and `select` are narrow Components 3 migration aliases for class, style, id, and ARIA values; attach event handlers and other ordinary attributes to the current `trigger`, `filter`, `multiple`, `listbox`, or `option` part instead.

## DOM part values

Use the exact kebab-case value in CSS or tests:

| Surface | `data-cratis-part` values |
| --- | --- |
| Button | `root`, `icon`, `label`, `spinner` |
| Basic controls | text inputs and surfaces use `root`; NumberInput uses `root`, `group`, `input`, `prefix`, `suffix`, `step`, `description`, `error`; choices use `root`, `input`, `label`, plus `box`/`indicator` or `control`/`handle` |
| Dialog | `backdrop`, `positioner`, `root`, `header`, `title`, `subtitle`, `close`, `content`, `busy-scope`, `footer`, `confirm`, `cancel` |
| ComboBox | `root`, `input`, `trigger`, `popover`, `listbox`, `option`, `optionLabel`, `optionDescription`, `loading`, `empty`, `failure`, `action`, `description`, `error` |
| ToggleGroup | `root`, `option`, `icon`, `label` |
| Tabs | `root`, `list`, `tab`, `panel` |
| TagGroup | `root`, `list`, `tag`, `remove`, `input` |
| Breadcrumbs | `root`, `item`, `link`, `separator` |
| Dropdown | `root`, `trigger`, `value`, `clear`, `indicator`, `filter`, `popover`, `listbox`, `option`, `multiple` |
| DatePicker | `root`, `group`, `input`, `placeholder`, `segment`, `trigger`, `popover`, `dialog`, `calendar`, `header`, `heading`, `previous`, `next`, `grid`, `cell`, `button-bar`, `today`, `clear` |
| DataTable | `root`, `search`, `search-input`, `table-container`, `table`, `head`, `header-row`, `header-cell`, `header-content`, `sort`, `select-all`, `filter-trigger`, `filter-popover`, `filter-menu`, `filter-actions`, `body`, `row`, `cell`, `empty-row`, `empty-cell`, `loading-row`, `loading-cell`, `failure-row`, `failure-cell` |
| TablePaginator | `root`, `range`, `info`; paginator buttons expose the documented Button parts |
| Stepper | `root`, `list`, `step`, `header`, `number`, `title`, `separator`, `panels`, `panel` |
| Toaster | `region`, `toast`, `icon`, `content`, `title`, `description`, `action`, `close` |
| Tooltip | `popup`; a standalone trigger uses `trigger`, while a composed child preserves its own component part and gains `data-cratis-tooltip-trigger` |
| Command fields | `root`, plus the typed field-specific values listed above (`input`, `textarea`, `group`, `box`, `control`, `handle`, `indicator`, `option`, `item`, `remove`, `value`, `star`, `toggle`) |
| Display | every component has `root`; Avatar adds `image`, `fallback`; Chip adds `icon`, `label`, `remove`; Message adds `icon`, `text`; ProgressBar adds `indicator`, `label`; ProgressSpinner adds `svg`, `track`, `range`; Tag adds `icon`, `label` |
| Chat sidebar | `backdrop`, `root`, `header`, `title`, `back`, `close`, `content` |
| Event timeline | `timeline`, `event`, `separator`, `marker`, `connector`, `content` |
| Toolbar | `root`, `button`, `icon`, `label`, `fanout-root`, `fanout-trigger`, `fanout-panel`, `toolbar-group`, `toolbar-separator`, `toolbar-layout`, `toolbar-section`, `toolbar-context`, `toolbar-slot`, `toolbar-slot-incoming`, `toolbar-slot-outgoing`, `toolbar-folder`, `toolbar-folder-trigger`, `toolbar-folder-panel` |

`busy-scope` wraps the Dialog content and footer in a `fieldset` that is disabled while the dialog is busy; it has no `DialogParts` key. ComboBox is the one surface whose multi-word DOM values keep the camel-case spelling of its keys (`optionLabel`, `optionDescription`); match them exactly.

The DataTable `root` exposes `data-busy` and the native `table` exposes `aria-busy="true"` during a refetch with rows. A failure row exposes `data-reason="failed"` or `"unauthorized"`; loading and failure messages have an inner status or alert element, not a role on the row.

`header-content`, `sort`, `select-all` (the multiple-selection header checkbox), and `filter-trigger` are DOM targets but are not `DataTableParts` keys. Customize them with CSS rather than claiming a nonexistent typed key.

`Tooltip` enhances the actual focusable child. If that child already has a component-specific `data-cratis-part` (for example `button`, `toolbar-folder-trigger`, or `fanout-trigger`), Tooltip preserves it and adds `data-cratis-tooltip-trigger`. It uses `data-cratis-part='trigger'` only for a child without its own stable part.

```css
[data-cratis-part='header-cell'] {
    text-transform: uppercase;
}

[data-cratis-part='row'][data-selected='true'] {
    background: var(--product-selected-row);
}
```

## State attributes

State attributes are component-specific. Common values include:

| Attribute | Meaning |
| --- | --- |
| `data-active` | Active filter, step, or action. |
| `data-selected` | Selected row, option, or value. |
| `data-invalid` | Validation error state. |
| `data-disabled` | Disabled component state. |
| `data-readonly` | Read-only date/control state. |
| `data-loading` | Loading toast/action. |
| `data-position` | Overlay, timeline, or region position. |
| `data-placement` | Dialog viewport placement: `center`, `start`, `end`. |
| `data-orientation` | Horizontal/vertical layout. |
| `data-size` | Component size variant. |
| `data-severity` | Semantic status tone. |

Do not assume an attribute exists on every component; use its documented parts/type and inspect the rendered Cratis contract in tests.

## Legacy flags

`ptOptions` and `unstyled` remain accepted temporarily for Components 3 source compatibility. They have no effect: typed Cratis attributes always merge, and styling is always CSS-owned.
