Server-rendered
CSS utilities for PHP, WordPress, Django and Rails
Server-rendered applications often skip a JavaScript toolchain entirely, and they are better for it. Monsoon fits them naturally: it is a stylesheet, so any template language can use it, and the optional purge command reads template files of any type.
Plain PHP and Laravel Blade
Add the stylesheet to your layout and write classes in your templates. Conditional classes are ordinary strings:
<!doctype html>
<html lang="en">
<head>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/monsooncss@0.2.0/dist/monsoon.min.css">
</head>
<body class="bg-background text-foreground">
<?php foreach ($orders as $order): ?>
<div class="flex items-center justify-between border-b py-3">
<span class="font-medium"><?= htmlspecialchars($order->number) ?></span>
<span class="rounded-full px-2 py-0.5 text-xs <?= $order->paid ? 'bg-success text-success-foreground' : 'bg-warning text-warning-foreground' ?>">
<?= $order->paid ? 'Paid' : 'Open' ?>
</span>
</div>
<?php endforeach; ?>
</body>
</html>Blade templates work the same way, since they compile to PHP. Put the <link> in your main layout.
WordPress themes
Enqueue the stylesheet from your theme so WordPress prints it in the head and plugins can depend on it:
<?php
add_action('wp_enqueue_scripts', function () {
wp_enqueue_style(
'monsoon',
'https://cdn.jsdelivr.net/npm/monsooncss@0.2.0/dist/monsoon.min.css',
array(),
null
);
});Then use utilities in your template files and block patterns. Content written in the editor keeps its own styles; Monsoon only styles the classes you add.
Django and Jinja
Link it from your base template. To host it yourself, place the file in a static folder and use the static tag:
{% load static %}
<!doctype html>
<html lang="en">
<head>
<link rel="stylesheet" href="{% static 'css/monsoon.css' %}">
</head>
<body class="bg-background text-foreground">
<main class="mx-auto max-w-3xl p-6 space-y-4">
{% for message in messages %}
<div class="rounded-lg border-l-4 border-info bg-info/10 p-4 text-sm">{{ message }}</div>
{% endfor %}
{% block content %}{% endblock %}
</main>
</body>
</html>Rails
stylesheet_link_tag accepts a full URL, so the CDN works without touching the asset pipeline:
<!DOCTYPE html>
<html>
<head>
<%= stylesheet_link_tag "https://cdn.jsdelivr.net/npm/monsooncss@0.2.0/dist/monsoon.min.css" %>
</head>
<body class="bg-background text-foreground">
<% flash.each do |type, message| %>
<div class="rounded-lg bg-success/10 text-foreground p-4"><%= message %></div>
<% end %>
<%= yield %>
</body>
</html>Reuse markup with partials, not new CSS
Long class lists repeat quickly in server templates: every button, every card, every form row. The answer is the reuse feature of your template language, not a new CSS class. A Blade component, a Django include, a Jinja macro or a Rails partial keeps the class list in one file, and every page that renders it stays consistent.
{% macro button(label, kind='primary') %}
<button class="rounded-lg px-4 py-2 font-medium {{ 'bg-primary text-primary-foreground hover:bg-primary/90' if kind == 'primary' else 'border hover:bg-muted' }}">
{{ label }}
</button>
{% endmacro %}Changing the look of every button is then one edit in one template, which is exactly what a component class would have given you, without leaving HTML. The same idea works with Flask, FastAPI with Jinja templates, Symfony with Twig and any other stack that renders HTML on the server.
Theme per customer from the server
Because the theme is one custom property, a multi tenant app can brand every customer with one attribute rendered by the server. Validate the value before printing it, for example by only accepting hex colors:
<body class="bg-background text-foreground" style="--seed: <?= $tenant->brand_hex ?>">Buttons, links, focus rings and surfaces now follow the customer color, with readable foregrounds and dark mode, and no per customer stylesheet to build or cache.
Dark mode and forms in server templates
Server-rendered pages get dark mode for free, because it is decided in the browser from the visitor setting. If your users can choose a theme in their profile, render it as an attribute on the html element, for example data-theme="dark", and the whole page follows on the first paint, with no flash and no script.
Forms deserve a mention because they are the heart of most server applications. The reset gives inputs, selects and buttons the page font and removes browser default borders, so style them explicitly: rounded-md border bg-background px-3 py-2 for fields and focus:ring-2 focus:ring-ring focus:outline-none for a focus ring that follows your seed. Validation states map to the status tokens, for example border-danger and text-danger next to an error message rendered by your framework.
Purge your template folders
The purge command accepts several globs and any file type. Point it at your templates and write the result into your static folder as part of your deploy:
# Django or Jinja
npx monsooncss purge "templates/**/*.html" -o static/css/monsoon.css
# Rails
npx monsooncss purge "app/views/**/*.erb" "app/helpers/**/*.rb" -o public/monsoon.css
# WordPress theme
npx monsooncss purge "wp-content/themes/my-theme/**/*.php" -o wp-content/themes/my-theme/monsoon.cssClasses that come from the database or are built from strings in code are invisible to the scanner. Add them with --safelist, separated by commas.
Frequently asked questions
Do I need Node.js on my server to use Monsoon?
No. Link the CDN file or copy the stylesheet into your static folder. Node.js is only used if you run the optional purge command, usually on a developer machine or in CI.
Will Monsoon conflict with WordPress block styles?
Monsoon includes a small reset in a cascade layer and only styles the utility classes you write. Test your theme, especially headings and lists, since the reset removes default margins and list markers.
Can I purge PHP or ERB files?
Yes. The purge command reads any text file and looks for class names in it, so .php, .erb, .html, .twig and .py files all work.
How do I brand each customer differently?
Render style="--seed: #hex" on the body or a wrapper from your server. Validate the value first.
Try it in ten seconds
Paste this into any HTML page. No install, no build.
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/monsooncss">