# Getting Started

## Install

```bash
npm install @tangible/ui
```

### Optional peer dependencies

Some components require additional packages. Install only what you use:

| Package | Required by |
| - | - |
| `@floating-ui/react` | Select, MultiSelect, Combobox, Dropdown, Tooltip |
| `@tanstack/react-table` | DataTable |

```bash
# If using Select, Dropdown, Tooltip, etc.
npm install @floating-ui/react

# If using DataTable
npm install @tanstack/react-table
```

Components without these dependencies (Button, Card, Accordion, Modal, Tabs, etc.) work with zero additional installs.

## Import styles

In your app entry point:

```tsx
import '@tangible/ui/styles';
```

Or if you're using SCSS and want access to tokens/mixins:

```scss
@use '@tangible/ui/styles/scss';
```

### CSS cascade layers

TUI uses internal CSS layers (`resets`, `defaults`, `components`, `utilities`) to organise its own cascade. This works well when you control the full page.

**For WordPress plugin contexts** where theme CSS is unlayered, use the unlayered build — unlayered CSS always beats layered CSS regardless of specificity:

```tsx
import '@tangible/ui/styles/unlayered';
```

| Import | Use when |
| - | - |
| `@tangible/ui/styles` | You control the full page |
| `@tangible/ui/styles/unlayered` | WordPress plugins, embedded UIs competing with theme CSS |

## Wrap your app

Components require the `.tui-interface` wrapper to access design tokens:

```tsx
function App() {
  return (
    <div className="tui-interface">
      {/* Your UI here */}
    </div>
  );
}
```

This wrapper:

- Scopes all `--tui-*` CSS custom properties
- Prevents style leakage in WordPress environments
- Enables portaled content (tooltips, modals) to inherit tokens automatically

### Dark mode

Set `data-theme` on the wrapper:

```tsx
<div className="tui-interface" data-theme="dark">
```

| Value | Behaviour |
| - | - |
| `"dark"` | Force dark mode |
| `"auto"` | Follow `prefers-color-scheme` |
| *(omit)* | Light mode (inherits host colour) |

## Use components

```tsx
import { Button, Card, Select } from '@tangible/ui';

function Example() {
  return (
    <Card>
      <Card.Body>
        <Button label="Save" theme="primary" />

        <Select placeholder="Choose..." onValueChange={(v) => console.log(v)}>
          <Select.Trigger />
          <Select.Content>
            <Select.Option value="a">Option A</Select.Option>
            <Select.Option value="b">Option B</Select.Option>
          </Select.Content>
        </Select>
      </Card.Body>
    </Card>
  );
}
```

### Tree-shaking

If your bundler doesn't tree-shake unused components from the barrel export, use individual imports:

```tsx
import { Button } from '@tangible/ui/components/Button';
import { Tooltip } from '@tangible/ui/components/Tooltip';
```

## Component patterns

### Compound components

Several components use dot notation for their parts:

```tsx
<Card>
  <Card.Head>Title</Card.Head>
  <Card.Body>Content</Card.Body>
  <Card.Foot>Footer</Card.Foot>
</Card>

<Accordion type="single" collapsible>
  <Accordion.Item value="item-1">
    <Accordion.Trigger>Section 1</Accordion.Trigger>
    <Accordion.Panel>Content here</Accordion.Panel>
  </Accordion.Item>
</Accordion>

<Modal open={isOpen} onClose={close} aria-labelledby="title" showCloseButton>
  <Modal.Head id="title">Edit Item</Modal.Head>
  <Modal.Body>Content</Modal.Body>
  <Modal.Foot>
    <Button label="Cancel" variant="ghost" onClick={close} />
    <Button label="Save" theme="primary" onClick={save} />
  </Modal.Foot>
</Modal>
```

### The `asChild` pattern

Some components accept `asChild` to merge props onto your own element instead of wrapping:

```tsx
{/* Without asChild — wraps in a span */}
<Tooltip.Trigger>
  <Button label="Hover" />
</Tooltip.Trigger>

{/* With asChild — props merged directly onto Button */}
<Tooltip.Trigger asChild>
  <Button label="Hover" />
</Tooltip.Trigger>
```

### Prop conventions

| Prop | Purpose | Values |
| - | - | - |
| `theme` | Semantic colour | `primary`, `secondary`, `success`, `warning`, `danger`, `info` |
| `variant` | Visual treatment | `solid`, `outline`, `ghost`, `link` (varies per component) |
| `size` | Component scale | `sm`, `md`, `lg` (varies per component) |
| `onValueChange` | Value callback | Used instead of `onChange` for non-native components |
| `open` / `defaultOpen` | Floating state | Controlled / uncontrolled for dropdowns, modals, etc. |

## Customising with tokens

### Token architecture

TUI uses a four-layer token system:

1. **Primitives** (`--tui-*`) — theme contract on `.tui-interface` (colours, spacing, radii)
2. **Component API** (`--tui-{component}-*`) — never defined by TUI, only read via fallback. Set these from your code.
3. **Internal** (`--_*`) — private to components, used for state management
4. **Structural** (`$_*`) — SCSS-only, compile away

```css
/* Override primitives globally */
.tui-interface {
  --tui-radius-md: 2px;
  --tui-focus-ring-color: hotpink;
}

/* Override a specific component's API token */
.my-context {
  --tui-button-radius: 0;
  --tui-accordion-padding: 8px;
  --tui-modal-spacing: 24px;
}
```

Each component's `styles.scss` header lists its full token API.

### Colour scale

Theme colours use a contrast-based naming scale: `subtlest → subtle → soft → base → strong → stronger → strongest`. "Stronger" always means more contrast against the background, making it consistent across light and dark modes.

### Form control sizing

All form controls (TextInput, Select, MultiSelect, Combobox) and buttons share unified height tokens:

```css
.my-context .tui-interface {
  --tui-control-height-sm: 28px;
  --tui-control-height-md: 32px;
  --tui-control-height-lg: 40px;

  /* Optional: decouple font size from size tier */
  --tui-control-font-size-sm: 13px;
  --tui-control-font-size-md: 13px;
  --tui-control-font-size-lg: 14px;
}
```

### Modal viewport offsets

Modal supports offset tokens for host chrome like the WordPress admin bar or sidebar:

```css
.wp-admin .tui-modal {
  --tui-modal-offset-top: 32px;     /* admin bar */
  --tui-modal-offset-start: 160px;  /* sidebar */
}
```

Offset tokens fall back to `env(safe-area-inset-*)` for device notch/home indicator clearance.

## Icons

Four icon sets via the registry: `system`, `cred`, `reaction`, `player`.

```tsx
import { Icon } from '@tangible/ui';

<Icon name="system/check" />
<Icon name="system/settings" size="lg" />
<Icon name="reaction/clap-fill" />
```

Browse available icons in the **Icon** story.

## CSS-only usage

Form inputs and some utilities work without React:

```html
<div class="tui-interface">
  <input type="text" class="tui-input" placeholder="Text input" />

  <label class="tui-inline-choice">
    <input type="checkbox" />
    <span>Checkbox label</span>
  </label>

  <label class="tui-toggle">
    <input type="checkbox" id="toggle-1" />
    <label for="toggle-1">Toggle label</label>
  </label>
</div>
```

See the **Inputs** story for all available form patterns.

---

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