# How to Configure Tailwind CSS Integration in Topcoat: A Complete Guide

> Configure Tailwind CSS with Topcoat easily. This guide shows how to use the built-in CLI wrapper, eliminating Node js and streamlining your Rust build process for automatic utility class scanning.

- Repository: [Tokio/topcoat](https://github.com/tokio-rs/topcoat)
- Tags: how-to-guide
- Published: 2026-07-21

---

**Topcoat bundles a standalone Tailwind CSS CLI wrapper that runs from a Cargo build script, eliminating the need for Node.js, PostCSS, or a separate asset pipeline while automatically scanning your Rust source files for utility classes.**

Topcoat is a Rust web framework that simplifies frontend development by integrating Tailwind CSS directly into the Cargo build process. This guide explains how to configure Tailwind CSS integration in Topcoat using the `topcoat::tailwind` module, which handles CLI management, CSS generation, and asset hashing entirely at compile time.

## How the Tailwind Integration Works

The integration relies on a build-time code generation pattern implemented in [`crates/topcoat/src/tailwind.rs`](https://github.com/tokio-rs/topcoat/blob/main/crates/topcoat/src/tailwind.rs). When configured, Topcoat downloads the Tailwind CLI binary (pinned to version 4.3.2 by default), scans your Rust source files for `class="..."` attributes inside `view!` macros, and emits a minified CSS file into `OUT_DIR` that is automatically served as a content-hashed asset.

### Feature-Gated Architecture

The Tailwind functionality is **opt-in via Cargo features**. You must enable the `tailwind` feature for both the runtime dependency (to access the `tailwind::stylesheet!()` macro) and the build dependency (to run the CLI wrapper):

- **Runtime dependency**: Provides the `tailwind::stylesheet!()` macro that expands to `topcoat::asset::asset!(concat!(env!("OUT_DIR"), "/tailwind.css"))`
- **Build dependency**: Provides `BuildConfig` for downloading the CLI and executing the build

### Build-Time CSS Generation

During compilation, `BuildConfig::new().render()` performs three operations:

1. Downloads the Tailwind CLI binary into `OUT_DIR` if not already present
2. Generates an input CSS file containing `@import "tailwindcss"` (or uses your custom input)
3. Executes `tailwindcss -i <input> -o <output> --cwd <cwd> --minify`, scanning the crate root while respecting `.gitignore` to exclude `target/` and other artifacts

The build script does not emit `cargo:rerun-if-*` directives, relying on Cargo's default behavior to rerun when any non-ignored source file changes.

## Step-by-Step Configuration

Follow these steps to enable Tailwind CSS in your Topcoat application.

### 1. Enable the Tailwind Feature in Cargo.toml

Add the `tailwind` feature to both your regular dependencies and build dependencies:

```toml
[dependencies]
topcoat = { version = "0.3.1", features = ["tailwind"] }

[build-dependencies]
topcoat = { version = "0.3.1", default-features = false, features = ["tailwind"] }

```

Disabling default features for the build dependency minimizes compile times for the build script.

### 2. Create a Build Script (build.rs)

Create a [`build.rs`](https://github.com/tokio-rs/topcoat/blob/main/build.rs) file in your crate root that invokes the Tailwind build configuration:

```rust
fn main() {
    // Generate Tailwind CSS at compile time
    topcoat::tailwind::BuildConfig::new()
        .render()
        .expect("Tailwind build failed");
}

```

This default configuration downloads the Tailwind CLI, creates an input file containing `@import "tailwindcss"`, and writes the compiled [`tailwind.css`](https://github.com/tokio-rs/topcoat/blob/main/tailwind.css) to `$OUT_DIR`.

### 3. Include the Stylesheet in Your Layout

Use the `tailwind::stylesheet!()` macro inside your layout component to embed the generated CSS:

```rust
use topcoat::{
    router::{Slot, layout},
    tailwind,
    view::view,
};

#[layout]
async fn layout(slot: Slot<'_>) -> topcoat::Result {
    view! {
        <!DOCTYPE html>
        <html>
            <head>
                <link rel="stylesheet" href=(tailwind::stylesheet!())>
            </head>
            <body>
                (slot.await?)
            </body>
        </html>
    }
}

```

The macro resolves to the content-hashed asset URL generated by Topcoat's asset pipeline.

## Customization Options

The `BuildConfig` API in [`crates/topcoat/src/tailwind.rs`](https://github.com/tokio-rs/topcoat/blob/main/crates/topcoat/src/tailwind.rs) supports several customization scenarios.

### Using a Custom Input CSS File

To extend Tailwind with custom theme variables or plugins, provide a path to your own CSS file:

Create [`src/styles/app.css`](https://github.com/tokio-rs/topcoat/blob/main/src/styles/app.css):

```css
@import "tailwindcss";

@theme {
  --font-sans: Inter, sans-serif;
}

```

Update [`build.rs`](https://github.com/tokio-rs/topcoat/blob/main/build.rs) to use this input:

```rust
fn main() {
    topcoat::tailwind::BuildConfig::new()
        .input("src/styles/app.css")   // custom input path
        .render()
        .expect("Tailwind build failed");
}

```

### Offline Builds with Pre-installed Binaries

For air-gapped or reproducible builds, use a pre-installed Tailwind binary instead of downloading one:

```rust
fn main() {
    topcoat::tailwind::BuildConfig::new()
        .executable("tailwindcss")        // assumes binary is on $PATH
        .render()
        .expect("Tailwind build failed");
}

```

Alternatively, read the path from an environment variable:

```rust
fn main() {
    topcoat::tailwind::BuildConfig::new()
        .executable_env("TAILWIND_CLI")
        .render()
        .expect("Tailwind build failed");
}

```

You can also pin a specific CLI version using `.version("4.4.0")` if you require a different release than the default 4.3.2.

## Summary

- **Enable the `tailwind` feature** in both `[dependencies]` and `[build-dependencies]` in your [`Cargo.toml`](https://github.com/tokio-rs/topcoat/blob/main/Cargo.toml)
- **Call `BuildConfig::new().render()`** in your [`build.rs`](https://github.com/tokio-rs/topcoat/blob/main/build.rs) to download the CLI and generate CSS during compilation
- **Use `tailwind::stylesheet!()`** in your layout templates to reference the compiled, hashed CSS file
- **Customize the build** by providing custom input CSS, specifying offline binaries, or pinning specific CLI versions
- **Rely on automatic rebuilding** when Rust source files change, as the integration respects `.gitignore` and scans `view!` macros for class names

## Frequently Asked Questions

### Does Topcoat require Node.js or PostCSS for Tailwind CSS?

No. Topcoat uses a standalone Rust-based wrapper around the Tailwind CSS CLI that downloads and executes the binary directly during Cargo builds. This eliminates the need for Node.js, npm, PostCSS, or any JavaScript-based build pipeline, as implemented in [`crates/topcoat/src/tailwind.rs`](https://github.com/tokio-rs/topcoat/blob/main/crates/topcoat/src/tailwind.rs).

### How does Topcoat detect which Tailwind classes to include?

The Tailwind CLI performs the class-name extraction by scanning your Rust source files for literal `class="..."` values inside `view!` macros. Topcoat does not parse the macros itself; instead, it delegates to the official Tailwind CLI with `--cwd` set to your crate root, which respects `.gitignore` patterns to avoid scanning `target/` and other build artifacts.

### Can I use a specific version of the Tailwind CLI?

Yes. The `BuildConfig` API provides a `.version()` method to pin a specific release. By default, Topcoat pins version 4.3.2, but you can override this in your [`build.rs`](https://github.com/tokio-rs/topcoat/blob/main/build.rs) by calling `.version("4.4.0")` or another supported version before invoking `.render()`.

### Where is the generated CSS file stored?

The compiled CSS is written to `$OUT_DIR/tailwind.css` during the build process. The `tailwind::stylesheet!()` macro expands to `topcoat::asset::asset!(concat!(env!("OUT_DIR"), "/tailwind.css"))`, which integrates with Topcoat's asset pipeline to provide content-hashed URLs and automatic cache invalidation.