React Component Skill
Description
Generate React components with TypeScript, hooks, and accessibility best practices.
Trigger
/reactcommand- User requests React component
- User needs React hooks
Prompt
You are a React expert that creates modern, accessible components.
Functional Component with Props
tsximport { FC, memo } from 'react'; interface ButtonProps { variant?: 'primary' | 'secondary' | 'danger'; size?: 'sm' | 'md' | 'lg'; disabled?: boolean; loading?: boolean; onClick?: () => void; children: React.ReactNode; } export const Button: FC<ButtonProps> = memo(({ variant = 'primary', size = 'md', disabled = false, loading = false, onClick, children, }) => { const baseStyles = 'inline-flex items-center justify-center font-medium rounded-lg transition-colors'; const variants = { primary: 'bg-blue-600 text-white hover:bg-blue-700 disabled:bg-blue-300', secondary: 'bg-gray-200 text-gray-900 hover:bg-gray-300 disabled:bg-gray-100', danger: 'bg-red-600 text-white hover:bg-red-700 disabled:bg-red-300', }; const sizes = { sm: 'px-3 py-1.5 text-sm', md: 'px-4 py-2 text-base', lg: 'px-6 py-3 text-lg', }; return ( <button type="button" className={`${baseStyles} ${variants[variant]} ${sizes[size]}`} disabled={disabled || loading} onClick={onClick} aria-busy={loading} > {loading && ( <svg className="animate-spin -ml-1 mr-2 h-4 w-4" 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 12h4z" /> </svg> )} {children} </button> ); }); Button.displayName = 'Button';
Custom Hook
tsximport { useState, useEffect, useCallback } from 'react'; interface UseFetchResult<T> { data: T | null; loading: boolean; error: Error | null; refetch: () => void; } export function useFetch<T>(url: string): UseFetchResult<T> { const [data, setData] = useState<T | null>(null); const [loading, setLoading] = useState(true); const [error, setError] = useState<Error | null>(null); const fetchData = useCallback(async () => { setLoading(true); setError(null); try { const response = await fetch(url); if (!response.ok) throw new Error(`HTTP ${response.status}`); const json = await response.json(); setData(json); } catch (e) { setError(e instanceof Error ? e : new Error('Unknown error')); } finally { setLoading(false); } }, [url]); useEffect(() => { fetchData(); }, [fetchData]); return { data, loading, error, refetch: fetchData }; }
Context Provider
tsximport { createContext, useContext, useState, ReactNode } from 'react'; interface User { id: string; name: string; email: string; } interface AuthContextType { user: User | null; login: (email: string, password: string) => Promise<void>; logout: () => void; isAuthenticated: boolean; } const AuthContext = createContext<AuthContextType | undefined>(undefined); export function AuthProvider({ children }: { children: ReactNode }) { const [user, setUser] = useState<User | null>(null); const login = async (email: string, password: string) => { const response = await fetch('/api/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, password }), }); const data = await response.json(); setUser(data.user); }; const logout = () => setUser(null); return ( <AuthContext.Provider value={{ user, login, logout, isAuthenticated: !!user }}> {children} </AuthContext.Provider> ); } export function useAuth() { const context = useContext(AuthContext); if (!context) throw new Error('useAuth must be used within AuthProvider'); return context; }
Tags
react, typescript, components, hooks, frontend
Compatibility
- Codex: ✅
- Claude Code: ✅

