Runtime Styles vs Build-Time Utilities
CSS-in-JS and Tailwind CSS represent fundamentally different philosophies for styling web applications. CSS-in-JS (styled-components, Emotion, Stitches, Panda CSS): styles are written in JavaScript, co-located with components, and generated at runtime (or extracted at build time in newer libraries). The component owns its styles completely. Tailwind CSS: styles are applied via utility classes directly in HTML/JSX. No custom CSS is written. The design system is encoded in the utility class names themselves (text-lg, bg-blue-500, flex items-center).
Why this matters for AI rules: every AI-generated component includes styling. If the AI generates styled-components syntax in a Tailwind project (or Tailwind classes in a styled-components project): the code is wrong. Not subtly wrong — obviously, visibly wrong. The styling approach is the single most visible difference in AI-generated React components. The AI must know: is this a CSS-in-JS project or a Tailwind project?
The trend: Tailwind CSS has become the dominant approach in 2025-2026, especially in Next.js, Remix, and Astro projects. CSS-in-JS is still widely used but faces performance challenges with React Server Components (runtime CSS-in-JS does not work in server components). The AI should default to Tailwind patterns for new projects unless the codebase clearly uses CSS-in-JS.
CSS-in-JS: AI Rules for styled-components and Emotion
styled-components pattern: const Button = styled.button<{ primary?: boolean }>`background: ${props => props.primary ? 'blue' : 'gray'}; padding: 8px 16px; border-radius: 4px;`. The AI generates: a styled component with template literals, dynamic props, and CSS properties. AI rule: 'CSS-in-JS project: generate styled components with TypeScript props interface. Use the theme from ThemeProvider for colors and spacing. Never hardcode values that should come from the theme.'
Emotion pattern: similar but with css prop support. const styles = css`padding: 8px; color: ${theme.colors.primary};`. Or the styled API: styled.div`...`. Emotion and styled-components are nearly interchangeable for AI generation. The AI should check: does the project use @emotion/react or styled-components? The import determines the syntax.
Server Component compatibility: runtime CSS-in-JS (styled-components, Emotion) does not work in React Server Components. The AI must know: in a Next.js App Router project using CSS-in-JS, client components need the 'use client' directive for any component with styled() calls. This constraint: affects component architecture decisions the AI makes.
In Next.js App Router: React Server Components cannot use styled-components or Emotion (they inject styles via JavaScript at runtime, which does not run on the server). Every component using styled() needs 'use client'. This means: the entire component tree below a styled component becomes client-rendered. Tailwind has no such constraint — utility classes work in both server and client components.
Tailwind CSS: AI Rules for Utility-First Styling
Tailwind component pattern: <button className="bg-blue-500 hover:bg-blue-600 text-white font-semibold py-2 px-4 rounded-lg transition-colors">Click me</button>. The AI generates: className strings with Tailwind utilities. No separate style file, no styled() wrapper. AI rule: 'Tailwind project: all styling via className. Use Tailwind utilities for spacing (p-4, m-2), colors (text-gray-900, bg-white), layout (flex, grid, items-center), responsive (md:flex-row, lg:grid-cols-3), and states (hover:, focus:, dark:).'
Tailwind with component libraries: projects using shadcn/ui, Radix, or Headless UI combine Tailwind with component primitives. The AI should: use the project's existing component library (import { Button } from '@/components/ui/button') rather than generating raw Tailwind HTML. AI rule: 'Check src/components/ui/ for existing components before generating raw Tailwind. Use cn() or clsx() for conditional classes.'
Tailwind configuration: tailwind.config.ts defines the design system (custom colors, fonts, spacing, breakpoints). The AI should: reference the existing Tailwind config for available values rather than using arbitrary values. AI rule: 'Use design token classes (text-primary, bg-background) over arbitrary values (text-[#1a2b3c], bg-[#f0f0f0]). Arbitrary values bypass the design system.'
Many Tailwind projects use shadcn/ui (components in src/components/ui/). Before the AI generates a custom button, dialog, dropdown, or form: check if the component already exists in the ui/ directory. Using the existing component ensures consistent styling, accessibility, and dark mode support. Raw Tailwind HTML should only be used for layouts and custom sections, not standard UI elements.
Responsive Design and State Variants
Tailwind responsive: mobile-first with breakpoint prefixes. flex flex-col md:flex-row lg:grid lg:grid-cols-3. The AI should: always start with mobile layout, then add breakpoint prefixes for larger screens. AI rule: 'Mobile-first: write the mobile styles as the base, add md: and lg: prefixes for tablet and desktop. Never write desktop-first Tailwind (no max-width approach).'
CSS-in-JS responsive: media queries inside template literals or theme breakpoint helpers. @media (min-width: 768px) { flex-direction: row; } or theme.breakpoints.md. The AI should: use the project's breakpoint convention consistently. AI rule: 'CSS-in-JS responsive: use the theme breakpoints or a shared media query helper. Match the mobile-first approach of the existing codebase.'
Dark mode: Tailwind uses dark: prefix (dark:bg-gray-900 dark:text-white). CSS-in-JS uses theme switching (ThemeProvider with light/dark theme objects). The AI must generate: the correct dark mode pattern for the project's approach. In Tailwind: every color class needs a dark: variant. In CSS-in-JS: the theme object handles it automatically.
Tailwind's responsive system is mobile-first by design: base classes apply to all screens, md: applies at 768px+, lg: at 1024px+. Writing lg:flex without a base flex or block class means the element has no layout below 1024px. The AI should always define the mobile layout first, then layer breakpoint overrides. This matches how users actually experience the site — mobile traffic exceeds desktop in most markets.
Decision Framework and Migration
Choose Tailwind when: starting a new project (fastest to productive), using Next.js App Router (server component compatible), the team prefers utility classes over writing CSS, the project uses shadcn/ui or similar Tailwind component libraries. Choose CSS-in-JS when: the existing codebase uses it (migration cost is high), the team strongly prefers co-located styled components, the project needs highly dynamic styles (complex animations, runtime theme generation), or using a design system that provides styled-components (Material UI, Chakra UI).
The AI rule: detect the styling approach from the codebase (look for tailwind.config, styled-components imports, or Tailwind classes in components) and generate all new components using that approach exclusively. Never mix Tailwind and CSS-in-JS in the same component. For new components in an existing project: match the existing pattern. For new projects: Tailwind is the default recommendation in 2026.
- CSS-in-JS: runtime styles, co-located, dynamic props. styled-components/Emotion syntax
- Tailwind: utility classes, build-time, design system via config. className strings
- Server Components: Tailwind works. Runtime CSS-in-JS requires 'use client'
- Responsive: Tailwind mobile-first prefixes (md:, lg:). CSS-in-JS media queries
- Dark mode: Tailwind dark: prefix. CSS-in-JS theme switching
- AI rule: detect from codebase (tailwind.config vs styled imports). Never mix approaches
- 2026 default: Tailwind for new projects. CSS-in-JS for existing codebases that use it