Agent Skill
2/7/2026webapp-devtailwind-ui
Use this skill when styling React/Next.js applications with Tailwind CSS. Provides patterns for responsive design, dark mode, animations, and common UI components.
A
amplifyautomation
1GitHub Stars
2Views
npx skills add AmplifyAutomation/amplify-plugin-marketplace
SKILL.md
| Name | webapp-devtailwind-ui |
| Description | Use this skill when styling React/Next.js applications with Tailwind CSS. Provides patterns for responsive design, dark mode, animations, and common UI components. |
name: webapp-dev:tailwind-ui description: Use this skill when styling React/Next.js applications with Tailwind CSS. Provides patterns for responsive design, dark mode, animations, and common UI components.
Tailwind CSS UI Patterns
Configuration
tailwind.config.ts
import type { Config } from 'tailwindcss'
const config: Config = {
content: [
'./src/**/*.{js,ts,jsx,tsx,mdx}',
'./components/**/*.{js,ts,jsx,tsx,mdx}',
'./app/**/*.{js,ts,jsx,tsx,mdx}',
],
darkMode: 'class',
theme: {
extend: {
colors: {
// Brand colors
brand: {
50: '#eff6ff',
100: '#dbeafe',
200: '#bfdbfe',
300: '#93c5fd',
400: '#60a5fa',
500: '#3b82f6',
600: '#2563eb',
700: '#1d4ed8',
800: '#1e40af',
900: '#1e3a8a',
},
},
fontFamily: {
sans: ['var(--font-inter)', 'system-ui', 'sans-serif'],
mono: ['var(--font-mono)', 'monospace'],
},
animation: {
'fade-in': 'fadeIn 0.5s ease-out',
'slide-up': 'slideUp 0.3s ease-out',
'slide-down': 'slideDown 0.3s ease-out',
'spin-slow': 'spin 3s linear infinite',
},
keyframes: {
fadeIn: {
'0%': { opacity: '0' },
'100%': { opacity: '1' },
},
slideUp: {
'0%': { transform: 'translateY(10px)', opacity: '0' },
'100%': { transform: 'translateY(0)', opacity: '1' },
},
slideDown: {
'0%': { transform: 'translateY(-10px)', opacity: '0' },
'100%': { transform: 'translateY(0)', opacity: '1' },
},
},
},
},
plugins: [
require('@tailwindcss/forms'),
require('@tailwindcss/typography'),
],
}
export default config
Responsive Design
Mobile-First Breakpoints
// Tailwind's default breakpoints:
// sm: 640px
// md: 768px
// lg: 1024px
// xl: 1280px
// 2xl: 1536px
// Always design mobile-first
<div className="
grid grid-cols-1 // Mobile: 1 column
sm:grid-cols-2 // Small: 2 columns
lg:grid-cols-3 // Large: 3 columns
xl:grid-cols-4 // XL: 4 columns
gap-4
">
{items.map(item => <Card key={item.id} {...item} />)}
</div>
Responsive Typography
<h1 className="
text-2xl // Mobile
sm:text-3xl // Small
md:text-4xl // Medium
lg:text-5xl // Large
font-bold tracking-tight
">
Welcome to Our App
</h1>
Responsive Navigation
// components/layouts/Header.tsx
'use client'
import { useState } from 'react'
import Link from 'next/link'
export function Header() {
const [isOpen, setIsOpen] = useState(false)
return (
<header className="sticky top-0 z-50 bg-white border-b border-gray-200">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between items-center h-16">
{/* Logo */}
<Link href="/" className="font-bold text-xl">
Logo
</Link>
{/* Desktop Navigation */}
<nav className="hidden md:flex items-center space-x-8">
<Link href="/features" className="text-gray-600 hover:text-gray-900">
Features
</Link>
<Link href="/pricing" className="text-gray-600 hover:text-gray-900">
Pricing
</Link>
<Link href="/login" className="text-gray-600 hover:text-gray-900">
Sign In
</Link>
<Link
href="/signup"
className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700"
>
Get Started
</Link>
</nav>
{/* Mobile Menu Button */}
<button
onClick={() => setIsOpen(!isOpen)}
className="md:hidden p-2 rounded-lg hover:bg-gray-100"
aria-label="Toggle menu"
>
<svg className="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
{isOpen ? (
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
) : (
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" />
)}
</svg>
</button>
</div>
{/* Mobile Navigation */}
{isOpen && (
<nav className="md:hidden py-4 border-t border-gray-200">
<div className="flex flex-col space-y-4">
<Link href="/features" className="text-gray-600 hover:text-gray-900">
Features
</Link>
<Link href="/pricing" className="text-gray-600 hover:text-gray-900">
Pricing
</Link>
<Link href="/login" className="text-gray-600 hover:text-gray-900">
Sign In
</Link>
<Link
href="/signup"
className="px-4 py-2 bg-blue-600 text-white rounded-lg text-center"
>
Get Started
</Link>
</div>
</nav>
)}
</div>
</header>
)
}
Dark Mode
Setup
// app/layout.tsx
import { ThemeProvider } from '@/components/ThemeProvider'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<ThemeProvider>{children}</ThemeProvider>
</body>
</html>
)
}
// components/ThemeProvider.tsx
'use client'
import { createContext, useContext, useEffect, useState } from 'react'
type Theme = 'light' | 'dark' | 'system'
const ThemeContext = createContext<{
theme: Theme
setTheme: (theme: Theme) => void
}>({
theme: 'system',
setTheme: () => {},
})
export function ThemeProvider({ children }: { children: React.ReactNode }) {
const [theme, setTheme] = useState<Theme>('system')
useEffect(() => {
const root = window.document.documentElement
root.classList.remove('light', 'dark')
if (theme === 'system') {
const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches
? 'dark'
: 'light'
root.classList.add(systemTheme)
} else {
root.classList.add(theme)
}
}, [theme])
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
)
}
export const useTheme = () => useContext(ThemeContext)
Dark Mode Classes
// Use dark: prefix for dark mode styles
<div className="
bg-white dark:bg-gray-900
text-gray-900 dark:text-gray-100
border-gray-200 dark:border-gray-700
">
<h1 className="text-gray-900 dark:text-white">Title</h1>
<p className="text-gray-600 dark:text-gray-400">Description</p>
</div>
Common UI Components
Hero Section
export function Hero() {
return (
<section className="relative overflow-hidden bg-gradient-to-b from-blue-50 to-white dark:from-gray-900 dark:to-gray-800">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-24 sm:py-32">
<div className="text-center">
<h1 className="text-4xl sm:text-5xl lg:text-6xl font-bold tracking-tight text-gray-900 dark:text-white">
Build amazing apps
<span className="block text-blue-600">with modern tools</span>
</h1>
<p className="mt-6 max-w-2xl mx-auto text-lg sm:text-xl text-gray-600 dark:text-gray-300">
The fastest way to build and deploy your next web application.
Get started in minutes.
</p>
<div className="mt-10 flex flex-col sm:flex-row gap-4 justify-center">
<a
href="/signup"
className="px-8 py-3 bg-blue-600 text-white font-medium rounded-lg hover:bg-blue-700 transition-colors"
>
Get Started Free
</a>
<a
href="/demo"
className="px-8 py-3 border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 font-medium rounded-lg hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors"
>
View Demo
</a>
</div>
</div>
</div>
</section>
)
}
Feature Grid
const features = [
{ icon: '⚡', title: 'Fast', description: 'Optimized for speed' },
{ icon: '🔒', title: 'Secure', description: 'Built-in security' },
{ icon: '📱', title: 'Responsive', description: 'Works everywhere' },
{ icon: '🎨', title: 'Beautiful', description: 'Modern design' },
]
export function Features() {
return (
<section className="py-16 sm:py-24">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-12">
<h2 className="text-3xl font-bold text-gray-900 dark:text-white">
Everything you need
</h2>
<p className="mt-4 text-gray-600 dark:text-gray-400">
Built with the best tools and practices
</p>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-8">
{features.map((feature) => (
<div
key={feature.title}
className="p-6 bg-white dark:bg-gray-800 rounded-xl shadow-sm border border-gray-200 dark:border-gray-700 hover:shadow-md transition-shadow"
>
<div className="text-4xl mb-4">{feature.icon}</div>
<h3 className="font-semibold text-gray-900 dark:text-white">
{feature.title}
</h3>
<p className="mt-2 text-gray-600 dark:text-gray-400">
{feature.description}
</p>
</div>
))}
</div>
</div>
</section>
)
}
Pricing Cards
export function PricingCard({
name,
price,
description,
features,
highlighted = false,
}: {
name: string
price: string
description: string
features: string[]
highlighted?: boolean
}) {
return (
<div
className={`
rounded-2xl p-8
${highlighted
? 'bg-blue-600 text-white ring-4 ring-blue-600 ring-offset-2'
: 'bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700'
}
`}
>
<h3 className={`font-semibold ${highlighted ? 'text-blue-100' : 'text-gray-500 dark:text-gray-400'}`}>
{name}
</h3>
<p className="mt-4">
<span className={`text-4xl font-bold ${highlighted ? 'text-white' : 'text-gray-900 dark:text-white'}`}>
{price}
</span>
<span className={highlighted ? 'text-blue-100' : 'text-gray-500 dark:text-gray-400'}>
/month
</span>
</p>
<p className={`mt-4 ${highlighted ? 'text-blue-100' : 'text-gray-600 dark:text-gray-400'}`}>
{description}
</p>
<ul className="mt-8 space-y-4">
{features.map((feature) => (
<li key={feature} className="flex items-center">
<svg
className={`w-5 h-5 mr-3 ${highlighted ? 'text-blue-200' : 'text-green-500'}`}
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
</svg>
<span className={highlighted ? 'text-white' : 'text-gray-600 dark:text-gray-300'}>
{feature}
</span>
</li>
))}
</ul>
<button
className={`
mt-8 w-full py-3 px-4 rounded-lg font-medium transition-colors
${highlighted
? 'bg-white text-blue-600 hover:bg-blue-50'
: 'bg-blue-600 text-white hover:bg-blue-700'
}
`}
>
Get Started
</button>
</div>
)
}
Modal/Dialog
// components/ui/Modal.tsx
'use client'
import { useEffect, useRef } from 'react'
import { createPortal } from 'react-dom'
interface ModalProps {
isOpen: boolean
onClose: () => void
title: string
children: React.ReactNode
}
export function Modal({ isOpen, onClose, title, children }: ModalProps) {
const overlayRef = useRef<HTMLDivElement>(null)
useEffect(() => {
const handleEscape = (e: KeyboardEvent) => {
if (e.key === 'Escape') onClose()
}
if (isOpen) {
document.addEventListener('keydown', handleEscape)
document.body.style.overflow = 'hidden'
}
return () => {
document.removeEventListener('keydown', handleEscape)
document.body.style.overflow = 'unset'
}
}, [isOpen, onClose])
if (!isOpen) return null
return createPortal(
<div
ref={overlayRef}
className="fixed inset-0 z-50 flex items-center justify-center p-4"
onClick={(e) => e.target === overlayRef.current && onClose()}
>
{/* Backdrop */}
<div className="absolute inset-0 bg-black/50 backdrop-blur-sm" />
{/* Modal */}
<div className="relative w-full max-w-lg bg-white dark:bg-gray-800 rounded-xl shadow-xl animate-slide-up">
{/* Header */}
<div className="flex items-center justify-between p-4 border-b border-gray-200 dark:border-gray-700">
<h2 className="text-lg font-semibold text-gray-900 dark:text-white">
{title}
</h2>
<button
onClick={onClose}
className="p-1 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700"
>
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
{/* Content */}
<div className="p-4">{children}</div>
</div>
</div>,
document.body
)
}
Animation Patterns
Hover Effects
// Scale on hover
<button className="transform hover:scale-105 transition-transform duration-200">
Click me
</button>
// Lift on hover
<div className="hover:-translate-y-1 hover:shadow-lg transition-all duration-200">
Card content
</div>
// Color transition
<a className="text-gray-600 hover:text-blue-600 transition-colors duration-150">
Link
</a>
Loading Spinner
export function Spinner({ className }: { className?: string }) {
return (
<svg
className={`animate-spin ${className}`}
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle
className="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="4"
/>
<path
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
/>
</svg>
)
}
Skeleton Loading
export function CardSkeleton() {
return (
<div className="animate-pulse">
<div className="bg-gray-200 dark:bg-gray-700 rounded-lg h-48" />
<div className="mt-4 space-y-3">
<div className="h-4 bg-gray-200 dark:bg-gray-700 rounded w-3/4" />
<div className="h-4 bg-gray-200 dark:bg-gray-700 rounded w-1/2" />
</div>
</div>
)
}
Layout Patterns
Centered Content
// Max width with padding
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
{/* Content */}
</div>
// Centered vertically and horizontally
<div className="min-h-screen flex items-center justify-center">
{/* Content */}
</div>
Sticky Footer Layout
export function Layout({ children }: { children: React.ReactNode }) {
return (
<div className="min-h-screen flex flex-col">
<Header />
<main className="flex-1">{children}</main>
<Footer />
</div>
)
}
Dashboard Layout
export function DashboardLayout({ children }: { children: React.ReactNode }) {
return (
<div className="min-h-screen bg-gray-50 dark:bg-gray-900">
{/* Sidebar */}
<aside className="fixed inset-y-0 left-0 w-64 bg-white dark:bg-gray-800 border-r border-gray-200 dark:border-gray-700">
<Sidebar />
</aside>
{/* Main content */}
<div className="pl-64">
<header className="sticky top-0 z-10 h-16 bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700">
<TopBar />
</header>
<main className="p-8">{children}</main>
</div>
</div>
)
}
Skills Info
Original Name:webapp-devtailwind-uiAuthor:amplifyautomation
Download