agentsclimarketplace

Rails tailwind

Skill Tyr0/agent-skills/plugins/rails-expert/skills/rails-tailwind

A collection of skills, plugins, and agents for AI workflows.

Install
npx -y skills add Tyr0/agent-skills --skill rails-tailwind

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Use this skill whenever the user asks about Tailwind CSS in a Ruby on Rails application, including setup, configuration, utility class patterns, extracting reusable styles, integrating Tailwind with ViewComponent or partials, responsive design, dark mode, custom theme values, or the tailwindcss-rails gem. Also use it for questions about purging unused styles, using @apply, building design systems with Tailwind in Rails, or Tailwind v3/v4 upgrade considerations. Triggers on 'how do I set up Tailwind in Rails', 'how do I extract a Tailwind component', 'how do I customize my Tailwind theme', 'how do I do dark mode in Rails', or any question about using Tailwind CSS in a Rails project.

SKILL.md

11.3 KB, ~2.8k tokens by cl100k_base, as published. Nobody here has run it

Rails Tailwind CSS Reference

A dense reference for integrating, configuring, and scaling Tailwind CSS in a Ruby on Rails application.


Setup

New Rails app

rails new myapp --css tailwind

Installs the tailwindcss-rails gem, generates config/tailwind.config.js, adds app/assets/stylesheets/application.tailwind.css, and configures the build process.

Existing app

bundle add tailwindcss-rails
bin/rails tailwindcss:install

Development build watcher

bin/dev   # starts both Rails server and Tailwind CSS watcher via Procfile.dev

The watcher rebuilds app/assets/builds/tailwind.css whenever a template changes.

Production build

Tailwind compiles automatically during assets:precompile:

bin/rails assets:precompile   # runs tailwindcss:build as part of the pipeline

Configuration

config/tailwind.config.js

const defaultTheme = require('tailwindcss/defaultTheme')

module.exports = {
  content: [
    './public/*.html',
    './app/helpers/**/*.rb',
    './app/javascript/**/*.js',
    './app/views/**/*.{erb,haml,html,slim}',
    './app/components/**/*.{erb,rb}',   // include ViewComponent templates
  ],
  theme: {
    extend: {
      fontFamily: {
        sans: ['Inter var', ...defaultTheme.fontFamily.sans],
      },
      colors: {
        brand: {
          50:  '#eff6ff',
          500: '#3b82f6',
          900: '#1e3a5f',
        },
      },
    },
  },
  plugins: [
    require('@tailwindcss/forms'),
    require('@tailwindcss/typography'),
    require('@tailwindcss/aspect-ratio'),
  ],
}

Do: Add ./app/components/**/*.{erb,rb} to content when using ViewComponent — otherwise Tailwind purges classes used only in component templates. Don't: Use string interpolation to build class names dynamically ("text-#{color}-500") — Tailwind's content scanner is a text search, not a Ruby evaluator. Dynamic classes get purged.

Safe-listing dynamic classes

// config/tailwind.config.js
module.exports = {
  safelist: [
    'text-red-500',
    'text-green-500',
    'text-yellow-500',
    { pattern: /bg-(red|green|blue)-(100|500|900)/ },
  ],
}

Or use a lookup map in Ruby instead of dynamic interpolation:

STATUS_CLASSES = {
  "active"   => "text-green-600 bg-green-50",
  "inactive" => "text-gray-500 bg-gray-50",
  "banned"   => "text-red-600 bg-red-50",
}.freeze

def status_classes(status)
  STATUS_CLASSES.fetch(status, "text-gray-500")
end

Utility Class Patterns

Consistent spacing scale

Use Tailwind's spacing scale consistently; avoid arbitrary values (w-[137px]) unless absolutely required for pixel-perfect third-party integration.

<%# Good — uses scale values %>
<div class="px-4 py-3 mt-6 mb-2">

<%# Avoid unless necessary %>
<div class="px-[17px] py-[11px]">

Grouping classes by concern

