# Installation

Set up a React, React Native, SwiftUI or Jetpack Compose project with init, then add the components you need.

Source: https://ui.suiss.app/docs/installation

**React**

## Requirements

- React with TypeScript, such as Next.js or Vite
- Tailwind CSS 4.2 or later
- Node.js 20 or later

## Add components

suiss/ui is a registry under the `@esuiss` namespace. In any project with a `components.json`, add components with the registry CLI:

```bash title="Terminal"
npx shadcn@latest add @esuiss/button @esuiss/dialog @esuiss/sidebar
```

Each item comes with the components, hooks and npm packages it depends on, and its icons are written for the icon library set in `components.json`. Patterns go to `components/patterns/`, interactions to `components/interactions/`, charts to `components/charts/` and blocks to `components/blocks/`.

### Choose the primitive base

Every item is published for three primitive bases under the same name. The registry picks one from the `style` in your `components.json`, so `@esuiss/dialog` installs the second base in a project whose style is `radix-nova`, the third in one whose style is `aria-nova`, and the default base everywhere else:

| `style` in `components.json` | Primitive base |
| --- | --- |
| `base-nova`, `base-vega` and every other style | The default base |
| `radix-nova`, `radix-vega` and any other `radix-*` style, `new-york`, `default` | The second base |
| `aria-nova`, `aria-vega` and any other `aria-*` style | The third base |

All three install the same files into the same folders, with the same component names and styles. They differ in how a part takes a custom element: the default base passes it to `render`, the second base wraps it with `asChild`, and in the third base the pressable element itself is the trigger, with state props such as `isOpen` and `isDisabled`. Patterns, `Button`, `Checkbox` and `AccordionItem` on the third base also take the default base's prop names, such as `open`, `disabled`, `checked` and, on pattern triggers, `render`.

```tsx
<DialogTrigger render={<Button variant="outline" />}>Open</DialogTrigger>

<DialogTrigger asChild>
  <Button variant="outline">Open</Button>
</DialogTrigger>

<Dialog>
  <Button variant="outline">Open</Button>
  <DialogContent>…</DialogContent>
</Dialog>
```

Combobox, drawer and toast use the default base's primitives in all three. Stepper does too in the second base, and direction, menubar and navigation menu in the third. The code on this site shows the default base with Phosphor icons. Pick another base or icon library under code options in the header to see the code you will get. Previews always run on the default base.

To start a new project, pick the base when you set it up:

```bash title="Terminal"
npx shadcn@latest init --base base
npx shadcn@latest init --base radix
npx shadcn@latest init --base aria
```

### Register the namespace

Once `@esuiss` is listed in the public registry directory, the namespace works without any setup. Until then, add it to `components.json` once:

```json title="components.json"
{
  "registries": {
    "@esuiss": "https://ui.suiss.app/r/{style}/{name}.json"
  }
}
```

