Installation
Install Monsoon in Solid
Solid compiles JSX to real DOM operations, and its class and classList props map straight onto utility classes. Monsoon is one import in the entry file.
Install
Start from npm create vite@latest my-app -- --template solid.
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My app</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/monsooncss@0.2.0/dist/monsoon.min.css" />
<script>(function(){var t;try{t=localStorage.getItem('monsoon-theme')}catch(e){}var d=t==='dark'||(t!=='light'&&matchMedia('(prefers-color-scheme: dark)').matches);document.documentElement.classList.add(d?'dark':'light')})()</script>
</head>
<body class="bg-background text-foreground antialiased">
<div id="root"></div>
<script type="module" src="/src/index.jsx"></script>
</body>
</html>npm install monsooncss/* @refresh reload */
import { render } from 'solid-js/web';
import 'monsooncss';
import './index.css';
import App from './App.jsx';
render(() => <App />, document.getElementById('root'));Keep the head script from the CDN tab in index.html.
Use the classes
Solid uses class (not className) for the static list and classList for classes that depend on signals or props:
export default function PlanCard(props) {
return (
<article
class="rounded-2xl border bg-surface p-6 space-y-4"
classList={{ 'ring-2 ring-ring': props.featured, 'shadow-sm': !props.featured }}
>
<h2 class="text-lg font-semibold">{props.name}</h2>
<p class="text-3xl font-bold">{props.price}</p>
<button
type="button"
class={props.featured
? 'w-full rounded-lg px-4 py-2 font-medium bg-primary text-primary-foreground hover:bg-primary/90'
: 'w-full rounded-lg px-4 py-2 font-medium bg-secondary text-secondary-foreground hover:bg-secondary/80'}
>
Choose {props.name}
</button>
</article>
);
}import PlanCard from './components/PlanCard.jsx';
export default function App() {
return (
<main class="mx-auto max-w-5xl px-6 py-12">
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<PlanCard name="Starter" price="$0" />
<PlanCard name="Team" price="$12" featured />
<PlanCard name="Business" price="$40" />
</div>
</main>
);
}Dark mode
import { createSignal } from 'solid-js';
export default function ThemeToggle() {
const [dark, setDark] = createSignal(document.documentElement.classList.contains('dark'));
const toggle = () => {
const next = dark() ? 'light' : 'dark';
const root = document.documentElement;
root.classList.remove('dark', 'light');
root.classList.add(next);
try { localStorage.setItem('monsoon-theme', next); } catch (e) {}
setDark(next === 'dark');
};
return (
<button
type="button"
onClick={toggle}
aria-pressed={dark()}
class="rounded-lg border px-3 py-2 text-sm hover:bg-muted"
>
{dark() ? 'Light mode' : 'Dark mode'}
</button>
);
}A single region can stay dark with classList={{ dark: alwaysDark() }} on its wrapper.
Theme with --seed
Solid writes style objects with setProperty, so custom properties work and update only when the signal changes:
import { createSignal } from 'solid-js';
export default function BrandPreview() {
const [seed, setSeed] = createSignal('#0d9488');
return (
<section style={{ '--seed': seed() }} class="rounded-2xl bg-surface p-6 space-y-4">
<input type="color" value={seed()} onInput={(e) => setSeed(e.currentTarget.value)} />
<button type="button" class="rounded-lg bg-primary text-primary-foreground px-4 py-2">Primary</button>
</section>
);
}Every semantic token (primary, secondary, accent, surfaces, muted text, borders and the focus ring) is derived from --seed in the browser. Theming lists the tokens.
Using the purge CLI
{
"scripts": {
"dev": "vite",
"css:purge": "monsooncss purge \"index.html\" \"src/**/*.{js,jsx,ts,tsx}\" -o src/monsoon.purged.css",
"build": "npm run css:purge && vite build",
"serve": "vite preview"
}
}import { defineConfig } from 'vite';
import solid from 'vite-plugin-solid';
import { fileURLToPath } from 'node:url';
const purged = fileURLToPath(new URL('./src/monsoon.purged.css', import.meta.url));
export default defineConfig(({ command }) => ({
plugins: [solid()],
resolve: {
alias: command === 'build' ? { monsooncss: purged } : {},
},
}));Development keeps the full file; vite build bundles the purged one. With the CDN setup, write to public/monsoon.css and link /monsoon.css.
The purge CLI reads your files as plain text and keeps every class name it can see. It cannot see a name that is assembled at runtime, so write each class in full: isActive ? 'bg-primary' : 'bg-muted' survives a purge, 'bg-' + color does not. Names that only exist at runtime (from a database, a CMS or an API) go in --safelist bg-success,bg-danger. Quoted classList keys such as { 'bg-primary': active() } are found.
The purged file always keeps the reset, the theme tokens, the .dark and .light scopes and the keyframes, so dark mode and --seed keep working. See the purge CLI reference for every option.
Next steps
- Browse every utility and its variants in the class reference.
- Read how the scheme is chosen in Dark mode, and how tokens are derived in Theming.
Frequently asked questions
How do I add Monsoon to SolidStart?
Import monsooncss in src/app.tsx (or src/app.jsx) and put the head script inside the <head> that src/entry-server.tsx renders.
Does className work in Solid?
Solid accepts it, but class is the idiomatic prop, and classList covers the conditional cases.