Group utility classes in a consistent order to aid scanning:

  1. Layout (flex, grid, block, hidden)
  2. Positioning (relative, absolute, top-*, z-*)
  3. Box model (w-*, h-*, p-*, m-*)
  4. Typography (text-*, font-*, leading-*)
  5. Visual (bg-*, border-*, rounded-*, shadow-*)
  6. Interactive (hover:, focus:, active:)
  7. Responsive (sm:, md:, lg:)

Many teams use the prettier-plugin-tailwindcss formatter to auto-sort classes.

Extracting repeated patterns with partials

The primary extraction mechanism in Rails is a partial, not @apply:

<%# app/views/shared/_button.html.erb %>
<button class="inline-flex items-center px-4 py-2 border border-transparent
               text-sm font-medium rounded-md shadow-sm text-white bg-indigo-600
               hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2
               focus:ring-indigo-500 <%= local_assigns[:extra_classes] %>"
        <%= tag.attributes(local_assigns.except(:extra_classes, :label)) %>>
  <%= label %>
</button>
<%= render "shared/button", label: "Save", type: "submit" %>
<%= render "shared/button", label: "Cancel", extra_classes: "bg-gray-200 text-gray-700" %>

Extracting with ViewComponent

ViewComponent is the preferred extraction mechanism for complex, interactive UI elements:

# app/components/button_component.rb
class ButtonComponent < ViewComponent::Base
  VARIANTS = {
    primary:   "bg-indigo-600 text-white hover:bg-indigo-700",
    secondary: "bg-white text-gray-700 border border-gray-300 hover:bg-gray-50",
    danger:    "bg-red-600 text-white hover:bg-red-700",
  }.freeze

  def initialize(label:, variant: :primary, **html_options)
    @label = label
    @variant = variant
    @html_options = html_options
  end

  def variant_classes
    VARIANTS.fetch(@variant)
  end
end
<%# app/components/button_component.html.erb %>
<button class="inline-flex items-center px-4 py-2 text-sm font-medium
               rounded-md shadow-sm focus:outline-none focus:ring-2
               focus:ring-offset-2 focus:ring-indigo-500 <%= variant_classes %>"
        <%= tag.attributes(@html_options) %>>
  <%= @label %>
</button>
<%= render ButtonComponent.new(label: "Save", variant: :primary, type: "submit") %>
<%= render ButtonComponent.new(label: "Delete", variant: :danger, data: { confirm: "Sure?" }) %>

Responsive Design

Tailwind is mobile-first. Unprefixed utilities apply at all breakpoints; prefixed utilities apply at that breakpoint and up.

<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
  <%= render @posts %>
</div>

Breakpoints

PrefixMin-width
sm:640px
md:768px
lg:1024px
xl:1280px
2xl:1536px

Customize breakpoints in tailwind.config.js:

theme: {
  screens: {
    tablet: '640px',
    laptop: '1024px',
    desktop: '1280px',
  },
},

Dark Mode

Configuration

// config/tailwind.config.js
module.exports = {
  darkMode: 'class',  // 'media' uses prefers-color-scheme; 'class' uses .dark on <html>
  // ...
}

Toggling dark mode

<%# Add/remove the `dark` class on <html> to toggle %>
<html class="<%= dark_mode? ? 'dark' : '' %>">
// Stimulus controller for toggling
export default class extends Controller {
  toggle() {
    document.documentElement.classList.toggle('dark')
    localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light')
  }
}

Persist preference with localStorage and set the class before first paint to avoid flash:

<%# In <head> — before body renders %>
<script>
  if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
    document.documentElement.classList.add('dark')
  }
</script>

Using dark variants

<div class="bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100">
  <p class="text-gray-600 dark:text-gray-400">...</p>
</div>

Typography Plugin

The @tailwindcss/typography plugin adds the prose class for rendering user-generated or CMS content:

<article class="prose prose-lg prose-indigo dark:prose-invert max-w-none">
  <%= @post.body_html %>
</article>

Useful for blog posts, documentation, and any rich text content rendered via ActionText or markdown.


Forms Plugin

