Audit performed against four guideline sets:
- Vercel React Best Practices (performance, bundle, re-render optimization)
- Frontend Design (aesthetics, typography, visual identity)
- Web Interface Guidelines (accessibility, forms, focus, animation)
- UI Skills (Tailwind conventions, component primitives, interaction patterns)
Severity: CRITICAL > HIGH > MEDIUM > LOW
src/App.tsx — All useState calls now use lazy initializer functions to avoid running I/O (cookies, URLSearchParams) on every render.
src/hooks/useDateDistance.ts — All imports changed from date-fns barrel to direct subpath imports (e.g., date-fns/differenceInYears).
App.tsx correctly uses functional updaters (setTheme(t => ...), setUseCustomFrom(v => ...)). No issue.
Client-only Vite SPA with no data fetching. Sections 1 (waterfalls), 3 (server-side), and 4 (client-side data fetching) are not applicable.
index.html, src/index.css
Inter is functional and universally readable. The app's identity comes from its utility, not its typography. Keeping Inter as a deliberate choice for a tool-first interface.
src/App.tsx, src/index.css
The indigo accent is used sparingly and pairs well with the dark glass-morphism aesthetic. The palette is cohesive and serves the tool's purpose.
Standard centered layout is the correct choice for a single-purpose utility tool. Novelty layouts would hurt usability.
Background gradient blobs provide sufficient atmosphere. Additional texture would increase complexity without meaningful benefit for a calculator tool.
src/App.tsx — Hero input uses <label htmlFor="target-date">. FromDateToggle.tsx from-date input has aria-label="Custom reference date".
All interactive elements now use focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500/50.
ThemeToggle.tsx, FromDateToggle.tsx toggle buttons, and footer Copy/Share buttons all have focus-visible ring states.
FromDateToggle.tsx — Today/Custom buttons now have aria-pressed attributes.
src/main.tsx — App is wrapped in <MotionConfig reducedMotion="user"> to respect OS-level motion preferences globally.
src/components/ResultDisplay.tsx — Secondary stats line uses tabular-nums for stable number alignment.
src/App.tsx — <h1> uses text-balance. ResultDisplay.tsx — Primary result uses text-balance.
src/App.tsx — <img> now has width={32} height={32} HTML attributes.
src/components/DateInput.tsx — All date inputs have autoComplete="off".
src/components/FromDateToggle.tsx — Now animates only opacity instead of width.
src/App.tsx — Changed to min-h-dvh for proper mobile viewport handling.
The project uses framer-motion (Framer Motion 12) which is the currently installed package. Migrating to motion is a separate dependency swap and does not affect functionality or performance.
The project uses minimal conditional class logic (ternary expressions). Adding clsx + tailwind-merge would increase bundle size for minimal benefit given the current component count.
src/components/ThemeToggle.tsx — Uses size-10 instead of w-10 h-10.
-z-10 is a Tailwind CSS default utility (not an arbitrary value) and is used once for the background layer. This is acceptable.
The two-button toggle in FromDateToggle.tsx uses plain <button> elements with proper aria-pressed attributes. For this simple toggle pattern, native buttons with ARIA are sufficient.
blur-[100px] on background gradient blobs is not animated and only applied to two small decorative elements. Performance impact is negligible on modern browsers.
| Category | Total | Fixed | Accepted / N/A |
|---|---|---|---|
| React Best Practices | 4 | 2 | 2 |
| Frontend Design | 4 | 0 | 4 |
| Web Interface Guidelines | 9 | 9 | 0 |
| UI Skills | 8 | 3 | 5 |
| Total | 25 | 14 | 11 |
All HIGH (7/7) and actionable MEDIUM (5/5) findings have been fixed. The remaining 11 items are either not applicable, already correct, or accepted as intentional design/architectural decisions.