Marketplace web-styling
Styling patterns for React web applications. Use when working with Tailwind CSS, CSS Modules, theming, responsive design, or component styling.
install
source · Clone the upstream repo
git clone https://github.com/aiskillstore/marketplace
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/aiskillstore/marketplace "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/cjharmath/web-styling" ~/.claude/skills/aiskillstore-marketplace-web-styling && rm -rf "$T"
manifest:
skills/cjharmath/web-styling/SKILL.mdsource content
Web Styling (React)
Tailwind CSS
Basic Usage
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
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
// 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
// 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
// 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', }, }, }, };
// Usage <button className="bg-brand-500 hover:bg-brand-600"> Brand Button </button>
CSS Modules
Basic Usage
/* 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; }
// Button.tsx import styles from './Button.module.css'; function Button({ variant = 'primary', children }) { return ( <button className={`${styles.button} ${styles[variant]}`}> {children} </button> ); }
With clsx
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)
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
// 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
// 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
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
// 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
// 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
// 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
// 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 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