# Tangible UI class naming and CSS structure

Tangible UI aims to be predictable to work with, hard to accidentally override, and polite to the host theme. This document describes how class names are structured, how styles are scoped, and how to extend or override them safely.

## Prefixes and high‑level conventions

Tangible UI uses three layers of naming to keep styles organized and collision‑free:

1. **Interface wrapper** – scopes all Tangible UI styles
2. **Block / component classes** – identify the UI pattern
3. **Element and modifier classes** – identify sub‑parts and variations

### Interface wrapper: `.tui-interface`

All Tangible UI components are expected to live inside a wrapper with the class `.tui-interface`. This wrapper is the primary guardrail against leaking styles into the rest of a site, and it also gives us a consistent way to increase specificity when we need to.

Example markup:

```html
<div class="tui-interface">
  <div class="tui-card tui-card__body">
    ...
  </div>
</div>
```

Example SCSS:

```scss
.tui-interface {
  // global resets and layout helpers for Tangible UI only

  .tui-card {
    // card styles
  }
}
```

When writing new component styles, assume they will always be rendered inside `.tui-interface` and keep selectors nested under that wrapper in SCSS.

### Component blocks: `tui-<component>`

Components are named with a `tui-` prefix followed by a descriptive block name:

- `tui-button`
- `tui-card`
- `tui-chip`
- `tui-table`
- `tui-modal`
- `tui-progress`

This avoids collisions with theme classes like `button`, `card`, or `table`, and makes it obvious which CSS belongs to Tangible UI.

### Elements and modifiers

Tangible UI loosely follows [BEM](https://getbem.com/naming/)-like patterns:

- **Element**: `tui-card__head`, `tui-card__body`, `tui-card__foot`
- **Modifier (state or variant)**: `.is-primary`, `.is-secondary`, `.is-outline`, `.is-active`, `.is-disabled`

Patterns you will see:

- `tui-card__head` – element
- `tui-card__body` – element
- `tui-card__foot` – element
- `tui-button is-primary` – primary variant
- `tui-button is-outline` – outline layout
- `tui-chip is-selectable is-selected` – selectable chip in selected state

Modifiers never stand alone. They always appear on top of a base block class.

```html
<button class="tui-button is-primary is-outline">Save changes</button>
```

Do not create new global modifier names for one‑off cases. Prefer component‑specific modifiers when necessary, or data attributes for very custom states.

### Design tokens: `--tui-{category}-{axis}-{step}`

Token names use one grammar, where the category is a design-language noun —
not a CSS property name:

- **Categories**: `color`, `theme`, `spacing`, `radius`, `motion`,
  `typography`, `shadow`, `layer`, `focus-ring`, `opacity`
- **Axis**: the dimension within the category (`weight`, `size`,
  `line-height`, `bg`, `fg`, `border`)
- **Step**: the point on the scale (`sm`/`md`/`lg`, `normal`/`tight`,
  `medium`/`semibold`, `base`/`subtle`/`strong`)

Examples: `--tui-typography-weight-semibold`, `--tui-color-bg-muted`,
`--tui-theme-primary-subtlest`, `--tui-spacing-md`.

The grammar is what makes token names guessable: if you know
`--tui-typography-size-sm`, you can derive `--tui-typography-weight-medium`
without looking it up. The corollaries:

- **One name per concept.** Never introduce a synonym for an existing token
  (the pre-0.0.20 system briefly had both `--tui-font-weight-*` and
  `--tui-typography-weight-*`; that class of duplication is a defect).
- **Don't mirror CSS property names.** `--tui-typography-weight-*`, not
  `--tui-font-weight-*` — half the system (`theme`, `spacing`) has no CSS
  property to mirror, so property-mirroring would always mean two grammars.
- **Component API tokens** are namespaced by component instead:
  `--tui-{component}-{property}` (e.g. `--tui-button-bg`,
  `--tui-pager-item-border`). TUI never defines these, only reads them —
  see the [Read-Only Component API](https://storybook-tangible-ui.pages.dev/docs/system-architecture.md)
  pattern in CONTRIBUTING.

---

## Wrapper and specificity strategy

### Why the wrapper exists

The `.tui-interface` wrapper ensures:

- Tangible UI resets and utilities do not leak into the host theme
- Components can rely on predictable base styles
- We can rely on a small, controlled increase in specificity when needed

All Tangible UI SCSS should be written in the form:

```scss
:where(.tui-interface) {
  .tui-button { ... }
  .tui-card { ... }
  .tui-table { ... }
}
```

Avoid targeting elements without the wrapper.

### Recommended specificity

Aim to keep selectors shallow and class‑only:

- Typical rule: `:where(.tui-interface) .tui-button`
- Element rule: `:where(.tui-interface) .tui-card__head`
- Variant rule: `:where(.tui-interface) .tui-button.is-primary`

`:where()` targets without adding specificity.

Avoid:

- IDs
- Type selectors (`button`, `h2`) as part of non-reset component rules
- Deep descendant chains (more than 2–3 classes)

If overriding Tangible UI from a plugin or theme, prefer to match class‑only specificity as well. For example, to override a primary button:

```scss
.tui-interface .tui-button.is-primary {
  background-color: ...;
}
```

---

## Structure of Tangible UI styles

Tangible UI SCSS is organized into several layers. The exact file layout may evolve, but the intent stays the same.

### System tokens

Located under `src/styles/system/`:

- Design tokens for color, spacing, typography, radius, shadows, breakpoints
- Palette helpers and mixins

These are the single source of truth for visual decisions. Components and utilities should depend on tokens, not hard‑coded values.

### Utilities

Located under `src/styles/utilities/`.

Utilities are small, single‑purpose classes for layout and spacing – things like:

- Flex and alignment helpers
- Gap and margin helpers
- Typography helpers
- Border and radius helpers

### Components

Components are co-located in `src/components/*/`:

```
src/components/Button/
├── Button.tsx           # React component
├── Button.stories.ts    # Storybook stories
├── styles.scss          # Component styles
└── index.ts             # Barrel export
```

Component styles mirror the React component structure:

- Block: `.tui-button`
- Elements: `.tui-button__icon`, `.tui-button__label`
- Modifiers: `.is-primary`, `.is-outline`, `.is-destructive`

See [Architecture](https://storybook-tangible-ui.pages.dev/docs/system-architecture.md) for full project structure.

---

Interactive version: https://storybook-tangible-ui.pages.dev/?path=/docs/system-naming--docs
