# Tailwind CSS

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](#use-another-stylesheet-system).

## 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.
```

## The authoring loop

In a generated project, 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, 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](https://tailwindcss.com/docs/installation/tailwind-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:

- `build` and `check` never download the Tailwind executable or add a Go dependency.
- Package resolution uses read-only `go list`.
- `check` uses 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`:

```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.
- `input` and `output` must be different local `.css` paths.
- 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 `latest` fetch.

## 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.go` files 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](https://tailwindcss.com/docs/detecting-classes-in-source-files).

### Customize the theme

Tailwind v4 is configured in CSS. Add theme values to the input file:

```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 v3 `@tailwind base` directives. A `tailwind.config.js` is 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:

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

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.

> [!NOTE]
> `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`.

```json
{
  "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:

1. Resolves the path through the host's selected Go module graph.
2. 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.
- `packages` does 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.

1. The home handler resolves `app.css` to its content-hashed URL with
   `static.URL(r.Context(), "project", "app.css")`.
2. It passes the URL to `layout.Page` through the optional `Props.Stylesheet`.
3. `layout.Page` emits a contextually escaped `<link rel="stylesheet">`.

See [static files](https://cicadel.fauzaanu.com/en/dev/howto/static-files/index.md) 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 check` before 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_URL` and upload the output of
  `go run manage.go collectstatic DIR`.

Tailwind v4 targets modern browsers. Use the upstream
[compatibility guidance](https://tailwindcss.com/docs/compatibility) to choose browser
support. This integration verifies generated CSS and its HTTP delivery, not
pixel-identical rendering across browser engines.

## Use another stylesheet system

1. Remove `ui.css.json`.
2. Replace `project/static/app.css` with your own stylesheet or build output.
3. 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

1. Add `ui.css.json`.
2. Add an input file that imports Tailwind with explicit source directories.
3. Choose an output location owned by your static pipeline.
4. Add the stylesheet link.
5. Install the tool, then run `ui build` and `ui check`.
6. Verify that the asset route serves the CSS.

Upgrading Cicadel does not restyle existing apps.
