Agent skill

web-styling

Styling patterns for React web applications. Use when working with Tailwind CSS, CSS Modules, theming, responsive design, or component styling.

Stars 232
Forks 15

Install this agent skill to your Project

npx add-skill https://github.com/aiskillstore/marketplace/tree/main/skills/cjharmath/web-styling

SKILL.md

Web Styling (React)

Tailwind CSS

Basic Usage

typescript
function Button({ variant = 'primary', children }) {
  const baseClasses = 'px-4 py-2 rounded-lg font-medium transition-colors';

  const variants = {
    primary: 'bg-blue-600 text-white hover:bg-blue-700',
    secondary: 'bg-gray-200 text-gray-800 hover:bg-gray-300',
    danger: 'bg-red-600 text-white hover:bg-red-700',
  };

  return (
    <button className={`${baseClasses} ${variants[variant]}`}>
      {children}
    </button>
  );
}

Conditional Classes with clsx/cn

typescript
import { clsx } from 'clsx';
// or with tailwind-merge for deduplication
import { twMerge } from 'tailwind-merge';

function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}

function Card({ isActive, isDisabled, className, children }) {
  return (
    <div
      className={cn(
        'p-4 rounded-lg border',
        isActive && 'border-blue-500 bg-blue-50',
        isDisabled && 'opacity-50 cursor-not-allowed',
        className // Allow overrides
      )}
    >
      {children}
    </div>
  );
}

Responsive Design

typescript
// Mobile-first breakpoints
// sm: 640px, md: 768px, lg: 1024px, xl: 1280px, 2xl: 1536px

<div className="
  grid
  grid-cols-1      /* Mobile: 1 column */
  sm:grid-cols-2   /* Tablet: 2 columns */
  lg:grid-cols-3   /* Desktop: 3 columns */
  xl:grid-cols-4   /* Large: 4 columns */
  gap-4
">
  {items.map(item => <Card key={item.id} {...item} />)}
</div>

// Responsive text
<h1 className="text-2xl md:text-3xl lg:text-4xl font-bold">
  Title
</h1>

// Hide/show at breakpoints
<nav className="hidden md:flex">Desktop Nav</nav>
<nav className="flex md:hidden">Mobile Nav</nav>

Dark Mode

typescript
// tailwind.config.js
module.exports = {
  darkMode: 'class', // or 'media' for OS preference
  // ...
};

// Component
<div className="bg-white dark:bg-gray-900 text-gray-900 dark:text-white">
  <h1 className="text-black dark:text-white">Title</h1>
  <p className="text-gray-600 dark:text-gray-400">Description</p>
</div>

// Toggle dark mode
function ThemeToggle() {
  const [isDark, setIsDark] = useState(false);

  useEffect(() => {
    document.documentElement.classList.toggle('dark', isDark);
  }, [isDark]);

  return (
    <button onClick={() => setIsDark(!isDark)}>
      {isDark ? '☀️' : '🌙'}
    </button>
  );
}

Custom Design Tokens

javascript
// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      colors: {
        brand: {
          50: '#f0f9ff',
          100: '#e0f2fe',
          500: '#0ea5e9',
          600: '#0284c7',
          700: '#0369a1',
        },
      },
      fontFamily: {
        sans: ['Inter', 'system-ui', 'sans-serif'],
      },
      spacing: {
        '18': '4.5rem',
        '88': '22rem',
      },
    },
  },
};
typescript
// Usage
<button className="bg-brand-500 hover:bg-brand-600">
  Brand Button
</button>

CSS Modules

Basic Usage

css
/* Button.module.css */
.button {
  padding: 0.5rem 1rem;
  border-radius: 0.5rem;
  font-weight: 500;
}

.primary {
  background-color: #3b82f6;
  color: white;
}

.secondary {
  background-color: #e5e7eb;
  color: #1f2937;
}
typescript
// Button.tsx
import styles from './Button.module.css';

function Button({ variant = 'primary', children }) {
  return (
    <button className={`${styles.button} ${styles[variant]}`}>
      {children}
    </button>
  );
}

With clsx

typescript
import styles from './Card.module.css';
import { clsx } from 'clsx';

function Card({ isActive, className, children }) {
  return (
    <div
      className={clsx(
        styles.card,
        isActive && styles.active,
        className
      )}
    >
      {children}
    </div>
  );
}

CSS-in-JS (styled-components)

typescript
import styled from 'styled-components';

const Button = styled.button<{ variant?: 'primary' | 'secondary' }>`
  padding: 0.5rem 1rem;
  border-radius: 0.5rem;
  font-weight: 500;
  transition: background-color 0.2s;

  ${({ variant = 'primary' }) =>
    variant === 'primary'
      ? `
        background-color: #3b82f6;
        color: white;
        &:hover {
          background-color: #2563eb;
        }
      `
      : `
        background-color: #e5e7eb;
        color: #1f2937;
        &:hover {
          background-color: #d1d5db;
        }
      `}
`;

// With theme
import { ThemeProvider } from 'styled-components';

const theme = {
  colors: {
    primary: '#3b82f6',
    secondary: '#e5e7eb',
  },
  spacing: {
    sm: '0.5rem',
    md: '1rem',
  },
};

const ThemedButton = styled.button`
  background-color: ${({ theme }) => theme.colors.primary};
  padding: ${({ theme }) => theme.spacing.md};
`;

Component Variants Pattern

typescript
// Using cva (class-variance-authority) with Tailwind
import { cva, type VariantProps } from 'class-variance-authority';

