---
name: cicadel-components
description: Build, edit, debug, and test Cicadel server-rendered .templ components, pages, layouts, accessible forms, and Tailwind CSS. Use for Cicadel UI work; React composition is the mental model, not a React or JSX runtime.
---

# Cicadel components

Deliver working typed components and their verification, not just markup suggestions.
Use terminal/compiler/HTTP tests; never browser or desktop automation.

## Find the actual contract

Read repository instructions and inspect `go.mod`, existing `.templ` files and their
props/slots definitions. Locate the selected framework with
`go list -m -f '{{.Dir}}' github.com/fauzaanu/cicadel` when working in an app. Its
`docs/component-ui.md` is the precise contract; `docs/component-authoring.md` is the
runnable React-style walkthrough; `docs/tailwind.md` covers CSS setup and packages.
Use those versioned docs when available rather than inventing APIs from React or
upstream templ. For focused composition/defaults/attributes/forms/override patterns,
read [references/patterns.md](https://cicadel.fauzaanu.com/en/dev/sources/skills/cicadel-components/references/patterns.md). This skill can be copied out
of the repository; its reference is self-contained.

## Use the familiar composition model

- A reusable public component is `ui.Definition[Props, Slots]`; its private body is
  a `.templ` function with those same two parameter types. Exported `Props` and
  `Slots` structs are the discoverable API. `Body: card` refers to generated Go.
- Call it with `@Card.Call(Props{...}, Slots{...})`. A slot is `ui.Content`:
  `ui.Text(value)` for text, `ui.Fragment(privateBody(...))` for compiled markup,
  `ui.Group(...)` for a fragment list. Name the ordinary child slot `Children`;
  other struct fields are named slots. `ui.NoSlots{}` means no slots.
- Props flow down; handlers fetch/bind data and pass it explicitly. Pass services
  or resolved component definitions as typed dependencies. Do not add ambient
  maps, providers, hooks, client state, effects, or hidden registry lookups.
- Go field/type checking replaces TypeScript props checking. Omitted fields use
  Go zero values. `Defaults` runs before `Validate`; use pointers when absent and
  false/zero differ. Neither hook may mutate caller-owned maps/slices/pointers.
  Required slots need an explicit `Empty()` check in `Validate`.
- Use `{ expression }` for text, `@content` for a component, Go `if`/`for`/`switch`
  for control flow, `class`/`for` HTML attributes, and `required?={ bool }` for
  booleans. Put control-flow bodies on separate lines. Do not write JSX, `.map`,
  React `key`, `{ children... }`, `className`, `onClick`, or `dangerouslySetInnerHTML`.

## Style with first-party Tailwind

Tailwind v4 is the default for generated projects, not a mandatory renderer.
Inspect `ui.css.json` and `project/styles/input.css`. Preserve an existing explicit
choice of another CSS system. The standalone compiler is pinned by the framework:
`go tool cicadel ui css install` installs it once; builds/checks never download it.
No npm, CDN script, `tailwind.config.js`, or v3 `@tailwind` directives are needed.

Write **complete literal utility names** in `.templ` or Go variant branches:
`"bg-indigo-600 text-white"`, not `"bg-" + color + "-600"`. Tailwind scans text;
it cannot evaluate Go strings. Class merging deduplicates identical tokens but
is not tailwind-merge: select one padding/color/etc. variant instead of assuming
last class wins. Keep CSS in the input stylesheet with v4 `@theme`/`@utility`.
Inline style/script and active SVG are outside the component contract.

For installed component libraries, add exact Go import paths to the config's
`packages` array so their classes are scanned; Go registration alone does not add
CSS sources. Explicitly register app exports/dependencies and required resources.
Use the installable-app workflow when distribution is part of the request.

## Render, diagnose, verify

Use `(ui.Renderer{}).HTML(r.Context(), w, status, content)` on an uncommitted writer.
On error log privately; send a generic error only if `!ui.Committed(err)`. Never
turn request strings into trusted HTML, URL, JS, or CSS; forwarding goes through
`ui.Merge`, and optional strict URL validation uses `ui.URL`.

From a generated app after `go mod tidy`:

```sh
go tool cicadel ui build
go tool cicadel ui check --json
go test -run '^TestYourComponent$' ./apps/yourapp
go test -race ./...
go run manage.go check
go build -trimpath -o bin/server .
```

In the framework checkout use `go run ./cmd/cicadel` instead of `go tool cicadel`.
`ui build` generates markup and configured CSS. `ui generate` is markup-only.
`ui check` catches stale markup/CSS and compiles Go without executing initializers.
Host `check` validates actual registrations/resources; it may need the host's DB.
Restart the Go server after rebuilding embedded assets; no automatic HMR is implied.

Read the diagnostic code and source position; fix authored `.go`/`.templ`/CSS,
then rebuild. Never edit `*_templ.go`, hand-edit compiled CSS, auto-accept snapshots,
or weaken escaping to make a test pass. Test actual output, empty/invalid inputs,
slots, escaping, links/labels and handler status. Use `apptest` for routes and
`Renderer.Render` for fragments; no separate test language is needed. Commit
source and generated artifacts together. Preserve unrelated checkout edits.
