Runtime hosts
How @chroma/style loads in Portable (Web) and Executable (Chroma Desktop) — same CSS pipeline, different origins and FOUC trade-offs.
Chroma-Style has no native or WASM styling path. Tokens and utilities are ordinary CSS; injectStyles and bootstrapStyle use document APIs available in any Chroma host. Read Runtime modes for the platform vocabulary Portable (Web) and Executable (Chroma Desktop).
Same in every host
| Behavior | Portable | Executable (Desktop) |
|---|---|---|
injectStyles() | <link rel="stylesheet"> in document.head | Same inside the app iframe |
| Stylesheet URLs | new URL("./tokens.css", import.meta.url) relative to the plugin module | Same |
bootstrapStyle({ cva, cx }) | Returns tw, presets, utilityClasses | Identical API |
data-theme / system dark | CSS in tokens.css | Identical |
| Production artifact | dist/plugins/chroma-style/* copied by chroma build | Same files inside imported .zip |
The Desktop shell does not rewrite or bundle your CSS separately. If styles work in a browser build, the same dist/ should look the same when served from Desktop's loopback library server.
Where hosts differ
| Concern | Portable (Web) | Executable (Desktop) |
|---|---|---|
| Origin | Your dev server or CDN URL | 127.0.0.1 dev port or library port 47823 (default) |
| Dev workflow | chroma dev --no-desktop — fastest CSS reload in the browser | chroma dev with dev.desktop: true — iframe without automatic CSS hot reload |
| Stored theme preference | localStorage keyed to dev/production URL | Different origin → separate storage partition |
| Serving extra CSS | Chroma-Server serves .css as static files | Same over loopback HTTP (not file://) |
Styling does not pick IndexedDB vs filesystem — that split applies to Chroma-Fs, not @chroma/style.
Loading strategies
1. Loader only (templates)
loadPlugins() calls injectStyles() via the manifest styles hook. Minimal setup; CSS may arrive slightly after HTML parse unless the entry module runs immediately.
2. HTML <link> + loader (recommended for production polish)
<head>
<link rel="stylesheet" href="./plugins/chroma-style/tokens.css" />
<link rel="stylesheet" href="./plugins/chroma-style/utilities.css" />
<link rel="stylesheet" href="./src/styles/theme.css" />
</head>injectStyles() remains idempotent (skips duplicate links).
3. Manual bootstrap without loadPlugins
Static template index.js can call bootstrapStyle after importing the plugin module directly — same API as main.chr.
CSS import limitations
| Approach | Supported? |
|---|---|
<link rel="stylesheet" href="..."> in index.html | Yes |
injectStyles() / duplicate-safe <link> injection | Yes |
import "./theme.css" from .chr or bundled JS | No — dev server does not treat CSS as ESM |
Inline <style> in index.html | Yes (used by standard template demo for FileExplorer chrome) |
Checklist before release
- Open the built
dist/in a browser (Portable). - Import the same zip into Chroma Desktop (Executable) and spot-check tokens, dark mode, and preset buttons.
- If theme is user-configurable, persist it per host or export preference in app data — do not assume
localStorageis shared.