Cloud|

@k2b/ui

Theme and styles

Scoped styles plus configurable font and semantic color tokens.

global.css@k2b/ui/global.css

Switch the local accent stack. The nested .k2b-ui scope updates its semantic tokens and components without changing the surrounding page.

Action solid--k2b-action-solid
Surface--k2b-surface
Text--k2b-text

TSX

Copy
import "@k2b/ui/global.css";
const [violet, setViolet] = createSignal(false);
const violetTheme = { /* --k2b-accent-50 through --k2b-accent-950 */ };
<div
class="k2b-ui ui-theme-demo"
style={violet() ? violetTheme : undefined}
>
<SegmentedControl
ariaLabel="Accent theme"
value={violet() ? "violet" : "blue"}
onValueChange={(value) => setViolet(value === "violet")}
options={[
{ value: "blue", label: "Default blue" },
{ value: "violet", label: "Violet" },
]}
/>
<Button>Primary action</Button>
<Button variant="ghost"><i class="ti ti-palette" /> Themed icon</Button>
</div>

@k2b/ui ships precompiled component CSS without a page-global reset. Every selector is scoped below .k2b-ui, so the package can be embedded in an existing SSR application. Its small scoped normalization lives in the CSS base layer, allowing consumer utilities to override native control typography and sizing normally.

Use theme and styles

Load the stylesheet once and wrap the part of the page that renders package components. Nested applications can override tokens on their own .k2b-ui scope without changing the surrounding page.

The scope establishes body text at 0.9375rem (15px with the browser's default root size) and weight 400. Components override that baseline only when their role needs a different type scale. The package never styles the document's global body.

Import

css
@import "@k2b/ui/global.css";

For applications with their own fonts or icons, the same layers remain available separately:

ts
import "@k2b/ui/styles.css";
import "@k2b/ui/fonts/plex.css";
import "@k2b/ui/icons/tabler.css";

Theme tokens

Override fonts through --k2b-font-sans, --k2b-font-condensed, --k2b-font-mono, and --k2b-font-signature, the handwriting face of typed signatures.

Accent, neutral, success, warning, and danger stacks are CSS variables. Semantic aliases such as --k2b-action, --k2b-surface, --k2b-text, and --k2b-border derive from those stacks.

Input placeholders use --k2b-placeholder-color, independently of helper text. The default is neutral-500 in light mode and a mix of 70% neutral-400 with 30% neutral-500 in dark mode. Native inputs, selection controls, and editor placeholders share this color without additional placeholder opacity. Override the token on your .k2b-ui scope to adjust them together.

The default dark theme uses a cool ink hierarchy for canvas, content, navigation, elevated surfaces, borders, and hover states. These semantic dark surface roles are purpose-built rather than direct neutral-stack aliases. When customizing them, override the complete surface hierarchy together so nested layouts and floating UI keep their intended depth.

Override a complete stack when its semantic aliases use several steps for hover, focus, selected, light, and dark states. Changing custom properties at runtime updates the scoped components immediately; the package does not maintain a separate theme store.

The selection hooks --k2b-app-workspace-selected, --k2b-app-workspace-active, and --k2b-row-selected, and which states use them, are in Colors and selection.

AI presentation has a separate semantic theme: --k2b-ai-accent, --k2b-ai-accent-hover, --k2b-ai-border, and --k2b-ai-surface. Override these roles when the assistant identity should differ from the general application accent.

Component APIs use the shared IntentTone vocabulary (neutral, info, success, warning, danger) when they describe user-facing intent, and AccentColor (zinc, blue, emerald, amber, red) for data presentation. Operational states such as running, degraded, and error remain a separate status vocabulary.

Use data-theme="dark" or k2b-dark on the scope, or place it inside a host .dark element. The library does not read prefers-color-scheme itself; the host resolves light or dark (for example, from a Cloud Automatic preference) and sets the class or attribute.

Ink hierarchy

  • --k2b-text: content, titles, and values.
  • --k2b-text-secondary: labels, field and sidebar section titles, supporting lines, descriptions, and secondary buttons.
  • --k2b-text-muted: metadata, timestamps, and quiet hints.

Secondary ink keeps at least 10:1 contrast and muted ink at least 7:1 on both --k2b-surface and --k2b-surface-muted, in light and dark themes. Placeholder color stays separate in --k2b-placeholder-color.

Buttons and labels use 13px semibold type, sidebar rows 13px regular type; small buttons and sidebar section titles use 12px. Descriptions and supporting lines use secondary ink at 12px, sidebar row descriptions 13px. Each primitive sets its own line height, so its box keeps its height whatever the host page's line height. Buttons inside a NoticeCard take the card's line height instead, so its actions keep their height (32px for sm). Titles use -0.018em tracking.

Three surfaces keep their own sizes: object sidebar rows keep a compact 11px subtitle, sidebar items shown as chips on narrow workspaces use 13px semibold labels, and the mobile shell applies its touch type scale.

Icon tile

Use k2b-icon-tile for app, file-type, and model icons. Do not use it for status icons or avatars.

The glyph color (currentColor) drives the fill: --k2b-icon-tile-fill sets its share (12% light, 22% dark) over whatever surface lies below. The radius is 28%. The owning element sets a fixed box and the glyph color. Hover, focus, and selection never change the tile.

tsx
<span
  class="k2b-icon-tile"
  style={{ width: "2.25rem", height: "2.25rem", color: "var(--k2b-app-workspace-active)" }}
>
  <i class="ti ti-notebook" />
</span>

Accessibility

Keep contrast between semantic text and surfaces when overriding color stacks. Focus, danger, success, and warning treatments must remain distinguishable without relying on hue alone.

Do not remove component focus treatments or reduced-motion behavior.

Motion

The OS reduced-motion setting or data-k2b-motion="reduced" on <html> makes transitions and animations inside .k2b-ui instant. For JavaScript-driven motion, use prefersReducedMotion() from @k2b/ui. See Motion for tokens and interaction guardrails.

Runtime

The styles need no JavaScript. Theme variables work in the initial server response and do not read Cloud state or browser storage. An application may still update those variables from an island when it offers an interactive theme picker.

Example

tsx
import { Button } from "@k2b/ui";
import { createSignal, type JSX } from "solid-js";

const violetAccent = {
  "--k2b-accent-50": "#f5f3ff",
  "--k2b-accent-100": "#ede9fe",
  "--k2b-accent-200": "#ddd6fe",
  "--k2b-accent-300": "#c4b5fd",
  "--k2b-accent-400": "#a78bfa",
  "--k2b-accent-500": "#8b5cf6",
  "--k2b-accent-600": "#7c3aed",
  "--k2b-accent-700": "#6d28d9",
  "--k2b-accent-800": "#5b21b6",
  "--k2b-accent-900": "#4c1d95",
  "--k2b-accent-950": "#2e1065",
} as JSX.CSSProperties;

const [violet, setViolet] = createSignal(false);

<main class="k2b-ui" style={violet() ? violetAccent : undefined}>
  <Button
    aria-pressed={violet()}
    onClick={() => setViolet((value) => !value)}
  >
    Switch accent
  </Button>
  <Application />
</main>

Connect a coding agent

The Cloud skill provides compact working instructions. MCP supplies exact current documentation when details matter.

CLI command
bunx skills add https://docs.example.com

This command installs the working instructions published by this website in the selected coding agent.

For exact, current details, also connect the MCP server through one of the agent tabs.

Installation uses the open-source Vercel Skills CLI.

The skill and MCP complement each other: the skill describes workflows, while MCP supplies current documentation.