const buttonVariants = cva(
  'inline-flex items-center justify-center rounded-md font-medium transition-colors',
  {
    variants: {
      variant: {
        primary: 'bg-blue-600 text-white hover:bg-blue-700',
        secondary: 'bg-gray-100 text-gray-900 hover:bg-gray-200',
        outline: 'border border-gray-300 hover:bg-gray-50',
        ghost: 'hover:bg-gray-100',
        danger: 'bg-red-600 text-white hover:bg-red-700',
      },
      size: {
        sm: 'h-8 px-3 text-sm',
        md: 'h-10 px-4',
        lg: 'h-12 px-6 text-lg',
      },
    },
    defaultVariants: {
      variant: 'primary',
      size: 'md',
    },
  }
);

interface ButtonProps
  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
    VariantProps<typeof buttonVariants> {}

function Button({ variant, size, className, ...props }: ButtonProps) {
  return (
    <button
      className={cn(buttonVariants({ variant, size }), className)}
      {...props}
    />
  );
}

// Usage
<Button variant="primary" size="lg">Large Primary</Button>
<Button variant="outline">Outline</Button>

Animation Patterns

Tailwind Animations

typescript
// Built-in animations
<div className="animate-spin">Loading...</div>
<div className="animate-pulse">Loading...</div>
<div className="animate-bounce">Scroll down</div>

// Transitions
<button className="transition-all duration-200 hover:scale-105">
  Hover me
</button>

// Custom animation in tailwind.config.js
module.exports = {
  theme: {
    extend: {
      animation: {
        'fade-in': 'fadeIn 0.3s ease-out',
        'slide-up': 'slideUp 0.3s ease-out',
      },
      keyframes: {
        fadeIn: {
          '0%': { opacity: '0' },
          '100%': { opacity: '1' },
        },
        slideUp: {
          '0%': { transform: 'translateY(10px)', opacity: '0' },
          '100%': { transform: 'translateY(0)', opacity: '1' },
        },
      },
    },
  },
};

// Usage
<div className="animate-fade-in">Fading in...</div>

Framer Motion

typescript
import { motion, AnimatePresence } from 'framer-motion';

function Modal({ isOpen, onClose, children }) {
  return (
    <AnimatePresence>
      {isOpen && (
        <>
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            className="fixed inset-0 bg-black/50"
            onClick={onClose}
          />
          <motion.div
            initial={{ opacity: 0, scale: 0.95, y: 20 }}
            animate={{ opacity: 1, scale: 1, y: 0 }}
            exit={{ opacity: 0, scale: 0.95, y: 20 }}
            className="fixed inset-x-4 top-1/2 -translate-y-1/2 bg-white rounded-lg p-6"
          >
            {children}
          </motion.div>
        </>
      )}
    </AnimatePresence>
  );
}

Layout Patterns

Flexbox

typescript
// Centering
<div className="flex items-center justify-center min-h-screen">
  <Card>Centered content</Card>
</div>

// Space between
<div className="flex items-center justify-between">
  <Logo />
  <Navigation />
  <UserMenu />
</div>

// Responsive direction
<div className="flex flex-col md:flex-row gap-4">
  <Sidebar />
  <Main />
</div>

Grid

typescript
// Equal columns
<div className="grid grid-cols-3 gap-4">
  {items.map(item => <Card key={item.id} {...item} />)}
</div>

// Complex layout
<div className="grid grid-cols-12 gap-4">
  <aside className="col-span-3">Sidebar</aside>
  <main className="col-span-6">Main content</main>
  <aside className="col-span-3">Right sidebar</aside>
</div>

// Auto-fit for unknown count
<div className="grid grid-cols-[repeat(auto-fit,minmax(250px,1fr))] gap-4">
  {items.map(item => <Card key={item.id} {...item} />)}
</div>

Container

typescript
// Centered container with max-width
<div className="container mx-auto px-4">
  <Content />
</div>

// Or with custom max-width
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
  <Content />
</div>

Theming System

typescript
// theme.ts
export const theme = {
  colors: {
    primary: {
      50: '#eff6ff',
      500: '#3b82f6',
      600: '#2563eb',
      700: '#1d4ed8',
    },
    gray: {
      50: '#f9fafb',
      100: '#f3f4f6',
      900: '#111827',
    },
  },
  spacing: {
    xs: '0.25rem',
    sm: '0.5rem',
    md: '1rem',
    lg: '1.5rem',
    xl: '2rem',
  },
} as const;

// CSS Variables approach
:root {
  --color-primary: #3b82f6;
  --color-background: #ffffff;
  --color-text: #111827;
}

.dark {
  --color-primary: #60a5fa;
  --color-background: #111827;
  --color-text: #f9fafb;
}

// Usage with Tailwind
<div className="bg-[var(--color-background)] text-[var(--color-text)]">
  Content
</div>

Common Issues

Issue Solution
Styles not applying Check class specificity, Tailwind purging
Dark mode flicker Use CSS variables or SSR-safe approach
Layout shift Set explicit dimensions, use skeleton loaders
Mobile overflow Add overflow-x-hidden to body
Z-index conflicts Use consistent z-index scale

File Structure

styles/
  globals.css          # Global styles, Tailwind imports
  variables.css        # CSS custom properties
components/
  Button/
    Button.tsx
    Button.module.css  # If using CSS Modules
    index.ts
tailwind.config.js     # Tailwind configuration

Didn't find tool you were looking for?

Be as detailed as possible for better results