suiss/ui
Installation
Set up a React, React Native, SwiftUI or Jetpack Compose project with init, then add the components you need.
Requirements
- React with TypeScript, such as Next.js or Vite
- Tailwind CSS 4.2 or later
- Node.js 18 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:
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.
Combobox, drawer and toast use the default base's primitives in all three. Stepper does too in the second base, and 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:
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:
The full catalog is at ui.suiss.app/r/registry.json, the second base's at ui.suiss.app/r/radix/registry.json and the third base's at 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.
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.
What init does
- Detects Next.js or Vite and checks for TypeScript and Tailwind CSS 4.2 or later.
- Adds the
@/*import alias totsconfig.jsonif it is missing. - Installs and wires up Tailwind CSS if needed:
postcss.config.mjsfor Next.js,vite.config.tsfor Vite. - Writes the theme stylesheet to
app/globals.css(Next.js) orsrc/index.css(Vite). It asks before replacing a stylesheet that already has content. - Sets up the font. Text uses the system font on macOS and Inter everywhere else. Inter is loaded with
next/font/googlein the root layout (Next.js), or with@fontsource-variable/interimported from the stylesheet (Vite). - Installs
tw-animate-cssandshadcn, 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. - Adds the
buttoncomponent and thecnhelper it uses.
Add components with the suiss/ui CLI
Pass one or more component names to add.
Run add without names to pick from a list instead. Choose a group, type to filter, select with space and press enter. See CLI.
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:
Then import and use them:
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:
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.
With the registry CLI, add the item again with --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 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 .... |
Requirements
- An Expo or React Native project with TypeScript
- The
@/*import alias intsconfig.json, such as"paths": { "@/*": ["./*"] } - For Uniwind or NativeWind, the styling library set up as its own guide describes, with
global.cssimported 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:
| 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:
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
- Uniwind: writes
theme-suiss.cssto the root of your project and imports it fromglobal.css. Ifglobal.csslives in another folder, fix the path of that import. - NativeWind: adds the color variables to
global.cssand the colors, type scale, shadows and radius scale totailwind.config.js. - StyleSheet: writes
components/ui/theme.tswith the colors and auseTheme()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:
The catalogs are at ui.suiss.app/r/rn-uniwind/registry.json, ui.suiss.app/r/rn-nativewind/registry.json and 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.
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
buttoncomponent
The styling library is detected from your project. When neither Uniwind nor NativeWind is installed, init asks. Pass --styling to choose up front:
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
Run add without names to pick from a list instead. See CLI.
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:
Requirements
- iOS 17 or later.
- Components with icons use the Phosphor 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.
Add components
Leave out the names to pick from a list that only shows what exists for SwiftUI. The CLI lists the Swift packages a component needs; add them to your app target in Xcode.
Manual setup
- Add the Phosphor package to your app:
- Copy the theme files,
Theme.swiftandTokens.swift. Every view uses them. - 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:
Every color in Tokens.swift has a light and a dark value, so views follow the system appearance without extra setup.
Requirements
minSdk24 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.
Add components
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
- Add the dependencies:
- Copy the theme files,
Theme.ktandTokens.kt. Every composable uses them. - Copy the component and the files it uses.
- Update the
com.esuiss.uipackage names to match your project.
Usage
Wrap your content in EsuissTheme, then use the components:
EsuissTheme follows the system setting through isSystemInDarkTheme(). Pass darkTheme to choose a mode yourself.