TailwindCSS integration
INFO
This integration is especially useful when you style UI extension points with custom CSS or Tailwind classes, like custom pages and custom fields, where classes may not exist in the precompiled Avo bundle.
This integration is built for Tailwind CSS 4.
Avo ships with precompiled styles that are easy to use and work out of the box, so most apps do not need to care about extra build steps.
When Avo detects tailwindcss-ruby, it automatically enables this integration and builds an app-level Avo stylesheet with zero (or close to zero) configuration.
If you have tailwindcss-ruby installed (or tailwindcss-rails, which depends on tailwindcss-ruby) but you do not use custom Tailwind/CSS classes in custom tools, ejected components, custom fields, or other extended UI areas, you can opt out and keep using only Avo's precompiled styles.
When enabled, this integration compiles a stylesheet that includes:
- Avo core styles
- loaded Avo plugin styles
- your host app Avo styles from
app/assets/stylesheets/avo/**/*.css - utility classes discovered under your Rails
app/directory (configurable; see below), plus Avo and plugin sources
The output file is:
app/assets/builds/avo/application.css
This integration writes to the same logical Avo stylesheet path (avo/application) so your app always loads one stylesheet entrypoint.
Auto-enable behavior
Add tailwindcss-ruby to your app:
gem "tailwindcss-ruby"Once present, Avo will:
- auto-build in development (on server boot)
- hook into
assets:precompilein production
WARNING
Avo's build emits Tailwind v4 syntax. If your app pulls Tailwind in through tailwindcss-rails, it must be >= 4.0 — on tailwindcss-rails 3.x the integration stays disabled even though tailwindcss-ruby is present. Apps that depend on tailwindcss-ruby directly (no tailwindcss-rails) aren't affected by this check.
TIP
We highly recommend running this integration through bin/dev with a Procfile.dev watcher process:
web: bin/rails server -p 3000
avo_css: bin/rails avo:tailwindcss:watchThis keeps your Avo Tailwind build running in parallel with the Rails server, so style changes are compiled automatically while you work without extra manual steps.
Add your custom Avo styles
Add your Avo-specific stylesheets under app/assets/stylesheets/avo/.
Every CSS file in this path is included in the final avo/application.css build.
For example:
/* app/assets/stylesheets/avo/buttons.css */
@layer components {
.avo-btn-highlight {
@apply px-3 py-2 rounded-md bg-indigo-600 text-white;
}
}Override styles and scripts (avo-overrides.css / avo-overrides.js)
Avo ships two empty files and loads them automatically on every screen:
avo-overrides.css— loaded afteravo/application.css, so its rules win the cascade.avo-overrides.js— loaded afteravo/application.js, sowindow.Stimulusis available.
Both are the no-build escape hatch: unlike app/assets/stylesheets/avo/, they are not run through the Tailwind build — they are served as-is. Use them for quick tweaks, re-theming, or small behaviors without touching the pipeline. To customize them, eject the file into your own app (Avo's copy is then shadowed by yours):
# just the stylesheet
rails g avo:eject --partial :avo_overrides_css
# just the script
rails g avo:eject --partial :avo_overrides_js
# both at once
rails g avo:eject --partial :asset_overridesBecause avo-overrides.css loads after Avo's own stylesheet, overriding Avo's CSS variables here is enough to re-skin the whole interface — no @apply, no build step. See the Theming guide for how to re-color and re-skin Avo through these variables.
Add behavior with Stimulus
avo-overrides.js runs once, but Avo navigates with Turbo. Register a Stimulus controller (Stimulus re-connects it on every visit) or attach a turbo:load listener — avoid one-shot DOM edits, they won't survive navigation:
// app/assets/javascripts/avo-overrides.js
document.addEventListener("turbo:load", () => {
// runs on every Turbo visit
})
// or register a controller against Avo's Stimulus instance:
// window.Stimulus.register("my-controller", class extends Controller { ... })TIP
For custom JS that needs bundling or imports (esbuild/importmap), use asset handling and the JavaScript guide instead. avo-overrides.js is for small, dependency-free snippets.
Disable integration (opt-out)
If your app has tailwindcss-ruby (directly or via tailwindcss-rails) but you do not need Avo custom utility coverage, disable the integration in your initializer:
Avo.configure do |config|
config.tailwindcss_integration_enabled = false
endDefault is true.
The default is intentionally true to preserve the zero-configuration experience: if your app has tailwindcss-ruby and you start adding classes/styles in custom Avo UI extension points, this integration should just work without you needing to think about setup details.
Host content scan paths (tailwindcss_content_sources)
Avo writes Tailwind v4 @source directives into tmp/avo/avo.tailwind.input.css so the compiler can see utility classes used in templates and Ruby/HTML. By default, the host-side scan is limited to Rails.root.join("app") (the usual Rails tree: views, components, app/avo resources, and similar).
That keeps discovery focused on application code and avoids scanning unrelated directories under the project root.
Configure extra roots (or override the list entirely) in config/initializers/avo.rb:
Avo.configure do |config|
config.tailwindcss_content_sources = [
Rails.root.join("app"),
Rails.root.join("lib", "components")
]
endEach entry may be an absolute path or a path relative to Rails.root. Directories that do not exist are skipped.
To include the entire project root in the host scan (everything under Rails.root), set:
config.tailwindcss_content_sources = [Rails.root]Debugging
If classes are missing from avo/application.css, check these files first:
- input file generated by Avo:
tmp/avo/avo.tailwind.input.css - output file generated by Tailwind:
app/assets/builds/avo/application.css
How it works, in short:
- Avo generates
tmp/avo/avo.tailwind.input.csson each build/watch cycle. - That input file imports Avo/plugin
application.cssfiles and your host styles fromapp/assets/stylesheets/avo/**/*.css. - It also adds
@sourceentries for Avo, loaded plugins, and your configured host directories (default:Rails.root.join("app")) so Tailwind can discover utility classes from templates and code. - Tailwind then compiles everything into
app/assets/builds/avo/application.css.
Quick checks:
- confirm the integration is enabled (
config.tailwindcss_integration_enabled = true); - ensure
tailwindcss-rubyis installed (directly, or viatailwindcss-rails>= 4.0); - verify your custom styles are under
app/assets/stylesheets/avo/; - run with the watcher (
bin/dev) so changes are rebuilt continuously.