Getting started
Introduction to Monsoon
Monsoon is a utility-first CSS framework that ships as one stylesheet. Link it from a CDN, write classes such as px-4, md:grid-cols-3 and hover:bg-primary in your markup, and the page is styled. There is no compiler, no config file and no JavaScript.
What Monsoon is
Most utility-first setups generate CSS from your source files. Monsoon ships the CSS already written: 4,923 base classes and 10,237 variant classes, a reset, a color palette, a theme engine and a layer of ready made components, all in one file. Because nothing is generated, the same file works in a static HTML page, a server rendered template and a single page app.
- Utilities for layout, flexbox, grid, spacing, sizing, typography, colors, backgrounds, borders, effects, filters, transitions, animation, transforms, interactivity and accessibility. Browse them in the class reference.
- Seed theming. Set one
--seedcolor and every semantic color (primary, accent, surfaces, borders, muted text, the focus ring) is derived from it in the browser with OKLCH relative colors. - Automatic dark mode that follows the operating system, plus
class="dark",class="light"anddata-themeto force a scheme on the page or on a single section. - Responsive and container variants:
sm:to2xl:for the viewport, and@xs:to@xl:for the nearest parent marked with@container. - A component layer with buttons, cards, alerts, form controls, tabs, modals and more, built on native HTML with no JavaScript. See the component gallery.
- An optional purge command,
npx monsooncss purge, that writes a smaller file with only the utilities your files use.
The ideas behind it
Predeclared, not generated
Every class exists before you type it. That is what removes the build step, and it is also why a few things are left out on purpose: a prebuilt file cannot contain values you invent while writing markup, so static classes have no stacked variants such as md:hover:. Values you do invent, such as w-[37px], are arbitrary values: the optional script writes them in the browser and the purge CLI compiles them, see Arbitrary values. Variants are generated only for the utility groups where they are useful, which keeps the complete file at about 88 kB with brotli.
One color, a whole theme
The theme is not a list of hand picked colors. It is a set of formulas that read your --seed and compute everything else, so changing one line re-themes the page, and style="--seed: teal" on an element re-themes only that element and its children. Foreground colors flip between white and near black to keep a contrast ratio of at least 4.5:1.
Dark mode is a number
Each token is declared once and reads a number, --mode, which is 0 in light mode and 1 in dark mode. The operating system setting, the dark class and the data-theme attribute only change that number. Semantic colors such as bg-surface and text-muted-foreground therefore need no dark: prefix at all.
Components without JavaScript
Component classes such as btn, card and alert come before the utilities in the stylesheet, so a utility on the same element always wins. They read the same theme tokens, which means they follow your seed and the color scheme with no extra work.
Your first page
Save this file and open it in a browser. It works from disk, from a local server and in production, because there is no development build that differs from the production file.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Hello, Monsoon</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/monsooncss">
</head>
<body class="bg-background text-foreground antialiased">
<main class="mx-auto max-w-md p-8">
<div class="rounded-2xl border bg-surface p-6 shadow-lg space-y-4">
<h1 class="text-2xl font-bold">Hello, Monsoon</h1>
<p class="text-muted-foreground">One stylesheet. No build step.</p>
<button class="rounded-lg bg-primary text-primary-foreground px-4 py-2 font-medium hover:bg-primary/90">
Get started
</button>
</div>
</main>
</body>
</html>Hello, Monsoon
One stylesheet. No build step.
Now change the button to bg-accent text-accent-foreground, or add style="--seed: #e11d48" to the main element, and refresh. That is the whole workflow: edit, save, reload.
How to read a class name
Each utility sets one thing, so class names read like shorthand CSS. Most follow the pattern variant:property-value, where the variant is optional:
| Class | Reads as | CSS |
|---|---|---|
p-4 | padding, step 4 of the spacing scale | padding: 1rem |
px-6 | padding on the inline axis, step 6 | padding-inline: 1.5rem |
-mt-2 | negative top margin, step 2 | margin-top: -0.5rem |
w-1/2 | width as a fraction | width: 50% |
text-muted-foreground | text color from a theme token | color: var(--muted-foreground) |
bg-rose-600 | background from the palette, hue and step | background-color: var(--color-rose-600) |
bg-primary/90 | background with an opacity modifier | color-mix(in oklab, var(--primary) 90%, transparent) |
hover:bg-primary | primary background while hovered | the same rule behind :hover |
md:grid-cols-3 | three grid columns from 768px up | the same rule inside @media (min-width: 768px) |
The spacing scale counts in quarters of a rem: 1 is 0.25rem, 4 is 1rem and 16 is 4rem. Text sizes, radii and shadows use names instead (text-sm, text-2xl, rounded-lg, shadow-md). A class takes at most one variant prefix.
Not sure a class exists? Search the class reference, which also lists the variants of every class, or run npx monsooncss classes --filter grid-cols in a terminal.
Utilities and components together
A component gives a whole pattern sensible defaults, and utilities adjust it. Both can live on the same element, and the utility wins because it comes later in the stylesheet:
<article class="card card-bordered max-w-sm">
<div class="card-body">
<div class="flex items-center justify-between gap-3">
<h3 class="card-title">Weekly digest</h3>
<span class="badge badge-success badge-dot">Live</span>
</div>
<p class="text-sm text-muted-foreground">Components set the defaults, utilities fine tune them.</p>
<div class="card-actions">
<button class="btn btn-ghost btn-sm">Later</button>
<button class="btn btn-primary btn-sm rounded-full px-6">Subscribe</button>
</div>
</div>
</article>Weekly digest
LiveComponents set the defaults, utilities fine tune them.
Every component page lists its classes, parts and modifiers. Good places to start are Button, Card and Alert.
Where to go next
- Install it: from a CDN with one link tag, or from npm for bundlers. Framework guides cover React, Vue, Laravel, Django and more.
- Make it yours with Theming, then check Dark mode.
- Lay out pages with Responsive design and components with Container queries.
- Learn which prefixes exist in Variants.
- Ship less CSS with the purge CLI, and see Browser support before you go live.
- Experiment with markup, classes and
--seedvalues live in the playground.
Frequently asked questions
Does Monsoon need Node.js or a build tool?
No. Link the stylesheet and write classes. Node.js is only needed to install from npm or to run the optional purge command.
Does Monsoon ship any JavaScript?
No. Theming, dark mode and the components are plain CSS. A theme switcher needs a few lines of your own script, shown in Dark mode.
Can I mix Monsoon with my own CSS?
Yes. The reset sits in a cascade layer named base, and every theme color is a custom property such as var(--primary), so your own rules can use the theme and override anything.