Skip to content

Installation

You install one adapter — Vue or React, or both — and optionally the stylesheet. The behaviour core comes along as a dependency of the adapter; you never install it yourself unless you are writing an adapter of your own.

Terminal window
# React 19
npm install @caioalfonso/kanso-react
# Vue 3
npm install @caioalfonso/kanso-vue

The framework is a peer dependency, never a dependency — react and react-dom at ^19, or vue at ^3.5. That is deliberate: bundling a second copy of the framework breaks hooks and reactivity in ways that are miserable to debug. Your app supplies the framework; kanso-ui uses the one you already have.

Vue is pinned at ^3.5 rather than ^3 because the adapter uses Vue’s built-in useId(), which landed in 3.5. Ids must come from the framework — see the server rendering guide for why a library-generated id is a hydration bug waiting to happen.

kanso-ui is headless. Without any CSS you get working, accessible, entirely unstyled components, and you write the appearance yourself against the data-part / data-state attributes.

If you want the Kanso look, or just a sensible starting point:

Terminal window
npm install @caioalfonso/kanso-styles

Both adapters expose one entry point per component, and so does the stylesheet. Importing from …/switch pulls in the Switch and nothing else — not Tabs, not Dialog, not the components you have never touched.

import { Switch } from '@caioalfonso/kanso-react/switch';
import '@caioalfonso/kanso-styles/tokens';
import '@caioalfonso/kanso-styles/base';
import '@caioalfonso/kanso-styles/switch';

The same subpath works across all three packages. /switch is the Switch in the React adapter, in the Vue adapter, and in the stylesheet.

ComponentSubpath
Switch/switch
Tabs/tabs
Dialog/dialog
Menu/menu
Field/field
Button/button
Card/card

Most subpaths export a single assembled component. /field exports three — Field, Input and Textarea — and the compound components also export their individual parts, TabsRoot, TabsList, TabsTrigger, TabsContent and so on, for when you need to control the markup rather than accept the default. Each component page lists its own.

There is a root entry on every package, if you would rather not think about it:

import { Switch, Tabs, Dialog } from '@caioalfonso/kanso-react';
import '@caioalfonso/kanso-styles';

Reach for this in a prototype. In an application, prefer the per-component subpaths — the root CSS import is every component’s styles whether or not you render them, and CSS does not tree-shake.

Subpath imports resolve only under a modern module resolution mode. If @caioalfonso/kanso-react/switch reports as missing while @caioalfonso/kanso-react resolves fine, this is why:

{
"compilerOptions": {
"moduleResolution": "bundler"
}
}

"node16" and "nodenext" work too. The legacy "node" mode predates the exports field and cannot see subpaths at all.

import { connect, switchAnatomy } from '@caioalfonso/kanso-core/switch';

@caioalfonso/kanso-core holds the behaviour — state machine, keyboard, ARIA, focus management — as plain TypeScript with zero dependencies and no import of any framework. Both adapters depend on it, so it is already installed.

Install it directly only if you are writing a third adapter, or reading the state machine to understand what a component does. Application code imports from an adapter. See the architecture guide for what the core actually hands back.