---
title: "CSS and UI-provider requirements"
description: "Design tokens, stylesheet order, Tailwind sources and the UI kit each surface needs."
canonical_url: "https://skaile-ai.github.io/forge-editor/reference/css-and-ui"
---
# CSS and UI-provider requirements

> Design tokens, stylesheet order, Tailwind sources and the UI kit each surface needs.

- Design tokens: `@skaile/forge-editor/styles/tokens.css` declares the shared `--sk-*` variables (`--sk-bg`, `--sk-fg`, `--sk-muted`, `--sk-border`, `--sk-primary`, `--sk-primary-fg`, `--sk-success`, `--sk-warning`, `--sk-danger`, `--sk-radius`, `--sk-font`) with light defaults under `:where(:root)` and dark values under `:where(.dark)`. Every feature stylesheet reads them; a UI kit maps them onto its own variables (Nuxt UI: `vue/kit/nuxt-ui.css`, React/shadcn: `react/styles/ui-vars.css`), a host may override them once.
- Basket colours: `@skaile/forge-editor/styles/composites.css` declares the colours of the default colour Baskets (`compositeFeature({ baskets })`) as `--sk-basket-red`, `--sk-basket-orange`, `--sk-basket-yellow`, `--sk-basket-green` and `--sk-basket-blue`, light values under `:where(:root)` and dark values under `:where(.dark)` like the design tokens, so a host overrides them once. A custom Basket brings its own `color`. The Typed block's node view sets `--sk-basket-color` on a Typed block in a Basket; the stripe reads it.
- Block type tone: a Block type with `chrome.tone` (`BlockType`, any CSS colour or `var(...)`) sets its Typed blocks apart. The Typed block's node view sets `data-block-type-tone` and `--sk-block-type-tone` on the wrapper of such a Typed block; `composites.css` tints its surface with the tone and paints the left border in it (a Basket stripe still wins on the border), and the Document tree rows of the Block type tint the Block type icon. How strong the tint is comes from `--sk-block-type-tone-mix` (`8%` under `:where(:root)`, `14%` under `:where(.dark)`, like the Basket colours). A Block type without a tone is untouched.
- Vue UI kit: the Vue binding is built on Nuxt UI. The chrome renders through the kit handed to `createEditor({ kit })`; `kit` is optional and defaults to `nuxtUiKit()` (`@skaile/forge-editor/vue/kit/nuxt-ui`, needs `@nuxt/ui`, stylesheet `@skaile/forge-editor/vue/kit/nuxt-ui.css`). `@skaile/forge-editor/vue/kit` holds the `VueUiKit` contract and `useUiKit()`; pass your own `VueUiKit` only to render the chrome with another library. Only the `nuxt-ui` kit entry imports `@nuxt/ui`. The Nuxt module has no `kit` option: it always adds `vue/kit/nuxt-ui.css`, patches Nuxt UI's `ui.css` so Tailwind scans the package (`@nuxt/ui` must be registered before the module) and installs the Nuxt UI context plugin.
- Import the core CSS **after** Tailwind and Nuxt UI, and let Tailwind see the library's classes. Scan the whole `dist` of the package (Vue files in `dist/vue` and `dist/features/*/components`, React files in `dist/react` and `dist/features/*/react`), never a single subdirectory; in this repository the examples scan `packages/editor/src`:```css
@import "tailwindcss";
@import "@nuxt/ui";
@import "@skaile/forge-editor/styles/core.css";
@source "../node_modules/@skaile/forge-editor/dist"; /* relative path from this CSS file to the installed package's dist */
```

<br />

The Nuxt module needs none of this: it adds `core.css` and every feature sheet to `css` (`themes.css` last) and appends the package to Tailwind's `@source` list. In plain Vue also import the sheet of each feature you use, e.g. `@skaile/forge-editor/styles/media.css`, after `core.css`. The AI sidebar (`@skaile/forge-editor/ai/vue/chat`) renders on the optional peer `@skaile/forge-chat`, whose resources the host owns, in Nuxt as well: import `@skaile/forge-chat/styles/chat.css`, add `@source` for `@skaile/forge-chat/dist` (e.g. `@source "../../../node_modules/@skaile/forge-chat/dist";`) and, in Nuxt, `'@skaile/forge-chat/nuxt'` after `'@nuxt/ui'` in `modules`. `styles/ai.css` no longer imports the chat stylesheet.
- Plain Vue: Vite plugins `vue()` and `ui({ router: false })` from `@nuxt/ui/vite`, `app.use(ui)` with `import ui from '@nuxt/ui/vue-plugin'`, and the editor context `app.use(createEditor())` (`createEditor` from `@skaile/forge-editor/vue`). Wrap the page in `<UApp>` (overlays, toasts, tooltips).
- React: Vite with `@vitejs/plugin-react` and `@tailwindcss/vite`. The CSS needs Tailwind, `tw-animate-css`, `@skaile/forge-editor/react/styles/ui-vars.css`, `core.css` (plus the sheet of each feature you use, e.g. `mentions.css`), the shadcn theme block (`:root`/`.dark` tokens and `@theme inline`; `bunx shadcn@latest init` generates it) and `@source` for the library's whole `dist` (`@source "../node_modules/@skaile/forge-editor/dist";`): the Features' React components live in `dist/features/*/react`, not in `dist/react`. For the advanced editor import `@skaile/forge-editor/react/styles/advanced.css` instead of those three library sheets: it bundles `ui-vars.css`, `core.css`, every feature sheet and `themes.css` (last). Preload the icons with `addCollection(lucide)` from `@iconify/react`, wrap the tree in `<EditorContextProvider context={createEditorContext({ notify: reactNotifier })}>` and mount `<Toaster />` (sonner, from `@skaile/forge-editor/react`) once so notices show up; see the [usage guide](https://skaile-ai.github.io/forge-editor/getting-started/quick-start-react), [Advanced editor in React](https://skaile-ai.github.io/forge-editor/guides/advanced-react), [`examples/react-simple`](https://github.com/skaile-ai/forge-editor/tree/main/examples/react-simple) and [`examples/react-advanced`](https://github.com/skaile-ai/forge-editor/tree/main/examples/react-advanced).
- Icons: Nuxt UI resolves `i-lucide-*` names at build time. A workspace library lies outside the Vite root that Nuxt UI scans, so list its icons for the client bundle (see how `examples/vue-simple/vite.config.ts` collects them) to avoid Iconify API requests at runtime.
- The editor context is mandatory: Vue `EditorSurface`, `SimpleEditor` and `EditorToolbar` throw a descriptive error without `createEditor()`, the React components without `<EditorContextProvider>`. Both wrap the framework-free `createEditorContext()` from `@skaile/forge-editor/core`; the host owns the React context and may call `context.dispose()` itself.


## Sitemap

See the full [sitemap](https://skaile-ai.github.io/forge-editor/sitemap.md) for all pages.
