

# Getting started

This guide is the happy path for a **Vite + React 19** app: install from npm, import CSS, wrap providers, and render a Button.

## Install

```bash
pnpm add @var-ui/react @var-ui/core @var-ui/icons react react-dom react-aria-components
```

```bash
npm install @var-ui/react @var-ui/core @var-ui/icons react react-dom react-aria-components
```

`@var-ui/icons` is optional. Without it, pass `icons={{}}` to `IconProvider`.

You do not add `typestyles` to the app. It arrives with `@var-ui/core`.

## Import CSS

```ts
import '@var-ui/core/styles.css';
```

That file includes every recipe, base HTML styles, and the default theme. Custom `createDesignTheme` modules and unused-recipe shedding use extract instead — see [Installation](/docs/installation).

## Providers

Mount `DesignSystemProvider` with `applyToDocument`, `IconProvider`, and `LayerProvider` at the root:

```tsx
import { defaultIcons } from '@var-ui/icons';
import { DesignSystemProvider, IconProvider, LayerProvider } from '@var-ui/react';

<DesignSystemProvider applyToDocument>
  <IconProvider icons={defaultIcons}>
    <LayerProvider>{children}</LayerProvider>
  </IconProvider>
</DesignSystemProvider>;
```

Without `@var-ui/icons`, pass `icons={{}}` to `IconProvider`.

`applyToDocument` puts the theme class on `html`. Isolate stacking and cover the visual viewport:

```css
html {
  isolation: isolate;
}

body {
  position: relative;
}
```

## First component

```tsx
import { Button } from '@var-ui/react';

<Button>Click me</Button>;
```

## Astro without React

```bash
pnpm add @var-ui/astro @var-ui/core
```

Import the same stylesheet in a layout, then import Astro components:

```astro
---
import '@var-ui/core/styles.css';
import { Button } from '@var-ui/astro';
---

<Button>Click me</Button>
```

See `examples/astro-app` in the repo for a full **workspace** tree. That example still extracts CSS with the TypeStyles Vite plugin because it lives in this monorepo.

## Next

- [Installation](/docs/installation) — package list, peers, and TypeStyles extract for custom themes
- [Overlay lifecycle](/docs/overlay-lifecycle) — overlay `data-*` attributes, positioner CSS variables, and `onOpenChange`
- [Theming](/theming) — tokens, themes, and `createDesignTheme`

## Direction, portals, and stacking

### Direction and locale

Pass `direction` and a real `locale` on `DesignSystemProvider`:

```tsx
<DesignSystemProvider applyToDocument direction="rtl" locale="he-IL">
  {children}
</DesignSystemProvider>
```

`applyToDocument` syncs `html dir` (and `lang` when `locale` is set) after hydration / on mount. It always writes `dir` for the resolved direction — including default `ltr`. If SSR set `<html dir="rtl">` and the client provider omits `direction`/`locale`, mount will rewrite `dir` to `ltr`. SSR apps that care about first paint should set `<html dir>` (and `lang` if needed) themselves **and** pass matching `direction`/`locale` to the provider.

React Aria overlays (`Popover`, `Menu`, `start` / `end` placement) take direction from **locale**, not from `dir`. `I18nProvider` only accepts `locale`.

- Prefer a real RTL locale (`he-IL`, `ar-EG`) so dates, numbers, and overlays agree.
- `direction="rtl"` with no locale wraps `I18nProvider` with `ar` so placement still flips. That workaround does **not** set `html lang="ar"`.
- `direction="ltr"` (explicit) with no locale wraps `I18nProvider` with `en-US` so a nested LTR island does not inherit a parent RTL locale for overlay placement.
- `locale="en-US"` plus `direction="rtl"` keeps English formatting; overlays may **not** flip.
- If you omit `direction` but pass `locale`, `dir` is derived from RAC `isRTL(locale)`.
- `useDirection()` returns `{ direction, isRtl }` and defaults to `ltr` when no provider is mounted.
- Directional icons opt in: `<Icon name="chevronRight" data-mirror={isRtl || undefined} />`.

Do not set `dir` on the whole docs site to try this — use a `DirectionProvider` island (see Hidden).

### Portals and stacking

Wrap the application in an isolating root so portaled dialogs and popovers stack above page `z-index`:

```html
<body>
  <div class="root">{children}</div>
</body>
```

```css
.root {
  isolation: isolate;
}
```

When `DesignSystemProvider` uses `applyToDocument`, put `isolation: isolate` on `html` or `body` instead of an extra wrapper.

#### Themed portals

Token CSS variables cascade from the theme class. If an overlay portals to `document.body` and the theme class is on a subtree, pass `portalContainer` pointing at the themed node (or use `applyToDocument`).

#### iOS 26+ Safari backdrops

Dialog and drawer backdrops use `position: absolute` under `@supports (-webkit-touch-callout: none)`. Add `body { position: relative; }` so a scrolled page still covers the visual viewport.

Overlay `data-*` attributes, positioner CSS variables, and `onOpenChange` details are documented in [Overlay lifecycle](/docs/overlay-lifecycle).
