We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/redf0x1/ui-ux-pro-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server
No,Category,Issue,Platform,Description,Do,Don't,Code Example Good,Code Example Bad,Severity
1,Navigation,Smooth Scroll,Web,Anchor links should scroll smoothly to target section,Use scroll-behavior: smooth on html element,Jump directly without transition,html { scroll-behavior: smooth; },<a href='#section'> without CSS,High
2,Navigation,Sticky Navigation,Web,Fixed nav should not obscure content,Add padding-top to body equal to nav height,Let nav overlap first section content,pt-20 (if nav is h-20),No padding compensation,Medium
3,Navigation,Active State,All,Current page/section should be visually indicated,Highlight active nav item with color/underline,No visual feedback on current location,text-primary border-b-2,All links same style,Medium
4,Navigation,Back Button,Mobile,Users expect back to work predictably,Preserve navigation history properly,Break browser/app back button behavior,history.pushState(),location.replace(),High
5,Navigation,Deep Linking,All,URLs should reflect current state for sharing,Update URL on state/view changes,Static URLs for dynamic content,Use query params or hash,Single URL for all states,Medium
6,Navigation,Breadcrumbs,Web,Show user location in site hierarchy,Use for sites with 3+ levels of depth,Use for flat single-level sites,Home > Category > Product,Only on deep nested pages,Low
7,Animation,Excessive Motion,All,Too many animations cause distraction and motion sickness,Animate 1-2 key elements per view maximum,Animate everything that moves,Single hero animation,animate-bounce on 5+ elements,High
8,Animation,Duration Timing,All,Animations should feel responsive not sluggish,Use 150-300ms for micro-interactions,Use animations longer than 500ms for UI,transition-all duration-200,duration-1000,Medium
9,Animation,Reduced Motion,All,Respect user's motion preferences,Check prefers-reduced-motion media query,Ignore accessibility motion settings,"// CSS: @media (prefers-reduced-motion: reduce) { * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }}
// React hook:
const usePrefersReducedMotion = () => { const [prefersReduced, setPrefersReduced] = useState(false); useEffect(() => { const mq = window.matchMedia('(prefers-reduced-motion: reduce)'); setPrefersReduced(mq.matches); const handler = (e) => setPrefersReduced(e.matches); mq.addEventListener('change', handler); return () => mq.removeEventListener('change', handler); }, []); return prefersReduced; };
// Tailwind: motion-safe:animate-bounce motion-reduce:animate-none","// Ignores user preference: <div className=""animate-bounce"">Always animating</div>",High
10,Animation,Loading States,All,Show feedback during async operations,Use skeleton screens or spinners,Leave UI frozen with no feedback,"const Skeleton = () => (<div className=""animate-pulse space-y-4""><div className=""h-4 bg-gray-200 rounded w-3/4""></div><div className=""h-4 bg-gray-200 rounded w-1/2""></div><div className=""h-32 bg-gray-200 rounded""></div></div>); const Card = ({ isLoading data }) => isLoading ? <Skeleton /> : <div>{data}</div>;",Blank screen while loading,High
11,Animation,Hover vs Tap,All,Hover effects don't work on touch devices,Use click/tap for primary interactions,Rely only on hover for important actions,"// Good: Works on both touch and mouse
const Card = ({ onSelect, children }) => (<button onClick={onSelect} className=""p-4 border rounded-lg bg-white hover:bg-gray-50 active:bg-gray-100 focus:ring-2 focus:ring-blue-500 transition-colors touch-manipulation"">{children}</button>);
// For tooltips use click on mobile:
const Tooltip = ({ content, children }) => { const [show, setShow] = useState(false); return (<div className=""relative inline-block"" onMouseEnter={() => setShow(true)} onMouseLeave={() => setShow(false)} onClick={() => setShow(!show)}>{children}{show && <div className=""absolute z-10 p-2 bg-gray-900 text-white text-sm rounded"">{content}</div>}</div>);};","// Bad: Hover-only dropdown unreachable on touch
<div onMouseEnter={() => setOpen(true)}><Menu /></div>",High
12,Animation,Continuous Animation,All,Infinite animations are distracting,Use for loading indicators only,Use for decorative elements,animate-spin on loader,animate-bounce on icons,Medium
13,Animation,Transform Performance,Web,Some CSS properties trigger expensive repaints,Use transform and opacity for animations,Animate width/height/top/left properties,transform: translateY(),top: 10px animation,Medium
14,Animation,Easing Functions,All,Linear motion feels robotic,Use ease-out for entering ease-in for exiting,Use linear for UI transitions,ease-out,linear,Low
15,Layout,Z-Index Management,Web,Stacking context conflicts cause hidden elements,Define z-index scale system (10 20 30 50),Use arbitrary large z-index values,"// Define z-index scale in tailwind.config.js or CSS variables:
// z-0: base | z-10: dropdowns | z-20: sticky nav | z-30: modals | z-40: toasts | z-50: tooltips
const Modal = ({ children }) => (<div className=""fixed inset-0 z-30 flex items-center justify-center""><div className=""fixed inset-0 bg-black/50"" onClick={onClose} /><div className=""relative z-30 bg-white rounded-lg p-6 max-w-md w-full mx-4"">{children}</div></div>);
const Toast = ({ message }) => (<div className=""fixed bottom-4 right-4 z-40 p-4 bg-gray-900 text-white rounded-lg shadow-lg"">{message}</div>);","<div className=""z-[99999]"">Competing z-index</div> // Z-index wars cause bugs",High
16,Layout,Overflow Hidden,Web,Hidden overflow can clip important content,Test all content fits within containers,Blindly apply overflow-hidden,overflow-auto with scroll,overflow-hidden truncating content,Medium
17,Layout,Fixed Positioning,Web,Fixed elements can overlap or be inaccessible,Account for safe areas and other fixed elements,Stack multiple fixed elements carelessly,Fixed nav + fixed bottom with gap,Multiple overlapping fixed elements,Medium
18,Layout,Stacking Context,Web,New stacking contexts reset z-index,Understand what creates new stacking context,Expect z-index to work across contexts,Parent with z-index isolates children,z-index: 9999 not working,Medium
19,Layout,Content Jumping,Web,Layout shift when content loads is jarring,Reserve space for async content,Let images/content push layout around,"// Reserve space for images to prevent CLS (Cumulative Layout Shift)
<div className=""aspect-video bg-gray-100 rounded-lg overflow-hidden""><img src={imageUrl} alt=""..."" className=""w-full h-full object-cover"" loading=""lazy"" /></div>
// Skeleton with fixed dimensions:
const ImageSkeleton = () => (<div className=""aspect-video bg-gray-200 animate-pulse rounded-lg"" />);
// Next.js Image with placeholder:
<Image src=""/photo.jpg"" width={800} height={450} placeholder=""blur"" blurDataURL=""data:image/..."" className=""w-full h-auto"" />","<img src={url} /> // No dimensions causes layout shift when image loads",High
20,Layout,Viewport Units,Web,100vh can be problematic on mobile browsers,Use dvh or account for mobile browser chrome,Use 100vh for full-screen mobile layouts,min-h-dvh or min-h-screen,h-screen on mobile,Medium
21,Layout,Container Width,Web,Content too wide is hard to read,Limit max-width for text content (65-75ch),Let text span full viewport width,max-w-prose or max-w-3xl,Full width paragraphs,Medium
22,Touch,Touch Target Size,Mobile,Small buttons are hard to tap accurately,Minimum 44x44px touch targets,Tiny clickable areas,"<button className=""min-h-[44px] min-w-[44px] px-4 py-2 flex items-center justify-center bg-blue-600 text-white rounded-lg touch-manipulation"" aria-label=""Settings""><Settings className=""h-5 w-5"" /></button><a href=""/profile"" className=""inline-flex items-center min-h-[44px] px-3 py-2 text-blue-600 hover:underline"">View Profile</a>","<button className=""w-6 h-6 p-1""><Icon /></button> // 24px too small for touch",High
23,Touch,Touch Spacing,Mobile,Adjacent touch targets need adequate spacing,Minimum 8px gap between touch targets,Tightly packed clickable elements,gap-2 between buttons,gap-0 or gap-1,Medium
24,Touch,Gesture Conflicts,Mobile,Custom gestures can conflict with system,Avoid horizontal swipe on main content,Override system gestures,Vertical scroll primary,Horizontal swipe carousel only,Medium
25,Touch,Tap Delay,Mobile,300ms tap delay feels laggy,Use touch-action CSS or fastclick,Default mobile tap handling,touch-action: manipulation,No touch optimization,Medium
26,Touch,Pull to Refresh,Mobile,Accidental refresh is frustrating,Disable where not needed,Enable by default everywhere,overscroll-behavior: contain,Default overscroll,Low
27,Touch,Haptic Feedback,Mobile,Tactile feedback improves interaction feel,Use for confirmations and important actions,Overuse vibration feedback,navigator.vibrate(10),Vibrate on every tap,Low
28,Interaction,Focus States,All,Keyboard users need visible focus indicators,Use visible focus rings on interactive elements,Remove focus outline without replacement,"<button className=""px-4 py-2 bg-blue-600 text-white rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-shadow"" onClick={handleClick}>Submit</button>","<button className=""outline-none"" onClick={handleClick}>Submit</button> // No visible focus indicator",High
29,Interaction,Hover States,Web,Visual feedback on interactive elements,Change cursor and add subtle visual change,No hover feedback on clickable elements,hover:bg-gray-100 cursor-pointer,No hover style,Medium
30,Interaction,Active States,All,Show immediate feedback on press/click,Add pressed/active state visual change,No feedback during interaction,active:scale-95,No active state,Medium
31,Interaction,Disabled States,All,Clearly indicate non-interactive elements,Reduce opacity and change cursor,Confuse disabled with normal state,opacity-50 cursor-not-allowed,Same style as enabled,Medium
32,Interaction,Loading Buttons,All,Prevent double submission during async actions,Disable button and show loading state,Allow multiple clicks during processing,"<button type=""submit"" disabled={isLoading} className=""px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2""> {isLoading && <svg className=""animate-spin h-4 w-4"" viewBox=""0 0 24 24""><circle className=""opacity-25"" cx=""12"" cy=""12"" r=""10"" stroke=""currentColor"" strokeWidth=""4"" fill=""none""/><path className=""opacity-75"" fill=""currentColor"" d=""M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z""/></svg>} {isLoading ? 'Submitting...' : 'Submit'}</button>","<button onClick={handleSubmit}>Submit</button> // Clickable during async operation",High
33,Interaction,Error Feedback,All,Users need to know when something fails,Show clear error messages near problem,Silent failures with no feedback,"<div className=""space-y-1""><input type=""email"" className={`w-full px-3 py-2 border rounded-lg ${error ? 'border-red-500 focus:ring-red-500' : 'border-gray-300 focus:ring-blue-500'} focus:outline-none focus:ring-2`} aria-invalid={!!error} aria-describedby={error ? 'email-error' : undefined} />{error && <p id=""email-error"" className=""text-sm text-red-600 flex items-center gap-1"" role=""alert""><AlertCircle className=""h-4 w-4"" />{error}</p>}</div>","<input type=""email"" /> // No error indication",High
34,Interaction,Success Feedback,All,Confirm successful actions to users,Show success message or visual change,No confirmation of completed action,Toast notification or checkmark,Action completes silently,Medium
35,Interaction,Confirmation Dialogs,All,Prevent accidental destructive actions,Confirm before delete/irreversible actions,Delete without confirmation,"<Dialog open={isOpen} onOpenChange={setIsOpen}><DialogContent className=""sm:max-w-md"" role=""alertdialog"" aria-labelledby=""dialog-title"" aria-describedby=""dialog-desc""><DialogHeader><DialogTitle id=""dialog-title"">Delete Item?</DialogTitle><DialogDescription id=""dialog-desc"">This action cannot be undone. This will permanently delete the item.</DialogDescription></DialogHeader><DialogFooter className=""flex gap-2""><Button variant=""outline"" onClick={() => setIsOpen(false)}>Cancel</Button><Button variant=""destructive"" onClick={handleDelete} className=""bg-red-600 hover:bg-red-700"">Delete</Button></DialogFooter></DialogContent></Dialog>","<button onClick={deleteItem}>Delete</button> // No confirmation",High
36,Accessibility,Color Contrast,All,Text must be readable against background,Minimum 4.5:1 ratio for normal text,Low contrast text,"<p className=""text-gray-900 dark:text-gray-100"">High contrast body text (21:1 ratio)</p><p className=""text-gray-700 dark:text-gray-300"">Secondary text (8.6:1 ratio)</p><span className=""text-lg font-semibold text-gray-800"">Large text 3:1 minimum</span>","<p className=""text-gray-400"">Low contrast gray text (2.8:1)</p> // Fails WCAG AA",High
37,Accessibility,Color Only,All,Don't convey information by color alone,Use icons/text in addition to color,Red/green only for error/success,"<div className=""flex items-center gap-2 text-red-600"" role=""alert""><XCircle className=""h-5 w-5"" aria-hidden=""true"" /><span>Error: Invalid email address</span></div><div className=""flex items-center gap-2 text-green-600""><CheckCircle className=""h-5 w-5"" aria-hidden=""true"" /><span>Success: Changes saved</span></div>","<div className=""border-red-500 border-2"">Error field</div> // Color only no text/icon",High
38,Accessibility,Alt Text,All,Images need text alternatives,Descriptive alt text for meaningful images,Empty or missing alt attributes,"<img src=""/hero.jpg"" alt=""Team collaborating around whiteboard in modern office"" className=""w-full h-auto rounded-lg"" /><figure><img src=""/chart.png"" alt="""" aria-describedby=""chart-desc"" className=""w-full"" /><figcaption id=""chart-desc"">Q3 revenue increased 25% compared to Q2</figcaption></figure>","<img src=""/photo.jpg"" /> // Missing alt attribute entirely",High
39,Accessibility,Heading Hierarchy,Web,Screen readers use headings for navigation,Use sequential heading levels h1-h6,Skip heading levels or misuse for styling,h1 then h2 then h3,h1 then h4,Medium
40,Accessibility,ARIA Labels,All,Interactive elements need accessible names,Add aria-label for icon-only buttons,Icon buttons without labels,"<button aria-label=""Close menu"" className=""p-2 rounded-full hover:bg-gray-100 focus:ring-2 focus:ring-blue-500"" onClick={onClose}><X className=""h-5 w-5"" aria-hidden=""true"" /></button><button aria-label=""Delete item"" aria-describedby=""delete-hint"" className=""p-2 text-red-600 hover:bg-red-50 rounded""><Trash2 className=""h-5 w-5"" aria-hidden=""true"" /></button><span id=""delete-hint"" className=""sr-only"">Permanently removes this item</span>","<button className=""p-2""><X className=""h-5 w-5"" /></button> // No accessible name",High
41,Accessibility,Keyboard Navigation,Web,All functionality accessible via keyboard,Tab order matches visual order,Keyboard traps or illogical tab order,"<div role=""toolbar"" aria-label=""Text formatting"" className=""flex gap-1""><button tabIndex={0} aria-pressed={isBold} onClick={toggleBold} className=""p-2 rounded hover:bg-gray-100 focus:ring-2 focus:ring-blue-500"">Bold</button><button tabIndex={0} onClick={toggleItalic} className=""p-2 rounded hover:bg-gray-100 focus:ring-2 focus:ring-blue-500"">Italic</button></div>// Use onKeyDown for arrow key navigation within toolbar","<div onClick={handleClick} className=""cursor-pointer"">Clickable div</div> // Not keyboard accessible",High
42,Accessibility,Screen Reader,All,Content should make sense when read aloud,Use semantic HTML and ARIA properly,Div soup with no semantics,<nav> <main> <article>,<div> for everything,Medium
43,Accessibility,Form Labels,All,Inputs must have associated labels,Use label with for attribute or wrap input,Placeholder-only inputs,"<div className=""space-y-2""><label htmlFor=""email"" className=""block text-sm font-medium text-gray-700"">Email address <span className=""text-red-500"" aria-hidden=""true"">*</span></label><input id=""email"" type=""email"" required aria-required=""true"" autoComplete=""email"" placeholder=""you@example.com"" className=""w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"" /></div>","<input type=""email"" placeholder=""Email"" /> // Placeholder disappears on focus no persistent label",High
44,Accessibility,Error Messages,All,Error messages must be announced,Use aria-live or role=alert for errors,Visual-only error indication,"<div aria-live=""polite"" aria-atomic=""true"" className=""sr-only"">{announcement}</div><div role=""alert"" className=""p-4 bg-red-50 border border-red-200 rounded-lg flex items-start gap-3""><AlertCircle className=""h-5 w-5 text-red-600 flex-shrink-0 mt-0.5"" aria-hidden=""true"" /><div><p className=""font-medium text-red-800"">Form submission failed</p><p className=""text-sm text-red-700 mt-1"">Please correct the errors and try again.</p></div></div>","<div className=""border-red-500"">Error</div> // Not announced to screen readers",High
45,Accessibility,Skip Links,Web,Allow keyboard users to skip navigation,Provide skip to main content link,No skip link on nav-heavy pages,Skip to main content link,100 tabs to reach content,Medium
46,Performance,Image Optimization,All,Large images slow page load,Use appropriate size and format (WebP),Unoptimized full-size images,"import Image from 'next/image'; <Image src=""/hero.jpg"" alt=""Hero image"" width={800} height={400} priority className=""w-full h-auto"" sizes=""(max-width: 768px) 100vw (max-width: 1200px) 50vw 800px"" placeholder=""blur"" blurDataURL=""data:image/jpeg;base64...""/>// Or native: <img srcSet=""hero-400.webp 400w hero-800.webp 800w"" sizes=""(max-width: 600px) 400px 800px"" />","<img src=""/hero-4000px.jpg"" /> // Unoptimized 4000px image for 400px display",High
47,Performance,Lazy Loading,All,Load content as needed,Lazy load below-fold images and content,Load everything upfront,loading='lazy',All images eager load,Medium
48,Performance,Code Splitting,Web,Large bundles slow initial load,Split code by route/feature,Single large bundle,dynamic import(),All code in main bundle,Medium
49,Performance,Caching,Web,Repeat visits should be fast,Set appropriate cache headers,No caching strategy,Cache-Control headers,Every request hits server,Medium
50,Performance,Font Loading,Web,Web fonts can block rendering,Use font-display swap or optional,Invisible text during font load,font-display: swap,FOIT (Flash of Invisible Text),Medium
51,Performance,Third Party Scripts,Web,External scripts can block rendering,Load non-critical scripts async/defer,Synchronous third-party scripts,async or defer attribute,<script src='...'> in head,Medium
52,Performance,Bundle Size,Web,Large JavaScript slows interaction,Monitor and minimize bundle size,Ignore bundle size growth,Bundle analyzer,No size monitoring,Medium
53,Performance,Render Blocking,Web,CSS/JS can block first paint,Inline critical CSS defer non-critical,Large blocking CSS files,Critical CSS inline,All CSS in head,Medium
54,Forms,Input Labels,All,Every input needs a visible label,Always show label above or beside input,Placeholder as only label,"const FormField = ({ label, id, error, required, ...props }) => (<div className=""space-y-1.5""><label htmlFor={id} className=""block text-sm font-medium text-gray-700"">{label} {required && <span className=""text-red-500"">*</span>}</label><input id={id} aria-required={required} aria-invalid={!!error} aria-describedby={error ? `${id}-error` : undefined} className=""w-full px-3 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500"" {...props} />{error && <p id={`${id}-error`} className=""text-sm text-red-600"">{error}</p>}</div>);","<input placeholder=""Email"" /> // Label disappears on input",High
55,Forms,Error Placement,All,Errors should appear near the problem,Show error below related input,Single error message at top of form,Error under each field,All errors at form top,Medium
56,Forms,Inline Validation,All,Validate as user types or on blur,Validate on blur for most fields,Validate only on submit,onBlur validation,Submit-only validation,Medium
57,Forms,Input Types,All,Use appropriate input types,Use email tel number url etc,Text input for everything,type='email',type='text' for email,Medium
58,Forms,Autofill Support,Web,Help browsers autofill correctly,Use autocomplete attribute properly,Block or ignore autofill,autocomplete='email',autocomplete='off' everywhere,Medium
59,Forms,Required Indicators,All,Mark required fields clearly,Use asterisk or (required) text,No indication of required fields,* required indicator,Guess which are required,Medium
60,Forms,Password Visibility,All,Let users see password while typing,Toggle to show/hide password,No visibility toggle,Show/hide password button,Password always hidden,Medium
61,Forms,Submit Feedback,All,Confirm form submission status,Show loading then success/error state,No feedback after submit,"const [status setStatus] = useState('idle'); // idle | loading | success | error
const handleSubmit = async (e) => { e.preventDefault(); setStatus('loading'); try { await submitForm(data); setStatus('success'); } catch { setStatus('error'); }};
<form onSubmit={handleSubmit}><button disabled={status === 'loading'} className=""px-4 py-2 bg-blue-600 text-white rounded-lg disabled:opacity-50"">{status === 'loading' ? 'Submitting...' : 'Submit'}</button>{status === 'success' && <p className=""text-green-600 flex items-center gap-2"" role=""status""><CheckCircle className=""h-4 w-4""/>Saved!</p>}{status === 'error' && <p className=""text-red-600"" role=""alert"">Failed. Try again.</p>}</form>","<button type=""submit"">Submit</button> // No loading/success/error feedback",High
62,Forms,Input Affordance,All,Inputs should look interactive,Use distinct input styling,Inputs that look like plain text,Border/background on inputs,Borderless inputs,Medium
63,Forms,Mobile Keyboards,Mobile,Show appropriate keyboard for input type,Use inputmode attribute,Default keyboard for all inputs,inputmode='numeric',Text keyboard for numbers,Medium
64,Responsive,Mobile First,Web,Design for mobile then enhance for larger,Start with mobile styles then add breakpoints,Desktop-first causing mobile issues,Default mobile + md: lg: xl:,Desktop default + max-width queries,Medium
65,Responsive,Breakpoint Testing,Web,Test at all common screen sizes,Test at 320 375 414 768 1024 1440,Only test on your device,Multiple device testing,Single device development,Medium
66,Responsive,Touch Friendly,Web,Mobile layouts need touch-sized targets,Increase touch targets on mobile,Same tiny buttons on mobile,"<nav className=""flex gap-1 md:gap-2""><a href=""/"" className=""min-h-[44px] md:min-h-[36px] px-4 py-3 md:py-2 text-sm font-medium rounded-lg hover:bg-gray-100 flex items-center"">Home</a><a href=""/about"" className=""min-h-[44px] md:min-h-[36px] px-4 py-3 md:py-2 text-sm font-medium rounded-lg hover:bg-gray-100 flex items-center"">About</a></nav>// Mobile: 44px height | Desktop: 36px height","<nav className=""flex gap-1""><a className=""px-2 py-1 text-xs"">Home</a></nav> // Same tiny size on all devices",High
67,Responsive,Readable Font Size,All,Text must be readable on all devices,Minimum 16px body text on mobile,Tiny text on mobile,"<p className=""text-base md:text-lg leading-relaxed text-gray-900"">Body text that scales responsively. Base 16px on mobile 18px on desktop.</p><span className=""text-sm text-gray-600"">Secondary text minimum 14px</span><input type=""text"" className=""text-base"" /> // Prevents iOS zoom on focus (16px+)","<p className=""text-xs leading-tight"">Tiny 12px body text</p> // Hard to read on mobile",High
68,Responsive,Viewport Meta,Web,Set viewport for mobile devices,Use width=device-width initial-scale=1,Missing or incorrect viewport,"<head><meta name=""viewport"" content=""width=device-width, initial-scale=1, viewport-fit=cover"" /><meta name=""theme-color"" content=""#3b82f6"" /></head>// Next.js: export const viewport = { width: 'device-width', initialScale: 1, viewportFit: 'cover' };","// No viewport meta - page renders at desktop width on mobile",High
69,Responsive,Horizontal Scroll,Web,Avoid horizontal scrolling,Ensure content fits viewport width,Content wider than viewport,"<main className=""w-full max-w-full overflow-x-hidden""><img className=""max-w-full h-auto"" src=""..."" alt=""..."" /><div className=""overflow-x-auto -mx-4 px-4 md:mx-0 md:px-0""><table className=""min-w-[600px] md:w-full"">...</table></div></main>// Allow horizontal scroll only for specific content like tables","<div className=""w-[1200px]"">Fixed width content</div> // Forces horizontal scroll on mobile",High
70,Responsive,Image Scaling,Web,Images should scale with container,Use max-width: 100% on images,Fixed width images overflow,max-w-full h-auto,width='800' fixed,Medium
71,Responsive,Table Handling,Web,Tables can overflow on mobile,Use horizontal scroll or card layout,Wide tables breaking layout,overflow-x-auto wrapper,Table overflows viewport,Medium
72,Typography,Line Height,All,Adequate line height improves readability,Use 1.5-1.75 for body text,Cramped or excessive line height,leading-relaxed (1.625),leading-none (1),Medium
73,Typography,Line Length,Web,Long lines are hard to read,Limit to 65-75 characters per line,Full-width text on large screens,max-w-prose,Full viewport width text,Medium
74,Typography,Font Size Scale,All,Consistent type hierarchy aids scanning,Use consistent modular scale,Random font sizes,Type scale (12 14 16 18 24 32),Arbitrary sizes,Medium
75,Typography,Font Loading,Web,Fonts should load without layout shift,Reserve space with fallback font,Layout shift when fonts load,font-display: swap + similar fallback,No fallback font,Medium
76,Typography,Contrast Readability,All,Body text needs good contrast,Use darker text on light backgrounds,Gray text on gray background,"<article className=""bg-white dark:bg-gray-900""><h1 className=""text-gray-900 dark:text-white font-bold text-2xl"">Heading</h1><p className=""text-gray-700 dark:text-gray-300 leading-relaxed"">Body text with 8:1+ contrast ratio for excellent readability.</p><span className=""text-gray-500 dark:text-gray-400 text-sm"">Caption text (4.5:1 minimum)</span></article>","<p className=""text-gray-400 bg-gray-100"">Low contrast text</p> // 2.5:1 ratio fails WCAG",High
77,Typography,Heading Clarity,All,Headings should stand out from body,Clear size/weight difference,Headings similar to body text,Bold + larger size,Same size as body,Medium
78,Feedback,Loading Indicators,All,Show system status during waits,Show spinner/skeleton for operations > 300ms,No feedback during loading,"const LoadingSpinner = ({ size = 'md' }) => (<svg className={`animate-spin ${size === 'sm' ? 'h-4 w-4' : 'h-6 w-6'} text-blue-600`} 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>);
const CardSkeleton = () => (<div className=""animate-pulse p-4 border rounded-lg""><div className=""h-4 bg-gray-200 rounded w-3/4 mb-4""/><div className=""h-20 bg-gray-200 rounded""/></div>);","// No loading indicator - UI appears frozen",High
79,Feedback,Empty States,All,Guide users when no content exists,Show helpful message and action,Blank empty screens,No items yet. Create one!,Empty white space,Medium
80,Feedback,Error Recovery,All,Help users recover from errors,Provide clear next steps,Error without recovery path,Try again button + help link,Error message only,Medium
81,Feedback,Progress Indicators,All,Show progress for multi-step processes,Step indicators or progress bar,No indication of progress,Step 2 of 4 indicator,No step information,Medium
82,Feedback,Toast Notifications,All,Transient messages for non-critical info,Auto-dismiss after 3-5 seconds,Toasts that never disappear,Auto-dismiss toast,Persistent toast,Medium
83,Feedback,Confirmation Messages,All,Confirm successful actions,Brief success message,Silent success,Saved successfully toast,No confirmation,Medium
84,Content,Truncation,All,Handle long content gracefully,Truncate with ellipsis and expand option,Overflow or broken layout,line-clamp-2 with expand,Overflow or cut off,Medium
85,Content,Date Formatting,All,Use locale-appropriate date formats,Use relative or locale-aware dates,Ambiguous date formats,2 hours ago or locale format,01/02/03,Low
86,Content,Number Formatting,All,Format large numbers for readability,Use thousand separators or abbreviations,Long unformatted numbers,"1.2K or 1,234",1234567,Low
87,Content,Placeholder Content,All,Show realistic placeholders during dev,Use realistic sample data,Lorem ipsum everywhere,Real sample content,Lorem ipsum,Low
88,Onboarding,User Freedom,All,Users should be able to skip tutorials,Provide Skip and Back buttons,Force linear unskippable tour,Skip Tutorial button,Locked overlay until finished,Medium
89,Search,Autocomplete,Web,Help users find results faster,Show predictions as user types,Require full type and enter,Debounced fetch + dropdown,No suggestions,Medium
90,Search,No Results,Web,Dead ends frustrate users,Show 'No results' with suggestions,Blank screen or '0 results',Try searching for X instead,No results found.,Medium
91,Data Entry,Bulk Actions,Web,Editing one by one is tedious,Allow multi-select and bulk edit,Single row actions only,Checkbox column + Action bar,Repeated actions per row,Low
92,AI Interaction,Disclaimer,All,Users need to know they talk to AI,Clearly label AI generated content,Present AI as human,"const AIMessage = ({ content timestamp }) => (<div className=""flex gap-3""><div className=""flex-shrink-0""><div className=""w-8 h-8 rounded-full bg-gradient-to-br from-purple-500 to-blue-500 flex items-center justify-center""><Sparkles className=""h-4 w-4 text-white"" /></div></div><div className=""flex-1""><div className=""flex items-center gap-2 mb-1""><span className=""font-medium text-gray-900"">AI Assistant</span><span className=""text-xs px-1.5 py-0.5 bg-purple-100 text-purple-700 rounded"">AI</span><time className=""text-xs text-gray-500"">{timestamp}</time></div><div className=""p-3 bg-gray-100 rounded-lg rounded-tl-none""><p className=""text-gray-800"">{content}</p></div><p className=""text-xs text-gray-500 mt-1 italic"">AI-generated content may contain errors</p></div></div>);","// Bad: <div><strong>Sarah</strong><p>{aiResponse}</p></div> // Fake human name hides AI",High
93,AI Interaction,Streaming,All,Waiting for full text is slow,Stream text response token by token,Show loading spinner for 10s+,Typewriter effect,Spinner until 100% complete,Medium
94,Spatial UI,Gaze Hover,VisionOS,Elements should respond to eye tracking before pinch,Scale/highlight element on look,Static element until pinch,hoverEffect(),onTap only,High
95,Spatial UI,Depth Layering,VisionOS,UI needs Z-depth to separate content from environment,Use glass material and z-offset,Flat opaque panels blocking view,.glassBackgroundEffect(),bg-white,Medium
96,Sustainability,Auto-Play Video,Web,Video consumes massive data and energy,Click-to-play or pause when off-screen,Auto-play high-res video loops,playsInline muted preload='none',autoplay loop,Medium
97,Sustainability,Asset Weight,Web,Heavy 3D/Image assets increase carbon footprint,Compress and lazy load 3D models,Load 50MB textures,Draco compression,Raw .obj files,Medium
98,AI Interaction,Feedback Loop,All,AI needs user feedback to improve,Thumps up/down or 'Regenerate',Static output only,Feedback component,Read-only text,Low
99,Accessibility,Motion Sensitivity,All,Parallax/Scroll-jacking causes nausea,Respect prefers-reduced-motion,Force scroll effects,@media (prefers-reduced-motion),ScrollTrigger.create(),High
100,Dashboard,KPI Hierarchy,Web,Dashboard KPIs should follow visual hierarchy,Most important KPIs largest and top-left,Equal sizing for all metrics,"const Dashboard = () => (<div className=""space-y-6""><div className=""grid grid-cols-1 md:grid-cols-2 gap-6""><KPICard title=""Total Revenue"" value=""$1.2M"" change=""+12%"" primary className=""md:col-span-2 p-6 bg-gradient-to-r from-blue-600 to-blue-700 text-white rounded-xl""/></div><div className=""grid grid-cols-2 md:grid-cols-4 gap-4"">{secondaryKPIs.map(kpi => (<KPICard key={kpi.id} {...kpi} className=""p-4 bg-white border rounded-lg"" />))}</div></div>);
const KPICard = ({ title value change primary className }) => (<div className={className}><p className={`text-sm ${primary ? 'text-blue-100' : 'text-gray-600'}`}>{title}</p><p className={`text-3xl font-bold ${primary ? 'text-white' : 'text-gray-900'}`}>{value}</p><span className=""text-sm text-green-500"">{change}</span></div>);","// All cards same size: <div className=""grid grid-cols-4 gap-4"">{kpis.map(k => <Card />)}</div>",High
101,Dashboard,Data Visualization Choice,Web,Choose chart types based on data story,Line for trends bar for comparison pie for composition,Wrong chart for data type,Line chart for time series,Pie chart for time series,High
102,Dashboard,Filter Persistence,Web,Dashboard filters should persist across sessions,Save filter state to localStorage or URL,Reset filters on page refresh,URL params for filter state,Filters reset on navigation,Medium
103,AI Interface,Streaming Response,All,AI responses should stream token by token,Show text as it generates with typing indicator,Wait for complete response then show,"const StreamingMessage = () => { const [text setText] = useState(''); const [isStreaming setIsStreaming] = useState(true);
useEffect(() => { const stream = await fetch('/api/ai' { method: 'POST' }).body.getReader();
while (true) { const { done value } = await stream.read(); if (done) break; setText(prev => prev + new TextDecoder().decode(value)); }
setIsStreaming(false); } []);
return (<div className=""prose""><p>{text}{isStreaming && <span className=""inline-block w-2 h-4 bg-gray-400 animate-pulse ml-1"" aria-label=""AI is typing"" />}</p></div>);};
// Shows text progressively as AI generates it","// Bad: 10+ second spinner then wall of text appears at once
<>{isLoading ? <Spinner /> : <p>{fullResponse}</p>}</>",High
104,AI Interface,Confidence Display,All,Show AI confidence levels when relevant,Visual confidence indicator for uncertain outputs,Hide uncertainty from users,Confidence bar or percentage,No indication of AI certainty,Medium
105,AI Interface,Error Recovery,All,AI errors should offer clear recovery paths,Retry button + alternative suggestions,Generic error message only,"const AIErrorState = ({ error onRetry onSimplify }) => (<div className=""p-4 bg-red-50 border border-red-200 rounded-lg"" role=""alert""><div className=""flex items-start gap-3""><AlertCircle className=""h-5 w-5 text-red-600 flex-shrink-0"" /><div className=""flex-1""><p className=""font-medium text-red-800"">Unable to generate response</p><p className=""text-sm text-red-700 mt-1"">{error.message || 'The AI service encountered an issue.'}</p><div className=""flex flex-wrap gap-2 mt-3""><button onClick={onRetry} className=""px-3 py-1.5 bg-red-600 text-white text-sm rounded-lg hover:bg-red-700 flex items-center gap-1""><RefreshCw className=""h-4 w-4"" />Try again</button><button onClick={onSimplify} className=""px-3 py-1.5 border border-red-300 text-red-700 text-sm rounded-lg hover:bg-red-100"">Simplify request</button></div></div></div></div>);","<p className=""text-red-600"">Error: Something went wrong</p> // No recovery options",High
106,WCAG 2.2,Target Size,All,Interactive elements need minimum 24x24px target,Minimum 24x24px (WCAG 2.5.8 AA),Smaller touch/click targets,"// WCAG 2.5.8 requires 24x24px minimum (AA) 44x44px for AAA
const IconButton = ({ icon: Icon label onClick }) => (<button onClick={onClick} aria-label={label} className=""min-w-[24px] min-h-[24px] p-1.5 rounded hover:bg-gray-100 focus:ring-2 focus:ring-blue-500 focus:outline-none inline-flex items-center justify-center""><Icon className=""h-4 w-4"" aria-hidden=""true"" /></button>);
// For mobile: use min-w-[44px] min-h-[44px] for better touch targets","<button className=""p-0.5""><X className=""h-3 w-3"" /></button> // 16px target too small",High
107,WCAG 2.2,Dragging Alternatives,All,Dragging operations need single-pointer alternative,Provide buttons or menus for drag actions,Drag-only interactions,"const ReorderItem = ({ item index onMove canMoveUp canMoveDown }) => (<li className=""flex items-center gap-2 p-3 bg-white border rounded-lg""><button aria-label=""Drag to reorder"" className=""cursor-grab p-1 hover:bg-gray-100 rounded""><GripVertical className=""h-5 w-5 text-gray-400"" /></button><span className=""flex-1"">{item.name}</span><div className=""flex flex-col""><button onClick={() => onMove(index -1)} disabled={!canMoveUp} aria-label=""Move up"" className=""p-1 hover:bg-gray-100 rounded disabled:opacity-30""><ChevronUp className=""h-4 w-4"" /></button><button onClick={() => onMove(index 1)} disabled={!canMoveDown} aria-label=""Move down"" className=""p-1 hover:bg-gray-100 rounded disabled:opacity-30""><ChevronDown className=""h-4 w-4"" /></button></div></li>);","// Drag-only: <div draggable onDrag={...}>{item}</div> // No keyboard alternative",High
108,Mobile UX,Gesture Patterns,Mobile,Use platform-native gesture patterns,Swipe to delete pull to refresh pinch to zoom,Custom unfamiliar gestures,iOS-style swipe actions,Custom swipe patterns,Medium
109,Mobile UX,Thumb Zone,Mobile,Place primary actions in thumb-friendly zones,Primary CTA bottom center or bottom right,Important actions at top of screen,"// Bottom navigation for primary actions - thumb-friendly zone
const MobileNav = () => (<nav className=""fixed bottom-0 inset-x-0 bg-white border-t safe-area-pb""><div className=""flex justify-around items-center h-16""><NavItem icon={Home} label=""Home"" href=""/"" /><NavItem icon={Search} label=""Search"" href=""/search"" /><NavItem icon={Plus} label=""Create"" href=""/new"" primary /><NavItem icon={Bell} label=""Alerts"" href=""/alerts"" /><NavItem icon={User} label=""Profile"" href=""/profile"" /></div></nav>);
// FAB for primary action: <button className=""fixed bottom-20 right-4 w-14 h-14 rounded-full bg-blue-600 shadow-lg"">+</button>","<header><button className=""absolute top-4 right-4"">+ Create</button></header> // Hard to reach with thumb",High
110,Voice UI,Multimodal Design,All,Voice interfaces should have visual fallbacks,Voice + screen + touch options,Voice-only with no visual,"const VoiceSearch = () => (<div className=""relative""><input type=""search"" placeholder=""Search or say a command..."" className=""w-full pl-10 pr-12 py-3 border rounded-lg"" aria-label=""Search"" /><Search className=""absolute left-3 top-1/2 -translate-y-1/2 h-5 w-5 text-gray-400"" /><button onClick={startVoice} aria-label={isListening ? 'Stop listening' : 'Start voice search'} className=""absolute right-2 top-1/2 -translate-y-1/2 p-2 rounded-full hover:bg-gray-100"">{isListening ? <MicOff className=""h-5 w-5 text-red-500 animate-pulse"" /> : <Mic className=""h-5 w-5 text-gray-600"" />}</button>{transcript && <p className=""mt-2 text-sm text-gray-600"" aria-live=""polite"">Heard: ""{transcript}""</p>}</div>);","// Voice-only: 'Say a command to continue' with no visual input option",High
111,Progressive Disclosure,AI Complexity,All,Hide AI complexity behind progressive disclosure,Simple default with advanced options expandable,All AI options visible at once,Advanced settings collapsed,20 AI parameters visible,Medium
112,Conversational UI,Thread Design,All,Chat threads need clear message attribution,Distinct visual separation between user and AI,Ambiguous message ownership,"const ChatMessage = ({ message isUser }) => (<div className={`flex gap-3 ${isUser ? 'flex-row-reverse' : ''}`}><div className=""flex-shrink-0""><div className={`w-8 h-8 rounded-full flex items-center justify-center ${isUser ? 'bg-blue-600' : 'bg-gray-200'}`}>{isUser ? <User className=""h-4 w-4 text-white"" /> : <Bot className=""h-4 w-4 text-gray-600"" />}</div></div><div className={`max-w-[80%] p-3 rounded-2xl ${isUser ? 'bg-blue-600 text-white rounded-br-md' : 'bg-gray-100 text-gray-900 rounded-bl-md'}`} aria-label={isUser ? 'You said' : 'Assistant said'}><p>{message.content}</p><time className={`text-xs mt-1 block ${isUser ? 'text-blue-200' : 'text-gray-500'}`}>{message.time}</time></div></div>);","// All messages same gray bubble - unclear who said what",High
113,Collaboration,Real-time Presence,Web,Show collaborator presence and activity,Cursor positions avatars typing indicators,No indication of other users,Live cursors with names,No presence indication,Medium
114,AI Systems,Graceful Degradation,All,AI features should degrade gracefully when unavailable,Fallback to non-AI alternative,Feature completely unavailable,"const SmartInput = ({ onSubmit }) => { const { data: suggestions error isLoading } = useAISuggestions(); return (<div className=""space-y-2""><div className=""relative""><input type=""text"" className=""w-full px-3 py-2 border rounded-lg pr-10"" placeholder=""Type or get AI suggestions..."" />{!error && <button onClick={getAISuggestion} disabled={isLoading} className=""absolute right-2 top-1/2 -translate-y-1/2 p-1 hover:bg-gray-100 rounded"" aria-label=""Get AI suggestion""><Sparkles className={`h-4 w-4 ${isLoading ? 'animate-pulse text-gray-400' : 'text-blue-600'}`} /></button>}</div>{error && <p className=""text-sm text-gray-500"">AI suggestions unavailable. Please type manually.</p>}{!error && suggestions && <SuggestionsList items={suggestions} />}</div>);};","// AI unavailable: <div className=""text-red-600"">Error: AI service is down</div> // Feature completely broken",High
115,Onboarding,AI Expectation Setting,All,Set realistic expectations for AI capabilities,Clear explanation of what AI can and cannot do,Overpromise AI capabilities,"const AIDisclaimer = () => (<div className=""p-4 bg-blue-50 border border-blue-200 rounded-lg""><div className=""flex items-start gap-3""><Info className=""h-5 w-5 text-blue-600 flex-shrink-0 mt-0.5"" /><div><h3 className=""font-medium text-blue-900"">About AI Assistant</h3><div className=""mt-2 text-sm text-blue-800 space-y-2""><p><strong>Can help with:</strong> Drafting content summarizing text answering questions brainstorming ideas</p><p><strong>Limitations:</strong> May produce inaccurate information. Cannot access real-time data or browse the web. Not suitable for medical legal or financial advice.</p><p className=""text-blue-600"">Always verify important information independently.</p></div></div></div></div>);","<p>AI can do anything you need!</p> // Overpromising leads to disappointment",High
116,Animation,View Transitions API,Web,Use View Transitions for smooth page-to-page navigation,Enable with startViewTransition() or CSS @view-transition,Instant jumps between pages without transition,"document.startViewTransition(() => { updateDOM(); }); // Or in CSS: @view-transition { navigation: auto; }","updateDOM(); // Direct DOM update without transition causes jarring page change",High
117,Animation,View Transition Names,Web,Named elements persist across page transitions with visual continuity,Add view-transition-name to shared elements like hero images,"Forget to name elements that should persist across views","<img src={hero} style={{ viewTransitionName: 'hero-image' }} alt=""Hero"" /> // Element morphs between pages","<img src={hero} alt=""Hero"" /> // No view-transition-name means no cross-page animation",Medium
118,Navigation,Cross-Document View Transitions,Web,Same-origin navigation transitions in Next.js/SPAs for seamless UX,Use Link with viewTransition prop in Next.js 15+,Ignore browser support - use progressive enhancement,"<Link viewTransition href=""/about"">About</Link> // Enables smooth cross-document transitions","<Link href=""/about"">About</Link> // No viewTransition prop means instant page swap",Medium
119,Animation,View Transition Fallback,Web,Handle browsers without View Transitions API support gracefully,Check document.startViewTransition support before using,Assume all browsers support View Transitions API,"if (document.startViewTransition) { document.startViewTransition(() => updateDOM()); } else { updateDOM(); } // Progressive enhancement","document.startViewTransition(() => updateDOM()); // Crashes in unsupported browsers",High
120,Animation,CSS Scroll-Driven Animations Basics,Web,Use animation-timeline: scroll() for scroll-linked animations,CSS animation-timeline: scroll(),JavaScript scroll event listeners,"animation-timeline: scroll(); animation-range: entry cover;","window.addEventListener('scroll', updateAnimation)",High
121,Animation,View Timeline for Element Visibility,Web,Use animation-timeline: view() for viewport-based animations,view() timeline for reveal animations,IntersectionObserver for simple reveals,"animation-timeline: view(); animation-range: entry 0% cover 40%;","useIntersectionObserver hook",Medium
122,Animation,Scroll-Driven Parallax Effects,Web,Create parallax without JavaScript using scroll(),CSS-only parallax with scroll timeline,requestAnimationFrame parallax,"@keyframes parallax { to { transform: translateY(-50%); } } .parallax { animation: parallax linear; animation-timeline: scroll(); }","onScroll={() => setTranslateY(scrollY * 0.5)}",Medium
123,Animation,Performance of Scroll Animations,Web,Prefer CSS scroll animations for better performance,CSS handles animation compositing,JS mutations every frame,".scroll-anim { animation: reveal linear; animation-timeline: scroll(); } /* Browser optimizes compositing */","requestAnimationFrame(() => element.style.transform = ...) // JS mutations every frame",High
124,Navigation,Navbar Scroll Threshold,Web,Navbar state should change at appropriate scroll distance,Use 50-100px scroll threshold for state change. Provides buffer before activating compact state,Change state immediately at scrollY > 0 (jarring) or too late > 150px (user misses transition),"window.addEventListener('scroll', () => { if (window.scrollY > 50) navbar.classList.add('scrolled'); else navbar.classList.remove('scrolled'); });","if (window.scrollY > 0) addClass('scrolled'); // Too sensitive triggers on any tiny scroll",Medium
125,Animation,Navbar Transition Timing,Web,Navbar transitions should feel smooth and professional,Use 0.3-0.4s duration with cubic-bezier easing for natural feel,Use linear easing or very fast transitions (<0.2s) which feel mechanical or jarring,".navbar { transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); } .navbar-logo { transition: transform 0.3s ease; }",".navbar { transition: all 0.1s linear; } // Too fast and robotic",Medium
126,Navigation,Mobile Menu Animation Patterns,Mobile,Mobile menu should animate smoothly when opening and closing,Use max-height + opacity or transform for smooth open/close animations with proper easing,Use display:none toggle which provides no animation and feels abrupt,".mobile-nav { max-height: 0; opacity: 0; overflow: hidden; transition: max-height 0.35s ease, opacity 0.3s ease; } .mobile-nav.active { max-height: 400px; opacity: 1; }",".mobile-nav { display: none; } .mobile-nav.active { display: block; } // No animation just instant toggle",Medium
127,Performance,Image Loading Effects,Web,Use blur-up placeholder technique for smooth image loading experience,Use low-res blurred placeholder that transitions to full resolution image. Prevents layout shift and provides visual feedback,Show empty space or cause layout shift during image load. Avoid no visual feedback while loading,".img-lazy { filter: blur(10px); transition: filter 0.3s ease; } .img-lazy.loaded { filter: blur(0); } /* Or use placeholder: */ .img-container { background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%); background-size: 200% 100%; }","img { opacity: 0; } img.loaded { opacity: 1; } /* No visual feedback during load */",Medium
128,Performance,Content Loading Placeholder,Web,Use skeleton with shimmer animation for loading states to improve perceived performance,Use skeleton screens with shimmer animation that matches content layout. Provides visual feedback and reduces perceived wait time,Show spinner or empty area while loading. Avoid blocking UI with no indication of what will load,".skeleton { background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%); background-size: 200% 100%; animation: shimmer 1.5s infinite; border-radius: 4px; } @keyframes shimmer { 0% { background-position: -200% 0; } 100% { background-position: 200% 0; } } .skeleton-text { height: 1em; margin: 0.5em 0; } .skeleton-avatar { width: 48px; height: 48px; border-radius: 50%; }",".loading { content: 'Loading...'; } /* Or just empty div with no visual feedback */",Medium
129,Navigation,Header Height Transition,Web,Navbar should shrink height on scroll to maximize content viewport while maintaining accessibility,Shrink from 80px to 56px with smooth transition (0.3s ease-out). Use explicit height values not just padding changes. Transition should feel natural and not jarring,Keep navbar same height on scroll which wastes screen space. Shrink too fast (<0.2s) which feels mechanical. Use only padding changes without explicit height,".navbar { position: fixed; height: 80px; transition: height 0.3s ease-out padding 0.3s ease-out; } .navbar.scrolled { height: 56px; padding: 0.75rem 2rem; } /* CSS Scroll-Driven (2026): */ @supports (animation-timeline: scroll()) { .navbar { animation: shrink linear both; animation-timeline: scroll(root); animation-range: 0px 100px; } @keyframes shrink { from { height: 80px; } to { height: 56px; } } }",".navbar { height: 80px; } /* No scroll state - wastes 24px viewport space on long pages */",Medium
130,Navigation,Auto-Hide Navigation Direction,Web Mobile,Hide navbar on scroll down and show on scroll up for maximum content visibility on mobile and content-heavy pages,Track scroll direction using prevScrollY comparison. Hide with transform translateY(-100%) for GPU-accelerated animation. Add 80px threshold before hiding to prevent jitter. Use requestAnimationFrame for performance,Use display:none which provides no animation. Hide immediately on any scroll amount causing jittery UX. Use raw scroll events without requestAnimationFrame throttling,".navbar { transform: translateY(0); transition: transform 0.3s ease; } .navbar.hidden { transform: translateY(-100%); } /* JS: let prevScrollY = window.scrollY; let ticking = false; window.addEventListener('scroll' () => { if (!ticking) { requestAnimationFrame(() => { const currScrollY = window.scrollY; if (currScrollY > prevScrollY && currScrollY > 80) { navbar.classList.add('hidden'); } else if (currScrollY < prevScrollY) { navbar.classList.remove('hidden'); } prevScrollY = currScrollY; ticking = false; }); ticking = true; } }); */",".navbar { display: block; } .navbar.hidden { display: none; } /* No animation causes jarring UX. Also: hiding on any scroll without threshold */",Medium
131,Mobile-Touch,WCAG Touch Target Minimum,Cross-platform,WCAG 2.5.8 requires minimum 24x24 CSS pixels for touch targets to ensure accessibility compliance,Use minimum 24x24px touch targets as absolute floor. Prefer 44x44px (iOS) or 48x48dp (Android) for comfortable tapping,Use touch targets smaller than 24x24px which fail WCAG 2.5.8 and cause accessibility issues,"<button className=""min-h-[24px] min-w-[24px] p-2"">OK</button> /* WCAG minimum */ <button className=""min-h-[44px] min-w-[44px]"">Better</button> /* Recommended */","<button className=""h-4 w-4""><Icon /></button> /* 16px fails WCAG 2.5.8 */",Critical
132,Mobile-Touch,iOS Touch Target Size,iOS,Apple HIG recommends 44x44 points minimum for comfortable touch targets on iOS devices,Use 44x44pt minimum for all tappable elements. Add padding to icons to meet minimum size,Use touch targets smaller than 44pt which cause mis-taps and frustration,"<TouchableOpacity style={{ minWidth: 44, minHeight: 44, padding: 12 }}><Icon size={20} /></TouchableOpacity>","<TouchableOpacity><Icon size={20} /></TouchableOpacity> /* Icon alone is too small */",High
133,Mobile-Touch,Android Touch Target Size,Android,Material Design 3 requires 48x48dp minimum touch targets with 8dp spacing between adjacent targets,Use 48x48dp minimum for all interactive elements. Ensure 8dp minimum gap between touch targets,Use touch targets smaller than 48dp or pack targets too closely together,"<Button android:minWidth=""48dp"" android:minHeight=""48dp"" android:layout_margin=""4dp"" />","<ImageButton android:layout_width=""32dp"" android:layout_height=""32dp"" /> /* Too small */",High
134,Mobile-Touch,Touch Target Spacing,Cross-platform,Adjacent touch targets need adequate spacing to prevent accidental taps on wrong elements,Maintain minimum 8dp/8pt gap between interactive elements. Use larger gaps (12-16dp) for destructive actions,Pack touch targets edge-to-edge with no spacing causing accidental activations,"<div className=""flex gap-3""><Button>Cancel</Button><Button>Confirm</Button></div>","<div className=""flex gap-0""><Button>Delete</Button><Button>Save</Button></div> /* Dangerous mis-tap risk */",High
135,Mobile-Touch,Touch Feedback Delay,Cross-platform,Immediate visual feedback on touch improves perceived responsiveness and confirms interaction,Show visual change within 100ms of touch. Use active/pressed states with scale or color change,Delay feedback more than 100ms or provide no visual confirmation of touch,"<button className=""active:scale-95 active:bg-blue-700 transition-transform duration-75"">Tap me</button>","<button className=""transition-all duration-500"">Slow feedback</button> /* 500ms too slow */",High
136,Mobile-Animation,iOS Animation Timing,iOS,iOS uses specific animation durations: fast (200-240ms) for simple transitions and moderate (340-360ms) for complex ones,Use 200-240ms for button presses and toggles. Use 340-360ms for modal presentations and page transitions,Use generic 300ms for everything or very slow animations that feel sluggish on iOS,"UIView.animate(withDuration: 0.24, delay: 0, options: .curveEaseOut) { /* fast transition */ }","UIView.animate(withDuration: 1.0) { /* Too slow for iOS feel */ }",Medium
137,Mobile-Animation,iOS Spring Animations,iOS,iOS favors spring-based animations for natural organic motion that feels responsive and alive,Use spring animations with damping 0.7-0.8 for bouncy feel. Apply to modals sheets and interactive elements,Use linear or ease-in-out timing functions which feel mechanical compared to springs,"UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.75, initialSpringVelocity: 0) { }","UIView.animate(withDuration: 0.3, animations: { }, options: .curveLinear) /* Feels robotic */",Medium
138,Mobile-Animation,Android Material Motion,Android,Material 3 uses physics-based MotionScheme with standard 300ms duration for shared element transitions,Use Material MotionScheme for consistent physics-based animations. Target 300ms for shared element transitions,Use custom timing that conflicts with Material motion system or feels inconsistent,"MaterialContainerTransform().apply { duration = 300; scrimColor = Color.TRANSPARENT }","ObjectAnimator.ofFloat(view, ""alpha"", 0f, 1f).setDuration(1000) /* Too slow */",Medium
139,Mobile-Animation,120Hz Display Optimization,Cross-platform,Modern 120Hz displays require smooth 120fps animations using GPU-optimized properties only,Animate only transform and opacity for 120fps capability. Keep animations under 500ms for responsiveness,Animate layout properties (width height margin) which cannot achieve 120fps on high refresh displays,"transform: translateX(100px); opacity: 0; transition: transform 0.3s, opacity 0.3s;","width: 100px; margin-left: 20px; transition: width 0.3s, margin 0.3s; /* Causes jank on 120Hz */",High
140,Mobile-Animation,Gesture-Driven Animation,Cross-platform,Animations should follow finger movement 1:1 during gestures for direct manipulation feel,Use gesture velocity to drive animation. Match animation position to finger position during drag,Animate independently of gesture creating disconnect between touch and visual response,"const translateX = useSharedValue(0); const gesture = Gesture.Pan().onUpdate(e => { translateX.value = e.translationX; });","onPanEnd: () => { Animated.timing(translateX, { toValue: 100, duration: 300 }) } /* Ignores gesture */",High
141,Mobile-Reachability,Thumb Zone Primary Actions,Cross-platform,Primary actions should be placed in the easy thumb zone (bottom 40% of screen) for one-handed use,Place CTAs and frequent actions in bottom 40% of screen. Use bottom sheets and FABs for key actions,Place primary actions in top corners requiring thumb stretch or two-handed operation,"<View style={{ position: 'absolute', bottom: 24, left: 24, right: 24 }}><Button>Primary CTA</Button></View>","<View style={{ position: 'absolute', top: 16, right: 16 }}><Button>Save</Button></View> /* Hard to reach */",High
142,Mobile-Reachability,Bottom Navigation Preference,Cross-platform,Bottom navigation outperforms hamburger menus for discoverability and one-handed reachability,Use bottom tab bar for 3-5 primary destinations. Reserve hamburger for secondary navigation,Hide primary navigation in hamburger menu at top requiring extra tap and thumb stretch,"<BottomNavigation><Tab icon=""home"" /><Tab icon=""search"" /><Tab icon=""profile"" /></BottomNavigation>","<TopBar><HamburgerMenu items={primaryNavItems} /></TopBar> /* Poor discoverability and reachability */",High
143,Mobile-Reachability,Stretch Zone Actions,Cross-platform,Middle screen area (stretch zone) is acceptable for secondary actions but avoid for frequent interactions,Place secondary actions and content browsing in middle area. Keep frequently-used controls at bottom,Place toggle switches sliders or frequent controls in middle zone requiring constant reaching,"<View style={{ flex: 1, justifyContent: 'center' }}><Text>Content here</Text></View>","<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}><Switch /> /* Frequent toggle in stretch zone */</View>",Medium
144,Mobile-Reachability,Hard Zone Avoidance,Cross-platform,Top corners are hardest to reach one-handed. Avoid placing critical or frequent actions there,Reserve top corners for infrequent actions like settings or overflow menus. Never place destructive actions there,Place primary CTAs close buttons or frequent actions in top corners causing thumb strain,"<Header><BackButton style={{ left: 0 }} /><OverflowMenu style={{ right: 0 }} /></Header>","<Header><SaveButton style={{ right: 16 }} /></Header> /* Frequent action in hard zone */",Medium
145,Mobile-Reachability,Large Phone Accommodation,Cross-platform,Phones over 6 inches make top 60% nearly unreachable one-handed requiring reachability mode,Design for one-handed use on 6.5+ inch screens. Test with thumb reach simulation tools,Assume users can reach all screen areas or will always use two hands,"/* iPhone reachability mode consideration */ <SafeAreaView edges={['bottom']}><View style={{ marginTop: 'auto' }}><ActionSheet /></View></SafeAreaView>","<View style={{ marginTop: 80 }}><PrimaryActions /></View> /* Forces two-handed use on large phones */",Medium
146,Mobile-Platform,iOS Visual Style,iOS,iOS design favors minimal shadows depth through blur and translucency and rounded corners,Use subtle shadows with blur. Apply SF Symbols. Use system blur effects for depth. Rounded corners 10-20pt,Use heavy drop shadows or flat design without depth cues which feels non-native on iOS,"<View style={{ backgroundColor: 'rgba(255,255,255,0.8)', backdropFilter: 'blur(20px)', borderRadius: 12 }}>","<View style={{ elevation: 8, shadowRadius: 8 }}> /* Android-style heavy shadow on iOS */",Medium
147,Mobile-Platform,iOS Date Picker Style,iOS,iOS uses scroll wheel pickers for date/time selection providing familiar haptic interaction pattern,Use UIDatePicker wheel style or equivalent. Provide haptic feedback on scroll stops,Use calendar grid picker which feels foreign to iOS users and lacks expected haptics,"<DatePicker mode=""date"" display=""spinner"" /> /* iOS native wheel style */","<CalendarPicker /> /* Android-style grid on iOS feels wrong */",Medium
148,Mobile-Platform,iOS Navigation Pattern,iOS,iOS uses edge swipe for back navigation and horizontal tab bars. Respect these system patterns,Implement interactivePopGestureRecognizer for back. Use TabBarController for main navigation,Disable edge swipe back or use Android-style drawer navigation which confuses iOS users,"navigationController?.interactivePopGestureRecognizer?.isEnabled = true","gestureRecognizer.isEnabled = false /* Breaks expected iOS back gesture */",High
149,Mobile-Platform,Android Elevation System,Android,Material Design uses elevation and shadows to communicate hierarchy. Higher elevation = more importance,Use elevation 1-6dp for cards 8dp for dialogs 16dp for drawers. Match Material elevation spec,Use flat design without elevation or iOS-style blur which feels non-native on Android,"<Card style={{ elevation: 2 }}> /* Surface */ <Modal style={{ elevation: 24 }}> /* Dialog */","<Card style={{ shadowOpacity: 0.1 }}> /* iOS shadow style on Android */",Medium
150,Mobile-Platform,Android Date Picker Style,Android,Material Design uses calendar grid for date picking with clear month navigation and range selection,Use MaterialDatePicker with calendar grid view. Support date range selection where appropriate,Use iOS-style scroll wheels for dates which feels foreign and lacks Material interaction patterns,"MaterialDatePicker.Builder.datePicker().setTitleText(""Select date"").build()","<DatePicker mode=""spinner"" /> /* iOS wheel style on Android */",Medium
151,Mobile-Platform,Android Back Button,Android,Android has system back button/gesture that must be handled. Predictable back behavior is expected,Handle onBackPressed consistently. Use NavController for predictable back stack,Override or ignore system back creating navigation confusion or trapping users,"onBackPressedDispatcher.addCallback { navController.popBackStack() }","onBackPressed { /* do nothing */ } /* Traps user violates Android contract */",Critical
152,Mobile-Platform,Android Predictive Back,Android,Android 14+ supports predictive back gesture showing destination preview during back swipe,Enable predictive back animations. Ensure all activities handle back consistently for preview,Disable predictive back or have inconsistent back handling breaking the preview experience,"android:enableOnBackInvokedCallback=""true"" /* In manifest */","android:enableOnBackInvokedCallback=""false"" /* Disables modern back UX */",Medium
153,Mobile-Accessibility,Screen Reader Touch,Cross-platform,Screen reader users navigate by swiping and need logical focus order and clear labels,Implement proper accessibilityLabel for all interactive elements. Ensure logical tab/swipe order,Rely on visual-only cues or have illogical focus order that confuses VoiceOver/TalkBack users,"<TouchableOpacity accessibilityLabel=""Submit order"" accessibilityRole=""button"" accessibilityHint=""Double tap to confirm"">","<TouchableOpacity><Image source={submitIcon} /></TouchableOpacity> /* No label for screen reader */",Critical
154,Mobile-Accessibility,Dynamic Type Support,iOS,iOS Dynamic Type allows users to set preferred text size. Apps must respect this setting,Use system fonts with Dynamic Type. Test at all accessibility sizes. Support up to xxxLarge,Use fixed font sizes that ignore Dynamic Type settings making text unreadable for low vision users,"UIFontMetrics.default.scaledFont(for: UIFont.systemFont(ofSize: 17))","UIFont.systemFont(ofSize: 17) /* Ignores Dynamic Type */",High
155,Mobile-Accessibility,Android Font Scaling,Android,Android allows font scaling up to 200%. Apps must handle this gracefully without breaking layout,Use sp units for text. Test at max font scale. Allow text containers to grow,Use dp for text or fixed height containers that clip scaled text,"android:textSize=""16sp"" /* Scales with user preference */","android:textSize=""16dp"" /* Won't scale */ android:layout_height=""48dp"" /* May clip large text */",High
156,Mobile-Accessibility,Reduce Motion Setting,Cross-platform,Users with vestibular disorders enable Reduce Motion. Apps must check and respect this preference,Query prefers-reduced-motion or UIAccessibility.isReduceMotionEnabled. Provide instant alternatives,Ignore reduce motion preference causing discomfort or nausea for vestibular disorder users,"if UIAccessibility.isReduceMotionEnabled { /* Use crossfade instead of slide */ }","UIView.animate(withDuration: 0.5) { /* Always animates regardless of setting */ }",Critical
157,Mobile-Accessibility,Touch Accommodation,Cross-platform,Users with motor impairments may need longer touch duration or different gesture requirements,Support iOS Touch Accommodations and Android accessibility timeout. Test with Switch Control,Require precise quick taps or complex multi-finger gestures that exclude motor-impaired users,"<TouchableOpacity delayPressIn={150} delayLongPress={800}> /* Accommodates slower input */","<TouchableOpacity delayLongPress={200}> /* Too fast for motor impairment */",High
158,Mobile-SafeArea,iOS Safe Area Insets,iOS,iPhone notch and home indicator require safe area handling to avoid content being obscured,Use safeAreaInsets on all screens. Apply to both top (notch) and bottom (home indicator),Ignore safe areas causing content to render behind notch or under home indicator,"<SafeAreaView><Content /></SafeAreaView> /* Or */ padding-top: env(safe-area-inset-top);","<View style={{ flex: 1 }}><Content /></View> /* Content hidden behind notch */",Critical
159,Mobile-SafeArea,Android Display Cutout,Android,Android devices have various cutout shapes (notch punch-hole) requiring display cutout handling,Use WindowInsets API. Set android:windowLayoutInDisplayCutoutMode in theme,Ignore display cutouts causing content to render behind camera or sensor housing,"WindowCompat.setDecorFitsSystemWindows(window, false); ViewCompat.setOnApplyWindowInsetsListener(view) { }","/* No inset handling - content behind cutout */",High
160,Mobile-SafeArea,Bottom Safe Area CTA,Cross-platform,Bottom CTAs must account for home indicator/gesture bar to remain fully visible and tappable,Add safe area padding to bottom fixed elements. Ensure CTA is above gesture area,Place CTAs that overlap with gesture bar causing accidental home triggers or hidden buttons,"<View style={{ paddingBottom: insets.bottom + 16 }}><Button>Checkout</Button></View>","<View style={{ position: 'absolute', bottom: 0 }}><Button>Checkout</Button></View> /* Overlaps gesture bar */",High
161,Mobile-SafeArea,Landscape Safe Areas,Cross-platform,Landscape orientation has safe areas on sides for notch and may have keyboard avoidance needs,Handle left/right safe area insets in landscape. Test both landscape orientations,Only handle portrait safe areas causing landscape layout issues with notch on side,"<View style={{ paddingLeft: insets.left, paddingRight: insets.right }}> /* Landscape safe */","<View style={{ paddingTop: insets.top }}> /* Ignores landscape side insets */",Medium
162,Mobile-SafeArea,Keyboard Avoidance,Cross-platform,Virtual keyboard can obscure input fields. Content must shift to keep focused field visible,Use KeyboardAvoidingView or android:windowSoftInputMode. Scroll focused input into view,Let keyboard cover input fields requiring user to dismiss keyboard to see what they typed,"<KeyboardAvoidingView behavior=""padding""><ScrollView><TextInput /></ScrollView></KeyboardAvoidingView>","<View><TextInput /></View> /* Keyboard covers input */",High
163,Mobile-Gesture,Swipe to Delete,iOS,iOS users expect swipe-to-reveal actions on list items particularly swipe-left for delete,Implement leading/trailing swipe actions. Use red for destructive and system colors for others,Use long-press menus only or Android-style checkbox selection for delete on iOS,"<SwipeableRow rightActions={[{ text: 'Delete', color: 'red', onPress: handleDelete }]}>","<TouchableOpacity onLongPress={showDeleteMenu}> /* iOS users expect swipe */",Medium
164,Mobile-Gesture,Pull to Refresh,Cross-platform,Pull-to-refresh is expected for refreshable content lists. Animation should indicate loading state,Implement RefreshControl with loading spinner. Place at list top. Provide haptic on activation,Omit pull-to-refresh on refreshable lists or place refresh button elsewhere confusing users,"<FlatList refreshControl={<RefreshControl refreshing={isLoading} onRefresh={handleRefresh} />}>","<FlatList /><Button onPress={handleRefresh}>Refresh</Button> /* Non-standard pattern */",Medium
165,Mobile-Gesture,Pinch to Zoom,Cross-platform,Image and map content should support pinch-to-zoom for detail inspection. Respect zoom limits,Enable pinch zoom with min/max scale limits. Support double-tap to zoom. Show zoom indicator,Disable zoom on zoomable content or allow infinite zoom causing performance issues,"<Image resizeMode=""contain"" style={{ transform: [{ scale: zoomScale }] }} /* With gesture handler */","<Image resizeMode=""cover"" /> /* No zoom capability on detail images */",Medium
166,Mobile-Gesture,Edge Swipe Conflicts,Cross-platform,Edge swipe gestures conflict with system navigation. Avoid custom edge gestures near screen edges,Keep custom gestures away from screen edges (20pt margin). Let system handle edge gestures,Implement custom edge swipes that conflict with iOS back gesture or Android edge navigation,"<GestureDetector hitSlop={{ left: -20 }}> /* Avoids edge conflict */","<GestureDetector hitSlop={{ left: 0 }}> /* Conflicts with system back gesture */",High
167,Mobile-Gesture,Haptic Feedback Patterns,Cross-platform,Haptic feedback confirms gestures and actions. Use appropriate feedback intensity for context,Use light haptic for selections medium for confirmations heavy for errors. Match system patterns,Overuse haptics or use wrong intensity creating annoying or confusing feedback,"UIImpactFeedbackGenerator(style: .light).impactOccurred() /* Selection */ UINotificationFeedbackGenerator().notificationOccurred(.success) /* Confirmation */","UIImpactFeedbackGenerator(style: .heavy).impactOccurred() /* For every tap - annoying */",Medium
168,Mobile-Gesture,Gesture Cancellation,Cross-platform,Users should be able to cancel gestures by moving finger away before release,Allow gesture cancellation by dragging outside hit area. Show visual feedback during drag,Commit action immediately on gesture start with no way to cancel accidental touches,"<Pressable onPressIn={highlight} onPressOut={unhighlight} onPress={performAction}> /* Can cancel by dragging out */","<TouchableWithoutFeedback onPressIn={performAction}> /* No cancel opportunity */",Medium
169,Mobile-Gesture,Long Press Timing,Cross-platform,Long press duration should balance quick access with accidental trigger prevention,Use 500ms for long press (iOS default). Show visual feedback during press buildup,Use very short (<300ms) or very long (>800ms) long press that triggers accidentally or feels unresponsive,"delayLongPress={500} /* Platform standard */","delayLongPress={200} /* Triggers accidentally during scroll */",Medium
170,Mobile-Gesture,Multi-Touch Gestures,Cross-platform,Complex multi-finger gestures should be optional with single-finger alternatives available,Provide single-finger alternatives for all multi-touch gestures. Multi-touch as shortcut only,Require multi-finger gestures for essential features excluding users with motor impairments,"/* Two-finger zoom OR double-tap zoom OR zoom buttons */ <ZoomControls showButtons={true} enablePinch={true} enableDoubleTap={true}>","<PinchableView> /* Only pinch zoom - excludes users who can't multi-touch */",High