# First-party Tailwind CSS

**Tailwind CSS is Cicadel's default styling workflow.** Generated projects include
Tailwind v4 input, a styled component page, compiled CSS, and an embedded static
route. Use the project CLI to install the compiler, generate CSS and check for stale output. The server has no Tailwind/Node process or CDN dependency.
Other CSS systems remain supported: see the opt-out instructions below.

The current toolchain pins Tailwind **v4.3.3**. Cicadel uses the upstream
[standalone CLI](https://tailwindcss.com/docs/installation/tailwind-cli), not npm,
PostCSS, a custom CSS compiler, or a browser-time Tailwind script.

## Ask your agent

```text
Read https://cicadel.fauzaanu.com/en/dev/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.
```

## Default authoring loop

From a generated application, after `go mod tidy`:

```sh
# 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 substitute `go run ./cmd/cicadel` for `go tool cicadel`.
The starter includes genuine compiler-generated CSS, so its initial server works
without downloading any CSS tool. Tests that compile CSS (including the framework's
scaffold/docs tests) need the explicitly installed compiler. CI installs it first.

| Command | Responsibility |
| --- | --- |
| `ui css install` | Download the pinned executable, verify SHA256, install in the OS user cache. An already valid installation does not download again. |
| `ui build` | Generate `.templ` Go, then build CSS if `ui.css.json` exists. |
| `ui generate` | Generate markup only; use for component-only libraries. |
| `ui css build` | Build/minify CSS only, atomically replacing output after success. |
| `ui check --json` | Check markup and configured CSS freshness, then compile Go/tests without executing them. |
| `ui css check` | Recompile/compare CSS without changing the committed output. |

The Go/CSS toolchains still need their normal local caches; install Go dependencies
with Go tooling before an offline build. Build/check never download the Tailwind
executable or add a Go dependency. Package resolution uses read-only `go list`.
Check uses temporary files/caches but leaves generated source and CSS unchanged.
A missing tool fails with `UI_CSS_TOOL`; stale output fails with `UI_CSS_STALE`.
All failed commands have nonzero exit status. Use top-level `ui check --json` for
machine diagnostics; `ui css ...` commands print human-readable errors.

## Files and configuration

Generated `ui.css.json`:

```json
{
  "version": "v4.3.3",
  "input": "project/styles/input.css",
  "output": "project/static/app.css",
  "packages": []
}
```

Paths are relative to the project/module directory where you run the command.
Input/output must be different local `.css` paths. Unknown config fields, unsupported
versions and invalid paths fail explicitly. Commands do not search parent directories.
The pinned framework and config version must agree; upgrading Tailwind is a reviewed
framework/toolchain upgrade, not an implicit `latest` fetch.

`project/styles/input.css` imports Tailwind with automatic detection disabled and
lists the project's `.templ` and ordinary Go source patterns explicitly. Generated
`*_templ.go` and tests are excluded, preventing stale generated classes and test
payloads from influencing normal CSS. Source paths are relative to the input file,
not the caller's current directory. See upstream
[source detection](https://tailwindcss.com/docs/detecting-classes-in-source-files).

Customize with CSS-first Tailwind v4, for example:

```css
@theme {
  --color-brand-600: #4f46e5;
}
```

Then write `class="bg-brand-600 text-white"` in `.templ`. Keep the existing
`@import` and `@source` declarations. Local CSS imports resolve relative to the
input file. Do not use old v3 `@tailwind base` directives or assume a
`tailwind.config.js` is auto-loaded. The standalone build is not a promise that
arbitrary npm plugins are bundled; those require their own explicitly maintained
build integration. CSS remains trusted authored source, not request input.

## Classes and variants

Use familiar complete utilities and responsive/state variants:

```templ
<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>
```

For dynamic variants, choose between complete literal strings in Go. Do not
construct utility names from request values (`"bg-" + color + "-600"`), because
Tailwind scans text rather than evaluating Go. For intentional finite classes that
cannot appear literally in scanned source, use an explicit CSS `@source inline(...)`
declaration. Never safelist an unbounded set derived from user input.

`ui.Merge` combines distinct class tokens. It does **not** implement tailwind-merge
or decide which conflicting utilities win: the generated CSS cascade governs that.
Prefer a typed variant that chooses one spacing/color utility per state.

## Independently installed component packages

Register an app through Go imports/manifests as usual. Separately add the **exact
Go import path** of a package containing Tailwind classes:

```json
{
  "version": "v4.3.3",
  "input": "project/styles/input.css",
  "output": "project/static/app.css",
  "packages": ["example.com/your-library/cards"]
}
```

That path is illustrative. Cicadel resolves each entry using the host's selected Go
module graph, then adds an explicit Tailwind source directory for the build. It
works with installed module-cache sources and local replacements; no paths into a
particular user's module cache are committed. Directory scans include descendants,
so point at the narrow component package. The `packages` setting does not install
modules, activate apps, or establish permissions. Missing packages fail with
`UI_CSS_PACKAGE`; install them via normal Go tooling first.

Library releases must include their class-bearing source or literal candidates;
Tailwind cannot infer utilities hidden in runtime-only data. Library authors remain
responsible for sensible source-directory contents and dependency declarations.

## Serving and production

The starter embeds `project/static/app.css` in Go and serves `/static/app.css` using
`static.Handler`. `layout.Page` accepts an optional `Props.Stylesheet` URL; it emits
a contextual-escaped `<link rel="stylesheet">`. The generated home page supplies
the default asset path. The minimal renderer/layout never silently inserts CSS into
other applications, so existing pages keep their current stylesheet choice.

Commit CSS input/config and generated CSS together with the generated component Go.
Run `ui check` before the production build. After UI changes, run `ui build` and
restart/rebuild the Go server to refresh embedded assets. There is no HMR/watch
server or production runtime CSS compilation. You can serve the output through your
existing static host/CDN instead by setting the page's stylesheet URL explicitly;
asset hashing/CDN cache policies are separate from this compiler integration.

Tailwind v4 targets modern browsers; use upstream
[compatibility guidance](https://tailwindcss.com/docs/compatibility) when choosing
browser support. This integration verifies generated CSS/HTTP delivery, not visual
pixel equivalence across browser engines.

## Another stylesheet system or an existing project

To opt out, remove `ui.css.json`, replace `project/static/app.css` with your own
stylesheet/build output, and keep or change the explicit link/static route.
`ui build/check` then handles markup only. Do not leave a Tailwind config pointing
at output maintained by a different compiler.

To adopt Tailwind in an existing app, add the config, an input importing Tailwind
with explicit source directories, and an output location owned by your static
pipeline. Add the stylesheet link, install the tool, build/check, and verify the
asset route. Existing apps are not automatically restyled by upgrading Cicadel.
