Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Implement and maintain Tailwind CSS design systems within a multi-agent Claude Code plugin ecosystem
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/advanced-patterns.md
1# Tailwind Design System: Advanced Patterns23Advanced Tailwind CSS v4 patterns including animations, dark mode theming, custom utilities, theme modifiers, namespace overrides, and the v3-to-v4 migration checklist.45## Pattern 5: Native CSS Animations (v4)67```css8/* In your CSS file - native @starting-style for entry animations */9@theme {10--animate-dialog-in: dialog-fade-in 0.2s ease-out;11--animate-dialog-out: dialog-fade-out 0.15s ease-in;12}1314@keyframes dialog-fade-in {15from {16opacity: 0;17transform: scale(0.95) translateY(-0.5rem);18}19to {20opacity: 1;21transform: scale(1) translateY(0);22}23}2425@keyframes dialog-fade-out {26from {27opacity: 1;28transform: scale(1) translateY(0);29}30to {31opacity: 0;32transform: scale(0.95) translateY(-0.5rem);33}34}3536/* Native popover animations using @starting-style */37[popover] {38transition:39opacity 0.2s,40transform 0.2s,41display 0.2s allow-discrete;42opacity: 0;43transform: scale(0.95);44}4546[popover]:popover-open {47opacity: 1;48transform: scale(1);49}5051@starting-style {52[popover]:popover-open {53opacity: 0;54transform: scale(0.95);55}56}57```5859```typescript60// components/ui/dialog.tsx - Using native popover API61import * as DialogPrimitive from '@radix-ui/react-dialog'62import { cn } from '@/lib/utils'6364const DialogPortal = DialogPrimitive.Portal6566export function DialogOverlay({67className,68ref,69...props70}: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay> & {71ref?: React.Ref<HTMLDivElement>72}) {73return (74<DialogPrimitive.Overlay75ref={ref}76className={cn(77'fixed inset-0 z-50 bg-black/80',78'data-[state=open]:animate-fade-in data-[state=closed]:animate-fade-out',79className80)}81{...props}82/>83)84}8586export function DialogContent({87className,88children,89ref,90...props91}: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {92ref?: React.Ref<HTMLDivElement>93}) {94return (95<DialogPortal>96<DialogOverlay />97<DialogPrimitive.Content98ref={ref}99className={cn(100'fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 border border-border bg-background p-6 shadow-lg sm:rounded-lg',101'data-[state=open]:animate-dialog-in data-[state=closed]:animate-dialog-out',102className103)}104{...props}105>106{children}107</DialogPrimitive.Content>108</DialogPortal>109)110}111```112113## Pattern 6: Dark Mode with CSS (v4)114115```typescript116// providers/ThemeProvider.tsx - Simplified for v4117'use client'118119import { createContext, useContext, useEffect, useState } from 'react'120121type Theme = 'dark' | 'light' | 'system'122123interface ThemeContextType {124theme: Theme125setTheme: (theme: Theme) => void126resolvedTheme: 'dark' | 'light'127}128129const ThemeContext = createContext<ThemeContextType | undefined>(undefined)130131export function ThemeProvider({132children,133defaultTheme = 'system',134storageKey = 'theme',135}: {136children: React.ReactNode137defaultTheme?: Theme138storageKey?: string139}) {140const [theme, setTheme] = useState<Theme>(defaultTheme)141const [resolvedTheme, setResolvedTheme] = useState<'dark' | 'light'>('light')142143useEffect(() => {144const stored = localStorage.getItem(storageKey) as Theme | null145if (stored) setTheme(stored)146}, [storageKey])147148useEffect(() => {149const root = document.documentElement150root.classList.remove('light', 'dark')151152const resolved = theme === 'system'153? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')154: theme155156root.classList.add(resolved)157setResolvedTheme(resolved)158159// Update meta theme-color for mobile browsers160const metaThemeColor = document.querySelector('meta[name="theme-color"]')161if (metaThemeColor) {162metaThemeColor.setAttribute('content', resolved === 'dark' ? '#09090b' : '#ffffff')163}164}, [theme])165166return (167<ThemeContext.Provider value={{168theme,169setTheme: (newTheme) => {170localStorage.setItem(storageKey, newTheme)171setTheme(newTheme)172},173resolvedTheme,174}}>175{children}176</ThemeContext.Provider>177)178}179180export const useTheme = () => {181const context = useContext(ThemeContext)182if (!context) throw new Error('useTheme must be used within ThemeProvider')183return context184}185186// components/ThemeToggle.tsx187import { Moon, Sun } from 'lucide-react'188import { useTheme } from '@/providers/ThemeProvider'189190export function ThemeToggle() {191const { resolvedTheme, setTheme } = useTheme()192193return (194<Button195variant="ghost"196size="icon"197onClick={() => setTheme(resolvedTheme === 'dark' ? 'light' : 'dark')}198>199<Sun className="size-5 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />200<Moon className="absolute size-5 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />201<span className="sr-only">Toggle theme</span>202</Button>203)204}205```206207## Advanced v4 Patterns208209### Custom Utilities with `@utility`210211Define reusable custom utilities:212213```css214/* Custom utility for decorative lines */215@utility line-t {216@apply relative before:absolute before:top-0 before:-left-[100vw] before:h-px before:w-[200vw] before:bg-gray-950/5 dark:before:bg-white/10;217}218219/* Custom utility for text gradients */220@utility text-gradient {221@apply bg-gradient-to-r from-primary to-accent bg-clip-text text-transparent;222}223```224225### Theme Modifiers226227```css228/* Use @theme inline when referencing other CSS variables */229@theme inline {230--font-sans: var(--font-inter), system-ui;231}232233/* Use @theme static to always generate CSS variables (even when unused) */234@theme static {235--color-brand: oklch(65% 0.15 240);236}237238/* Import with theme options */239@import "tailwindcss" theme(static);240```241242### Namespace Overrides243244```css245@theme {246/* Clear all default colors and define your own */247--color-*: initial;248--color-white: #fff;249--color-black: #000;250--color-primary: oklch(45% 0.2 260);251--color-secondary: oklch(65% 0.15 200);252253/* Clear ALL defaults for a minimal setup */254/* --*: initial; */255}256```257258### Semi-transparent Color Variants259260```css261@theme {262/* Use color-mix() for alpha variants */263--color-primary-50: color-mix(in oklab, var(--color-primary) 5%, transparent);264--color-primary-100: color-mix(265in oklab,266var(--color-primary) 10%,267transparent268);269--color-primary-200: color-mix(270in oklab,271var(--color-primary) 20%,272transparent273);274}275```276277### Container Queries278279```css280@theme {281--container-xs: 20rem;282--container-sm: 24rem;283--container-md: 28rem;284--container-lg: 32rem;285}286```287288## v3 to v4 Migration Checklist289290- [ ] Replace `tailwind.config.ts` with CSS `@theme` block291- [ ] Change `@tailwind base/components/utilities` to `@import "tailwindcss"`292- [ ] Move color definitions to `@theme { --color-*: value }`293- [ ] Replace `darkMode: "class"` with `@custom-variant dark`294- [ ] Move `@keyframes` inside `@theme` blocks (ensures keyframes output with theme)295- [ ] Replace `require("tailwindcss-animate")` with native CSS animations296- [ ] Update `h-10 w-10` to `size-10` (new utility)297- [ ] Remove `forwardRef` (React 19 passes ref as prop)298- [ ] Consider OKLCH colors for better color perception299- [ ] Replace custom plugins with `@utility` directives300301## Best Practices302303### Do's304305- **Use `@theme` blocks** - CSS-first configuration is v4's core pattern306- **Use OKLCH colors** - Better perceptual uniformity than HSL307- **Compose with CVA** - Type-safe variants308- **Use semantic tokens** - `bg-primary` not `bg-blue-500`309- **Use `size-*`** - New shorthand for `w-* h-*`310- **Add accessibility** - ARIA attributes, focus states311312### Don'ts313314- **Don't use `tailwind.config.ts`** - Use CSS `@theme` instead315- **Don't use `@tailwind` directives** - Use `@import "tailwindcss"`316- **Don't use `forwardRef`** - React 19 passes ref as prop317- **Don't use arbitrary values** - Extend `@theme` instead318- **Don't hardcode colors** - Use semantic tokens319- **Don't forget dark mode** - Test both themes320