The @tailwindcss/forms plugin resets browser form styles so Tailwind utilities apply cleanly to inputs, selects, and textareas.

npm install @tailwindcss/forms
# or (with tailwindcss-rails)

Add to plugins array in tailwind.config.js. Then style inputs directly with utilities:

<%= f.text_field :email,
      class: "block w-full rounded-md border-gray-300 shadow-sm
              focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" %>

Design Tokens / Theme

Define all brand values in theme.extend rather than using arbitrary values inline. This creates a consistent token set across the app.

theme: {
  extend: {
    colors: {
      brand: {
        light: '#60a5fa',
        DEFAULT: '#2563eb',
        dark: '#1d4ed8',
      },
    },
    spacing: {
      18: '4.5rem',
      88: '22rem',
    },
    borderRadius: {
      '4xl': '2rem',
    },
    boxShadow: {
      card: '0 2px 8px 0 rgba(0,0,0,0.08)',
    },
  },
},

Reference custom tokens with the same utility class syntax:

<div class="bg-brand text-white shadow-card rounded-4xl p-18">

@apply (use sparingly)

@apply lets you extract a group of utilities into a CSS class. Use it only for truly global, design-system-level abstractions — not as a default extraction pattern.

/* app/assets/stylesheets/application.tailwind.css */
@layer components {
  .btn-primary {
    @apply inline-flex items-center px-4 py-2 text-sm font-medium rounded-md
           bg-indigo-600 text-white hover:bg-indigo-700 focus:outline-none
           focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500;
  }
}

Do: Use @apply for globally shared atomic components (.btn-primary, .badge, .input). Don't: Use @apply to avoid repeating classes in partials — prefer ViewComponent or a partial instead. @apply breaks the utility-first model and makes classes opaque.


Anti-Patterns

Anti-patternProblemFix
Dynamic class interpolation ("text-#{color}-500")Tailwind purges dynamically constructed class names; classes are missing in productionUse a lookup hash or safelist in config
Over-relying on @apply for everythingDefeats utility-first model; produces opaque class names; fights Tailwind's designExtract to ViewComponent or partial instead
Omitting ./app/components/**/* from contentViewComponent template classes purged in production buildAdd component paths to content array in config
Inline styles for values not in the scaleInconsistent spacing/color; hard to maintainAdd custom tokens to theme.extend instead
Setting !important utilities everywhereIndicates a specificity war, usually from third-party CSSScope third-party styles; use Tailwind's important strategy if needed
Using Tailwind without prettier-plugin-tailwindcssClasses in random order; hard to scan or diffAdd the plugin; enforce with lint
Copying long class strings to every button/inputDuplication; one change requires find-and-replace across templatesExtract shared elements to partials or ViewComponents
Not running bin/dev during developmentTailwind build is stale; classes added to templates are missingAlways use bin/dev (or foreman start) which runs the Tailwind watcher

Gives 0 of the 12 instructions most project setup skills give in ~2.8k tokens

Counted across 999 of the 1,637 authors here whose files we hold, read 2026-08-06

  • ask one question at a timein 29 of 999, across 28 files
  • detect the package manager from lockfilesin 28 of 999, across 9 files
  • present findings to the userin 25 of 999, across 4 files
  • explore current repo statein 24 of 999, across 3 files
  • update the agent skills block in place if it existsin 24 of 999, across 3 files
  • install husky lint-staged and prettierin 23 of 999, across 4 files
  • create the lintstagedrc filein 22 of 999, across 3 files
  • commit all changed filesin 22 of 999, across 3 files
  • run lint-staged to verify it worksin 22 of 999, across 3 files
  • initialize huskyin 21 of 999, across 2 files
  • create the husky pre-commit filein 21 of 999, across 2 files
  • create a prettierrc file if missingin 21 of 999, across 2 files

Said here and by no other author read

  • run the development build watcher during development
  • add component template paths to the content configuration
  • use static lookup hashes instead of dynamic class interpolation
  • order utility classes consistently
  • extract repeated patterns into partials or components
  • define brand values in theme extend

Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.