The full catalog is at [ui.suiss.app/r/registry.json](https://ui.suiss.app/r/registry.json), the second base's at [ui.suiss.app/r/radix/registry.json](https://ui.suiss.app/r/radix/registry.json) and the third base's at [ui.suiss.app/r/aria/registry.json](https://ui.suiss.app/r/aria/registry.json).

### Use the suiss/ui theme

Adding components never changes your colors. To switch to the suiss/ui theme, add it as an item. See [Theming](https://ui.suiss.app/docs/theming#the-theme-item).

```bash title="Terminal"
npx shadcn@latest add @esuiss/theme-suiss
```

## Use the suiss/ui CLI

The suiss/ui CLI sets up a Next.js or Vite project from scratch, writes the full theme stylesheet and uses Phosphor icons. Run `init` once, in the root of your project.

```bash title="Terminal"
npx @esuiss/ui@latest init
```

### What init does

1. Detects Next.js or Vite and checks for TypeScript and Tailwind CSS 4.2 or later.
2. Adds the `@/*` import alias to `tsconfig.json` if it is missing.
3. Installs and wires up Tailwind CSS if needed: `postcss.config.mjs` for Next.js, `vite.config.ts` for Vite.
4. Writes the theme stylesheet to `app/globals.css` (Next.js) or `src/index.css` (Vite). It asks before replacing a stylesheet that already has content.
5. Sets up the font. Text uses the system font on macOS and Inter everywhere else. Inter is loaded with `next/font/google` in the root layout (Next.js), or with `@fontsource-variable/inter` imported from the stylesheet (Vite).
6. Installs `tw-animate-css` and `shadcn`, whose stylesheets provide the animations, variants and utilities the components rely on. The stylesheet imports them, as in any project set up with the registry CLI.
7. Adds the `button` component and the [`cn` helper](#the-cn-helper) it uses.

### Add components with the suiss/ui CLI

Pass one or more component names to `add`.

```bash title="Terminal"
npx @esuiss/ui@latest add button dialog sidebar
```

Run `add` without names to pick from a list instead. Choose a group, type to filter, select with space and press enter. See [CLI](https://ui.suiss.app/docs/cli#pick-from-a-list).

```bash title="Terminal"
npx @esuiss/ui@latest add
```

Components are written to `components/ui/` under your `@/*` alias root. Components they depend on are added too, and missing npm packages are installed with your package manager: npm, pnpm, yarn or bun.

The suiss/ui CLI uses the default base. In a project whose `components.json` has a `radix-*`, `new-york` or `default` style, it adds the second base instead, and with an `aria-*` style the third. Pass `--base` to choose for yourself:

```bash title="Terminal"
npx @esuiss/ui@latest init --base radix
npx @esuiss/ui@latest add dialog --base radix
npx @esuiss/ui@latest add dialog --base aria
```

Then import and use them:

```tsx title="components/example.tsx"
import { Button } from "@/components/ui/button"

export function Example() {
  return <Button>Continue</Button>
}
```

## The cn helper

Components merge class names with `cn`, imported from `@/lib/utils`. `init` and `add` write it to `lib/utils.ts` under your `@/*` alias root when it is missing. To add it by hand, install `cn` and create the file:

- `lib/utils.ts`: [source](https://github.com/e-suiss/ui/blob/main/packages/web/lib/utils.ts)

## Update components

Components are your code, so updates never overwrite your changes silently. Review the latest version first, then replace your copy if you want it.

```bash title="Terminal"
npx @esuiss/ui@latest add button --diff
npx @esuiss/ui@latest add button --overwrite
```

With the registry CLI, add the item again with `--overwrite`:

```bash title="Terminal"
npx shadcn@latest add @esuiss/button --overwrite
```

Running `add` for a component you already have keeps your file and tells you when it differs from the registry.

## Troubleshooting

| Message | Fix |
| --- | --- |
| Tailwind CSS 4.2 or later is required | Upgrade with `npm install tailwindcss@latest` and run `init` again. |
| No `@/*` import alias found | Run `init` first, or add `"paths": { "@/*": ["./src/*"] }` to `compilerOptions` in `tsconfig.json`. |
| `Unknown registry "@esuiss"` | Add the `registries` entry from [Register the namespace](#register-the-namespace) to `components.json`. |
| A newly published version is not found | npm can take a few minutes to make new versions available. Run `npx --prefer-online @esuiss/ui@latest ...`. |

**React Native**

## Requirements

- An Expo or React Native project with TypeScript
- The `@/*` import alias in `tsconfig.json`, such as `"paths": { "@/*": ["./*"] }`
- For Uniwind or NativeWind, the styling library set up as its own guide describes, with `global.css` imported in your root component

## Add components

The React Native components are published as a registry too, once per styling library. Add a `components.json` to the root of your project and point the `@esuiss-rn` namespace at the registry for your styling:

```json title="components.json"
{
  "$schema": "https://ui.shadcn.com/schema.json",
  "style": "new-york",
  "rsc": false,
  "tsx": true,
  "tailwind": {
    "config": "",
    "css": "global.css",
    "baseColor": "neutral",
    "cssVariables": true
  },
  "aliases": {
    "components": "@/components",
    "utils": "@/lib/utils",
    "ui": "@/components/ui",
    "lib": "@/lib",
    "hooks": "@/hooks"
  },
  "registries": {
    "@esuiss-rn": "https://ui.suiss.app/r/rn-uniwind/{name}.json"
  }
}
```

| Styling | `@esuiss-rn` registry | `tailwind` in `components.json` |
| --- | --- | --- |
| Uniwind | `https://ui.suiss.app/r/rn-uniwind/{name}.json` | `"css": "global.css"` |
| NativeWind v4 | `https://ui.suiss.app/r/rn-nativewind/{name}.json` | `"css": "global.css"`, `"config": "tailwind.config.js"` |
| StyleSheet | `https://ui.suiss.app/r/rn-stylesheet/{name}.json` | `"css": ""` |

Then add components with the registry CLI:

```bash title="Terminal"
npx shadcn@latest add @esuiss-rn/button @esuiss-rn/dialog @esuiss-rn/select
```

Each item comes with the components, primitives and npm packages it depends on. In Expo projects packages are installed with `expo install`, so native modules match the Expo SDK. Components go to `components/ui/`, the primitives they build on to `components/primitives/`, patterns to `components/patterns/`, interactions to `components/interactions/`, charts to `components/charts/` and blocks to `components/blocks/`. Icons use `phosphor-react-native`.

### Add the theme

```bash title="Terminal"
npx shadcn@latest add @esuiss-rn/theme-suiss
```

- Uniwind: writes `theme-suiss.css` to the root of your project and imports it from `global.css`. If `global.css` lives in another folder, fix the path of that import.
- NativeWind: adds the color variables to `global.css` and the colors, type scale, shadows and radius scale to `tailwind.config.js`.
- StyleSheet: writes `components/ui/theme.ts` with the colors and a `useTheme()` hook. Every component that needs it adds it on its own.

### Render the portal host

Dialogs, sheets, menus and toasts render into a portal host. Render it once, as the last child of your root component:

```tsx title="App.tsx"
import { View } from "react-native"
import { PortalHost } from "@/components/primitives/portal"
import { Button } from "@/components/ui/button"
import { Text } from "@/components/ui/text"

export default function App() {
  return (
    <View style={{ flex: 1 }}>
      <Button>
        <Text>Continue</Text>
      </Button>
      <PortalHost />
    </View>
  )
}
```

The catalogs are at [ui.suiss.app/r/rn-uniwind/registry.json](https://ui.suiss.app/r/rn-uniwind/registry.json), [ui.suiss.app/r/rn-nativewind/registry.json](https://ui.suiss.app/r/rn-nativewind/registry.json) and [ui.suiss.app/r/rn-stylesheet/registry.json](https://ui.suiss.app/r/rn-stylesheet/registry.json).

## Use the suiss/ui CLI

The suiss/ui CLI sets up the styling library, the theme, the Metro config and the portal host for you. Run `init` once, in the root of your project.

```bash title="Terminal"
npx @esuiss/ui@latest init
```

`init` sets up:

- the styling library: Uniwind, NativeWind or StyleSheet
- the `@/*` import alias
- the theme stylesheet
- the Metro config
- the portal host in the root layout
- the `button` component

The styling library is detected from your project. When neither Uniwind nor NativeWind is installed, `init` asks. Pass `--styling` to choose up front:

```bash title="Terminal"
npx @esuiss/ui@latest init --styling uniwind
npx @esuiss/ui@latest init --styling nativewind
npx @esuiss/ui@latest init --styling stylesheet
```

StyleSheet needs no Tailwind. `init` writes `components/ui/theme.ts` with the colors and a `useTheme()` hook. For NativeWind, `init` also writes `tailwind.config.js` and the NativeWind Babel preset.

### Add components with the suiss/ui CLI

```bash title="Terminal"
npx @esuiss/ui@latest add dialog
```

Run `add` without names to pick from a list instead. See [CLI](https://ui.suiss.app/docs/cli#pick-from-a-list).

Components are copied into `components/ui/` together with the components and packages they depend on.

### React Native without Expo

`init` also adds the `@/*` alias to Babel with `babel-plugin-module-resolver`, and `add` adds the Reanimated Babel plugin when a component needs it. Run `pod install` after adding components:

```bash title="Terminal"
cd ios && pod install
```

**SwiftUI**

## Requirements

- iOS 17 or later.
- Components with icons use the [Phosphor](https://github.com/phosphor-icons/swift) Swift package.
- Charts are drawn with Apple's Swift Charts framework, which ships with iOS.

## Set up your project

Run `init` in the folder that holds your Xcode project or `Package.swift`. It copies the theme files, `Theme.swift` and `Tokens.swift`, and the button.

```bash title="Terminal"
npx @esuiss/ui@latest init --platform swift
```

## Add components

```bash title="Terminal"
npx @esuiss/ui@latest add button --platform swift
```

Leave out the names to pick from a list that only shows what exists for SwiftUI. The CLI prints what a component needs on each platform, such as Swift packages; add them to your app target in Xcode.

### Manual setup

1. Add the Phosphor package to your app:

```swift title="Package.swift"
.package(url: "https://github.com/phosphor-icons/swift", from: "2.1.0")
```

2. Copy the theme files, `Theme.swift` and `Tokens.swift`. Every view uses them.
3. Copy the component and the files it uses, then add them to your app target.

## Usage

Components follow SwiftUI conventions. The button, for example, is a button style:

```swift
struct ContentView: View {
  var body: some View {
    Button("Continue") {}
      .buttonStyle(.variant())
  }
}
```

Every color in `Tokens.swift` has a light and a dark value, so views follow the system appearance without extra setup.

**Jetpack Compose**

## Requirements

- `minSdk` 24 or higher.
- Jetpack Compose Foundation and UI. The components do not depend on Material.
- Components with icons use the Phosphor icons library for Android.

## Set up your project

Run `init` in the folder that holds your Android Gradle module. It copies the theme files, `Theme.kt` and `Tokens.kt`, and the button.

```bash title="Terminal"
npx @esuiss/ui@latest init --platform kotlin
```

## Add components

```bash title="Terminal"
npx @esuiss/ui@latest add button --platform kotlin
```

Leave out the names to pick from a list that only shows what exists for Jetpack Compose. The CLI lists the Gradle dependencies a component needs; it never edits your Gradle files.

### Manual setup

1. Add the dependencies:

```kotlin title="build.gradle.kts"
implementation(platform("androidx.compose:compose-bom:2026.09.00"))
implementation("androidx.compose.foundation:foundation")
implementation("androidx.compose.ui:ui")
implementation("com.adamglin:phosphor-icon-android:1.0.0")
```

2. Copy the theme files, `Theme.kt` and `Tokens.kt`. Every composable uses them.
3. Copy the component and the files it uses.
4. Update the `com.esuiss.ui` package names to match your project.

## Usage

Wrap your content in `EsuissTheme`, then use the components:

```kotlin
@Composable
fun App() {
    EsuissTheme {
        Button("Continue", onClick = {})
    }
}
```

`EsuissTheme` follows the system setting through `isSystemInDarkTheme()`. Pass `darkTheme` to choose a mode yourself.

