Style with Tailwind
Tailwind CSS is Cicadel’s default way to style components. New projects come with Tailwind v4 input, compiled CSS and a static route that serves it.
The server runs no Tailwind or Node process and needs no CDN. You can still use another CSS system: see Use another stylesheet system.
#Ask your agent
Read https://cicadel.fauzaanu.com/en/0.2.8/howto/tailwind/index.md.
Style [component] using this application's existing Tailwind setup.
Use complete utility classes, keep labels and focus states accessible,
and run the matching Cicadel ui build and ui check commands.#The authoring loop
In a generated project, after go mod tidy:
# Once per development/CI machine; explicit network download.
go tool cicadel ui css install
# After editing .templ, Go class variants, or CSS input.
go tool cicadel ui build
go tool cicadel ui check --json
go test -race ./...
go build -trimpath -o bin/server .In the framework checkout, use go run ./cmd/cicadel in place of go tool cicadel.
The starter ships with real compiler-generated CSS. Its first run works without downloading any CSS tool. Tests that compile CSS need the installed compiler, including the framework’s scaffold and docs tests. CI installs it first.
#Which toolchain
The toolchain pins Tailwind v4.3.3. Cicadel uses the upstream standalone CLI.
It does not use npm, PostCSS, a custom CSS compiler or a browser-time Tailwind script.
#Commands
| Command | What it does |
|---|---|
ui css install | Downloads the pinned executable, verifies its SHA256 and installs it in the OS user cache. A valid installation is not downloaded again. |
ui build | Generates .templ Go, then builds CSS if ui.css.json exists. |
ui generate | Generates markup only. Use it for component-only libraries. |
ui css build | Builds and minifies CSS only. Replaces the output atomically after success. |
ui check --json | Checks markup and configured CSS freshness, then compiles Go and tests without running them. |
ui css check | Recompiles CSS and compares it, without changing the committed output. |
What the commands never do:
buildandchecknever download the Tailwind executable or add a Go dependency.- Package resolution uses read-only
go list. checkuses temporary files and caches. It leaves generated source and CSS unchanged.
Go and CSS toolchains still need their normal local caches. Install Go dependencies with Go tooling before an offline build.
#Errors
| Problem | Diagnostic |
|---|---|
| Compiler not installed | UI_CSS_TOOL |
| Output is stale | UI_CSS_STALE |
Every failed command exits nonzero. Use the top-level ui check --json for machine
diagnostics. The ui css ... commands print human-readable errors.
#Configuration: ui.css.json
A generated project has this ui.css.json:
{
"version": "v4.3.3",
"input": "project/styles/input.css",
"output": "project/static/app.css",
"packages": []
}- Paths are relative to the project or module directory where you run the command.
inputandoutputmust be different local.csspaths.- Unknown fields, unsupported versions and invalid paths fail with an error.
- Commands do not search parent directories.
- The framework’s pinned version and the config version must match. Upgrading
Tailwind is a reviewed framework and toolchain upgrade, never an implicit
latestfetch.
#The input file
project/styles/input.css imports Tailwind with automatic detection turned off. It
lists the project’s .templ and ordinary Go source patterns explicitly.
- Generated
*_templ.gofiles and tests are excluded. Stale generated classes and test payloads cannot leak into your CSS. - Source paths are relative to the input file, not your current directory.
See upstream source detection.
#Customize the theme
Tailwind v4 is configured in CSS. Add theme values to the input file:
@theme {
--color-brand-600: #4f46e5;
}Then write class="bg-brand-600 text-white" in .templ.
- Keep the existing
@importand@sourcedeclarations. - Local CSS imports resolve relative to the input file.
- Do not use v3
@tailwind basedirectives. Atailwind.config.jsis not loaded automatically. - The standalone build does not promise to bundle arbitrary npm plugins. Those need their own explicitly maintained build integration.
- CSS is trusted authored source, never request input.
#Classes and variants
Write complete utilities with responsive and state variants:
<button class="rounded-lg bg-indigo-600 px-4 py-2 text-white hover:bg-indigo-700 focus-visible:outline-2 sm:px-6">
Save
</button>Tailwind scans text. It does not run Go. So for dynamic variants, choose between
complete literal strings in Go. Never build utility names from values such as
"bg-" + color + "-600".
For a finite set of classes that cannot appear literally in scanned source, add an
explicit CSS @source inline(...) declaration. Never safelist an unbounded set
derived from user input.
Good to know
ui.Merge combines distinct class tokens. It is not tailwind-merge and does not
decide which conflicting utility wins. The generated CSS cascade does. Prefer a
typed variant that picks one spacing or color utility per state.
#Classes from installed packages
You register an app through Go imports and manifests as usual. Its classes are a
separate step: add the exact Go import path of each package that contains
Tailwind classes to packages.
{
"version": "v4.3.3",
"input": "project/styles/input.css",
"output": "project/static/app.css",
"packages": ["example.com/your-library/cards"]
}That path is an example. For each entry, Cicadel:
- Resolves the path through the host’s selected Go module graph.
- Adds that directory as an explicit Tailwind source for the build.
- This works with installed module-cache sources and local replacements.
- No path into one user’s module cache is committed.
- Scans include subdirectories, so point at the narrow component package.
packagesdoes not install modules, activate apps or grant permissions.- A missing package fails with
UI_CSS_PACKAGE. Install it with normal Go tooling first.
Library releases must include their class-bearing source or literal candidates. Tailwind cannot find utilities hidden in runtime-only data. Library authors are responsible for sensible source directory contents and dependency declarations.
#Serve the CSS
The starter publishes project/static/ as the project app’s App.Static files.
- The home handler resolves
app.cssto its content-hashed URL withstatic.URL(r.Context(), "project", "app.css"). - It passes the URL to
layout.Pagethrough the optionalProps.Stylesheet. layout.Pageemits a contextually escaped<link rel="stylesheet">.
See static files for caching and CDN collection.
The renderer and layout never insert CSS into other applications on their own. Existing pages keep their current stylesheet.
#Production
- Commit CSS input, config and generated CSS together with the generated component Go.
- Run
ui checkbefore the production build. - After UI changes, run
ui build, then restart or rebuild the Go server to refresh embedded assets. - There is no HMR or watch server, and no CSS compilation at runtime in production.
- To serve the CSS from a CDN, set
CICADEL_STATIC_URLand upload the output ofgo run manage.go collectstatic DIR.
Tailwind v4 targets modern browsers. Use the upstream compatibility guidance to choose browser support. This integration verifies generated CSS and its HTTP delivery, not pixel-identical rendering across browser engines.
#Use another stylesheet system
- Remove
ui.css.json. - Replace
project/static/app.csswith your own stylesheet or build output. - Keep or change the explicit stylesheet link.
ui build and ui check then handle markup only. Do not leave a Tailwind config
pointing at output that a different compiler maintains.
#Add Tailwind to an existing project
- Add
ui.css.json. - Add an input file that imports Tailwind with explicit source directories.
- Choose an output location owned by your static pipeline.
- Add the stylesheet link.
- Install the tool, then run
ui buildandui check. - Verify that the asset route serves the CSS.
Upgrading Cicadel does not restyle existing apps.