# CodeAtlas UI: full documentation
> Open-source Svelte 5 component library (`@codeatlasdev/ui`). Index: https://ui.codeatlas.com.br/llms.txt
---
# Introduction
Group: Getting started. URL: https://ui.codeatlas.com.br/docs/
CodeAtlas UI is an open-source Svelte 5 component library with a glass material system, an OKLCH theme engine and native-feeling mobile behavior.
CodeAtlas UI gives Svelte 5 apps full screens, not just bricks: page templates, an app shell, data tables, charts, forms and overlays, all built on [bits-ui](https://bits-ui.com) and themed through CSS custom properties.
```svelte
{#snippet children(list)}
{#each list.rows as u (u.id)}
{/each}
{/snippet}
```
That is a whole users page: header, search, pagination, empty state and glass surface, with no CSS written.
## What you get
- **Pages, not primitives.** `AppList`, `AppForm`, `AppSettings`, `PageShell` and `AppShellLayout` bring layout, spacing and empty states.
- **Liquid Glass.** Five material tiers with real `backdrop-filter`, tuned for light and dark, with opaque fallbacks for reduced transparency.
- **Theme engine.** Eight OKLCH presets, brand presets from one hex color, four surface styles, and no flash on load.
- **Native on mobile.** Safe areas, keyboard handling, 44px touch targets, bottom sheets with swipe to dismiss, and browser chrome color that follows the page.
- **Accessible.** bits-ui behavior, axe-tested components, reduced motion and reduced transparency support.
- **Light.** Charts, DataTable and CodeSnippet are separate entry points with optional peers, so they stay out of your bundle unless imported.
- **Built for AI agents.** Closed prop vocabularies, typed props, `llms.txt` and installable skills.
## Install
## Start here
## Explore
---
# Installation
Group: Getting started. URL: https://ui.codeatlas.com.br/docs/getting-started/installation/
Install @codeatlasdev/ui and wire the theme into SvelteKit, Astro or plain Vite without a flash of the wrong theme.
CodeAtlas UI needs Svelte 5 (runes mode). In a SvelteKit or Astro app, `bunx @codeatlasdev/ui init` does the whole setup below for you, and prints a diff instead of overwriting any file that already exists. Setup is three things: import the stylesheet once, inject the theme script before first paint, and start the `colorScheme` store in your root layout.
The core bundle stays small. Heavy features are separate entry points with optional peer dependencies, so install only what you use:
| Feature | Import from | Also install |
|---|---|---|
| Charts | `@codeatlasdev/ui/charts` | `echarts` |
| DataTable | `@codeatlasdev/ui/table` | `@tanstack/svelte-table` |
| CodeSnippet | `@codeatlasdev/ui/code` | `shiki` |
| Masked and money fields | `@codeatlasdev/ui/forms` | nothing |
Icons come from `@lucide/svelte`, which the package already depends on.
### Release channels
| Channel | Install | When to use it |
|---|---|---|
| `latest` | `bun add @codeatlasdev/ui` | Production. Semver: breaking changes only in a major. |
| `beta` | `bun add @codeatlasdev/ui@beta` | The next minor, feature-complete. Try it before it ships. |
| `alpha` | `bun add @codeatlasdev/ui@alpha` | The next major while it is still moving. Expect breaking changes between alphas. |
Every version is published from CI with an npm provenance statement, so you can check which commit and workflow built it (`npm audit signatures`).
## SvelteKit
1. **Register the Vite plugin.** It bundles the ESM-only dependencies for SSR (`@tanstack/svelte-table`, `shiki`) and warns at build time if the theme script is not injected.
```ts
// vite.config.ts
import { sveltekit } from "@sveltejs/kit/vite";
import { caThemePlugin } from "@codeatlasdev/ui/vite";
import { defineConfig } from "vite";
import { theme } from "./src/lib/theme";
export default defineConfig({ plugins: [sveltekit(), caThemePlugin(theme)] });
```
2. **Inject the theme script in the server hook.** `caThemeHandle` puts the brand presets and the init script right after `
` of every SSR and prerendered page, so the first paint already has the right scheme and preset.
```ts
// src/hooks.server.ts
import { sequence } from "@sveltejs/kit/hooks";
import { caThemeHandle } from "@codeatlasdev/ui/kit";
import { theme } from "$lib/theme";
export const handle = sequence(caThemeHandle(theme));
```
3. **Define the theme once.** Both the hook and the plugin take the same object. An empty object is valid and gives you the built-in amber preset in dark mode.
```ts
// src/lib/theme.ts
import type { ThemeOptions } from "@codeatlasdev/ui";
export const theme: ThemeOptions = {
defaultScheme: "system",
};
```
4. **Import the stylesheet and start the store in the root layout.**
```svelte
{@render children()}
```
5. **Set the viewport meta in `src/app.html`.** See [Mobile](/docs/getting-started/mobile/) for what each part does.
```html
```
If you cannot use a hook, paste the script into `src/app.html` instead. `CA_THEME_SCRIPT_TAG` from `@codeatlasdev/ui/vite` is a ready-to-paste tag for the default theme; for a custom theme, use the hook.
## Astro
Use the integration together with `@astrojs/svelte`. `caUI` injects the theme into the `` of every page and handles the SSR bundling.
```sh
bun add @codeatlasdev/ui @astrojs/svelte svelte
```
```js
// astro.config.mjs
import svelte from "@astrojs/svelte";
import { caUI } from "@codeatlasdev/ui/astro";
import { defineConfig } from "astro/config";
import { theme } from "./src/theme.ts";
export default defineConfig({ integrations: [svelte(), caUI(theme)] });
```
```ts
// src/theme.ts
import type { ThemeOptions } from "@codeatlasdev/ui/astro";
export const theme: ThemeOptions = { defaultPreset: "amber", defaultScheme: "dark" };
```
Import the stylesheet once in your base layout and add the viewport meta:
```astro
---
// src/layouts/Base.astro
import "@codeatlasdev/ui/styles/global.css";
---
```
Components are Svelte islands. Add a client directive to anything interactive (`client:visible` or `client:load`); purely visual components render on the server with no JavaScript. In islands, call `colorScheme.init()` from one island that is always on the page, such as your header, or from a small script.
Astro needs `astro` 5, 6 or 7 as a peer. Components that read `colorScheme` render correctly on the server because the init script sets `class="dark"` and `data-preset` before the stylesheet applies.
## Plain Vite
`caThemePlugin` also works without SvelteKit: it injects the theme head through `transformIndexHtml`.
```ts
// vite.config.ts
import { svelte } from "@sveltejs/vite-plugin-svelte";
import { caThemePlugin } from "@codeatlasdev/ui/vite";
import { defineConfig } from "vite";
export default defineConfig({ plugins: [caThemePlugin(), svelte()] });
```
```ts
// src/main.ts
import "@codeatlasdev/ui/styles/global.css";
import { colorScheme } from "@codeatlasdev/ui";
import { mount } from "svelte";
import App from "./App.svelte";
colorScheme.init();
mount(App, { target: document.getElementById("app")! });
```
## Verify
```svelte
```
Reload with the toggle on dark and check that there is no white flash. Continue with [Theming](/docs/getting-started/theming/).
---
# Theming
Group: Getting started. URL: https://ui.codeatlas.com.br/docs/getting-started/theming/
Define a theme with defineTheme, derive a brand preset from one hex color, switch schemes and surface styles, and override tokens through the cascade.
A theme is a plain object. The library compiles it to CSS once at build time (the same object always gives the same CSS) and injects it before any stylesheet, so there is no per-render style work and no flash.
```ts
// src/lib/theme.ts
import type { ThemeOptions } from "@codeatlasdev/ui";
export const theme: ThemeOptions = {
presets: [{ id: "acme", color: "#2563eb" }],
defaultPreset: "acme",
defaultScheme: "system",
defaultStyle: "glass",
fonts: { body: "Geist, system-ui, sans-serif" },
radius: 1,
density: "comfortable",
overrides: { light: { "--ca-card-padding": "16px" } },
};
```
Pass the same object to `caThemeHandle` and `caThemePlugin` (SvelteKit), `caUI` (Astro) or `themeHead` (custom setups), see [Installation](/docs/getting-started/installation/). `ThemeOptions` is `Partial`, so every field is optional.
## Options
| Option | Default | Description |
|---|---|---|
| `presets` | `[]` | Brand presets generated from a hex color. Built-in presets are always available. |
| `defaultPreset` | `"amber"` | Preset used until the user picks one. Must be a built-in or one of `presets`. |
| `defaultScheme` | `"dark"` | `"light"`, `"dark"` or `"system"`. |
| `defaultStyle` | `"glass"` | `"glass"`, `"frosted"`, `"solid"` or `"flat"`. |
| `fonts` | `{}` | `body`, `mono` and `display`. Each is a font stack string or a self-hosted font descriptor (`@font-face`, preload, metric-matched fallback), see [Performance](/docs/getting-started/performance/#fonts). They set `--ca-font-sans`, `--ca-font-mono` and `--ca-font-display`. |
| `radius` | `1` | Multiplier applied to the `--ca-radius-xs` to `--ca-radius-xl` scale. |
| `density` | `"comfortable"` | `"compact"` tightens card padding and page gaps. |
| `overrides` | `{}` | Raw `--ca-*` token overrides, per scheme (`light`, `dark`). |
`defineTheme(options)` resolves the options (defaults, validation) and `themeCSS(resolved)` returns the CSS string. You rarely call them yourself; the integrations do. Invalid input fails the build: a preset `id` that clashes with a built-in, a color that is not `#rrggbb`, or a `defaultPreset` that does not exist.
## Presets
Eight OKLCH presets ship with the package: `amber`, `ocean`, `crimson`, `cyan`, `violet`, `emerald`, `rose` and `slate`. One attribute switches the whole app:
```html
```
In code, use the store:
```ts
import { colorScheme } from "@codeatlasdev/ui";
colorScheme.setPreset("violet");
colorScheme.presets; // every valid id: built-ins plus your brand presets
```
### Brand preset from a hex color
Give the library your logo color and it derives hue, chroma and lightness in OKLCH, then emits the complete light and dark token set (brand, surfaces, text, outlines, glass tints). Charts use the hex as their first series color.
```ts
export const theme: ThemeOptions = {
presets: [{ id: "acme", color: "#2563eb", label: "Acme" }],
defaultPreset: "acme",
};
```
Values stored by the user that your theme does not know are discarded and removed from storage. If you rename or delete a brand preset, returning users fall back to `defaultPreset` instead of seeing a broken theme.
## Schemes
`defaultScheme: "system"` follows the operating system, including live changes while the page is open. The init script also keeps `` in sync with the preset's surface color.
```ts
colorScheme.preference; // "light" | "dark" | "system"
colorScheme.resolved; // "light" | "dark" (system already resolved)
colorScheme.isDark; // boolean
colorScheme.setPreference("system");
colorScheme.toggle(); // flips resolved light and dark
```
## Surface styles
`data-style` on `` swaps the material of every surface at once.
| Style | Look |
|---|---|
| `glass` | Liquid Glass: strong blur and saturation, translucent tints. Default. |
| `frosted` | Less blur, calmer mesh background. |
| `solid` | No blur, opaque surfaces, no mesh background. Keeps soft shadows. |
| `flat` | No blur, no mesh, no drop shadows: separation comes from borders. |
```ts
colorScheme.setStyle("solid");
```
Users on `prefers-reduced-transparency: reduce` get opaque surfaces regardless of the style.
## The colorScheme store
Call `colorScheme.init()` once in the root layout (inside `onMount`). It re-applies the state to ``, follows OS scheme changes and keeps the browser chrome color in sync. It is idempotent and returns a cleanup function.
| Member | Description |
|---|---|
| `preference`, `resolved`, `preset`, `style`, `isDark`, `presets` | Reactive getters (Svelte 5 `$state`). |
| `setPreference(pref)`, `toggle()` | Change the scheme. |
| `setPreset(id)`, `setStyle(style)` | Change preset or surface style. |
| `setTokens(vars)` | Runtime token overrides, see below. |
| `init()` | Start listeners. Returns cleanup. |
All choices persist in `localStorage` (`ca-scheme`, `ca-preset`, `ca-style`). Storage errors in private mode are ignored, and the values are validated against the theme before use.
### Runtime tokens
`setTokens` writes your `--ca-*` variables to a single `