Style with Tailwind
templ has no opinion on CSS. Plain class and style attributes pass straight through, which makes Tailwind the common pairing.
Tailwind classes in components
Write classes like anywhere else:
templ alert(msg string) {
<div class="rounded border border-amber-300 bg-amber-50 p-4 text-amber-900">
{ msg }
</div>
}
Run the Tailwind CLI as usual; it scans .templ files like any other source. The only setup friction is editor support: the Tailwind language server needs to know that .templ files contain class candidates.
Tailwind LSP setup
Two editor-side settings make completions work inside templ files:
- Register
.templas a recognized filetype in your editor - Add templ to the Tailwind language server’s user languages mapping
The exact setting names differ per editor; the IDE support documentation covers VS Code and Neovim.
Tip: If Tailwind completions silently do nothing, it is almost always the filetype mapping - the server never sees
.templas a candidate file.
css components for dynamic values
Tailwind’s utility model struggles with computed or stateful values. templ’s css components are the documented alternative: they compile to hashed class names plus a <style> tag (runtime.go):
css meterFill() {
width: 100%;
background-color: #0ea5e9;
}
templ meter() {
<div class={ meterFill() }></div>
}
Because css components are Go, styling logic can depend on your data instead of one-size-fits-all utilities.
Combining static and conditional classes
Static Tailwind classes and css components mix in one class={ ... } list, with templ.KV for conditional entries:
templ row(id string, active bool) {
<tr class={ "py-2", templ.KV("bg-slate-100", active) }>
<td>{ id }</td>
</tr>
}
templ.KV(name, cond) adds the class only when the condition holds - no string building.
Gotcha:
csscomponent output is a hashed class name emitted in a<style>tag. You will not find the literal class name in your markup - that is expected, not a bug.