Score: 91/100 · 2 errors · 65 warnings
Copy as prompt
Fix the following React Review diagnostics in my codebase.
## Errors (2)
1. [error] nextjs-no-side-effect-in-get-handler — apps/api/app/keep-alive/route.ts:6
GET handler has side effects (database.insert()) — use POST to prevent CSRF and unintended prefetch triggers
2. [error] require-reduced-motion — packages/ui/package.json:0
Project uses a motion library but has no prefers-reduced-motion handling — required for accessibility (WCAG 2.3.3)
## Warnings (65)
3. [warning] design-no-bold-heading — apps/web/app/(home)/components/app.tsx:53
font-bold on <h2> crushes counter shapes at display sizes — use font-semibold (600) or font-medium (500)
4. [warning] no-array-index-as-key — apps/web/app/(home)/components/app.tsx:86
Array index "index" used as key — causes bugs when list is reordered or filtered
5. [warning] design-no-redundant-size-axes — apps/web/app/(home)/components/header/auth-buttons.tsx:51
w-8 h-8 → use the shorthand size-8 (Tailwind v3.4+)
6. [warning] design-no-redundant-padding-axes — apps/web/app/(home)/components/header/auth-buttons.tsx:65
px-2 py-2 → use the shorthand p-2
7. [warning] design-no-redundant-size-axes — apps/web/app/(home)/components/header/auth-buttons.tsx:91
w-4 h-4 → use the shorthand size-4 (Tailwind v3.4+)
8. [warning] react-compiler-destructure-method — apps/web/app/(home)/components/header/auth-buttons.tsx:110
Destructure for clarity: `const { push } = useRouter()` then call `push(...)` directly — easier for React Compiler to memoize and clearer about which methods this component depends on
9. [warning] design-no-redundant-size-axes — apps/web/app/(home)/components/header/auth-buttons.tsx:118
w-4 h-4 → use the shorthand size-4 (Tailwind v3.4+)
10. [warning] nextjs-missing-metadata — apps/web/app/(home)/page.tsx:1
Page without metadata or generateMetadata export — hurts SEO
11. [warning] design-no-redundant-size-axes — apps/web/app/(home)/components/footer/index.tsx:36
w-7 h-7 → use the shorthand size-7 (Tailwind v3.4+)
12. [warning] nextjs-missing-metadata — apps/web/app/(unauthenticated)/login/email/page.tsx:1
Page without metadata or generateMetadata export — hurts SEO
13. [warning] design-no-bold-heading — apps/web/app/(authenticated)/dashboard/page.tsx:4
font-bold on <h1> crushes counter shapes at display sizes — use font-semibold (600) or font-medium (500)
14. [warning] design-no-redundant-size-axes — apps/web/app/(home)/components/header/mobile-auth-buttons.tsx:48
w-5 h-5 → use the shorthand size-5 (Tailwind v3.4+)
15. [warning] design-no-redundant-size-axes — apps/web/app/(home)/components/header/mobile-auth-buttons.tsx:64
w-5 h-5 → use the shorthand size-5 (Tailwind v3.4+)
16. [warning] design-no-redundant-size-axes — apps/web/app/(home)/components/header/mobile-auth-buttons.tsx:73
w-5 h-5 → use the shorthand size-5 (Tailwind v3.4+)
17. [warning] design-no-redundant-size-axes — apps/web/app/(home)/components/header/mobile-auth-buttons.tsx:80
w-5 h-5 → use the shorthand size-5 (Tailwind v3.4+)
18. [warning] react-compiler-destructure-method — apps/web/app/(home)/components/header/mobile-auth-buttons.tsx:96
Destructure for clarity: `const { push } = useRouter()` then call `push(...)` directly — easier for React Compiler to memoize and clearer about which methods this component depends on
19. [warning] design-no-bold-heading — apps/web/app/(home)/components/hero.tsx:9
font-bold on <h1> crushes counter shapes at display sizes — use font-semibold (600) or font-medium (500)
20. [warning] react-compiler-destructure-method — apps/web/app/(unauthenticated)/login/email/login-email.tsx:48
Destructure for clarity: `const { replace } = useRouter()` then call `replace(...)` directly — easier for React Compiler to memoize and clearer about which methods this component depends on
21. [warning] use-lazy-motion — apps/web/app/(home)/components/header/mobile-menu.tsx:10
Import "m" with LazyMotion instead of "motion" — saves ~30kb in bundle size
22. [warning] no-array-index-as-key — apps/web/app/(home)/components/header/mobile-menu.tsx:55
Array index "index" used as key — causes bugs when list is reordered or filtered
23. [warning] design-no-space-on-flex-children — apps/web/app/(home)/components/header/mobile-menu.tsx:86
space-y-4 on a flex/grid parent — use gap-y-4 instead. Per-sibling margins phantom-gap on conditional render and don't mirror in RTL
24. [warning] no-array-index-as-key — apps/web/app/(home)/components/header/mobile-menu.tsx:92
Array index "index" used as key — causes bugs when list is reordered or filtered
25. [warning] design-no-space-on-flex-children — apps/web/app/(home)/components/header/index.tsx:34
space-x-6 on a flex/grid parent — use gap-x-6 instead. Per-sibling margins phantom-gap on conditional render and don't mirror in RTL
26. [warning] design-no-space-on-flex-children — apps/web/app/(home)/components/header/index.tsx:35
space-x-2 on a flex/grid parent — use gap-x-2 instead. Per-sibling margins phantom-gap on conditional render and don't mirror in RTL
27. [warning] design-no-redundant-size-axes — apps/web/app/(home)/components/header/index.tsx:36
w-8 h-8 → use the shorthand size-8 (Tailwind v3.4+)
28. [warning] js-combine-iterations — apps/web/app/(home)/components/header/index.tsx:75
.filter().map() iterates the array twice — combine into a single loop with .reduce() or for...of
29. [warning] no-array-index-as-key — apps/web/app/(home)/components/header/index.tsx:79
Array index "index" used as key — causes bugs when list is reordered or filtered
30. [warning] design-no-redundant-size-axes — apps/web/app/(home)/components/header/index.tsx:83
w-8 h-8 → use the shorthand size-8 (Tailwind v3.4+)
31. [warning] design-no-redundant-size-axes — apps/web/app/(home)/components/header/index.tsx:85
w-4 h-4 → use the shorthand size-4 (Tailwind v3.4+)
32. [warning] js-combine-iterations — apps/web/app/(home)/components/header/index.tsx:105
.filter().map() iterates the array twice — combine into a single loop with .reduce() or for...of
33. [warning] no-array-index-as-key — apps/web/app/(home)/components/header/index.tsx:109
Array index "index" used as key — causes bugs when list is reordered or filtered
34. [warning] design-no-redundant-size-axes — apps/web/app/(home)/components/header/index.tsx:113
w-8 h-8 → use the shorthand size-8 (Tailwind v3.4+)
35. [warning] design-no-redundant-size-axes — apps/web/app/(home)/components/header/index.tsx:115
w-4 h-4 → use the shorthand size-4 (Tailwind v3.4+)
36. [warning] design-no-redundant-size-axes — apps/web/app/(unauthenticated)/components/footer.tsx:22
w-6 h-6 → use the shorthand size-6 (Tailwind v3.4+)
37. [warning] design-no-redundant-size-axes — apps/web/app/(unauthenticated)/components/footer.tsx:72
w-4 h-4 → use the shorthand size-4 (Tailwind v3.4+)
38. [warning] rendering-hydration-mismatch-time — apps/web/app/(unauthenticated)/components/footer.tsx:105
new Date() reachable from JSX renders differently on server vs client — wrap in useEffect+useState (client-only) or add suppressHydrationWarning to the parent if intentional
39. [warning] react-compiler-destructure-method — apps/web/app/(unauthenticated)/signup/signup.tsx:52
Destructure for clarity: `const { replace } = useRouter()` then call `replace(...)` directly — easier for React Compiler to memoize and clearer about which methods this component depends on
40. [warning] nextjs-missing-metadata — apps/web/app/(unauthenticated)/signup/page.tsx:1
Page without metadata or generateMetadata export — hurts SEO
41. [warning] nextjs-missing-metadata — apps/web/app/(unauthenticated)/login/page.tsx:1
Page without metadata or generateMetadata export — hurts SEO
42. [warning] design-no-redundant-size-axes — packages/ui/components/ui/menubar.tsx:238
w-4 h-4 → use the shorthand size-4 (Tailwind v3.4+)
43. [warning] no-react19-deprecated-apis — packages/ui/components/ui/carousel.tsx:36
useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`
44. [warning] no-prop-callback-in-effect — packages/ui/components/ui/carousel.tsx:93
useEffect calls prop callback "setApi" with local state in deps — this is the "lift state via callback" anti-pattern; lift state into a shared Provider so both sides read the same source
45. [warning] advanced-event-handler-refs — packages/ui/components/ui/carousel.tsx:96
useEffect re-subscribes a "onSelect" listener every time the handler identity changes — store the handler in a ref and have the listener read `handlerRef.current()`, then drop it from the deps
46. [warning] no-react19-deprecated-apis — packages/ui/components/ui/input-otp.tsx:46
useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`
47. [warning] client-passive-event-listeners — packages/ui/hooks/use-scroll.ts:10
"scroll" listener without { passive: true } — blocks scrolling performance. Only add { passive: true } if the handler does NOT call event.preventDefault() (passive listeners silently ignore preventDefault())
48. [warning] no-react19-deprecated-apis — packages/ui/components/ui/form.tsx:46
useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`
49. [warning] no-react19-deprecated-apis — packages/ui/components/ui/form.tsx:47
useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`
50. [warning] no-danger — packages/ui/components/ui/chart.tsx:83
Do not use `dangerouslySetInnerHTML` prop
51. [warning] prefer-dynamic-import — packages/ui/components/ui/chart.tsx:4
"recharts" is a heavy library — use React.lazy() or next/dynamic for code splitting
52. [warning] no-react19-deprecated-apis — packages/ui/components/ui/chart.tsx:28
useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`
53. [warning] rerender-memo-before-early-return — packages/ui/components/ui/chart.tsx:131
useMemo returning JSX runs before an early return — extract the JSX into a memoized child component so the parent bails out before the subtree renders
54. [warning] design-no-redundant-size-axes — packages/ui/components/ui/chart.tsx:293
w-2 h-2 → use the shorthand size-2 (Tailwind v3.4+)
55. [warning] rerender-state-only-in-handlers — packages/ui/components/theme-toggle.tsx:10
useState "mounted" is updated but never read in the component's return — use useRef so updates don't trigger re-renders
56. [warning] rendering-hydration-no-flicker — packages/ui/components/theme-toggle.tsx:13
useEffect(setState, []) on mount causes a flash — consider useSyncExternalStore or suppressHydrationWarning
57. [warning] design-no-redundant-size-axes — packages/ui/components/theme-toggle.tsx:48
w-6 h-6 → use the shorthand size-6 (Tailwind v3.4+)
58. [warning] no-array-index-as-key — packages/ui/components/ui/slider.tsx:55
Array index "index" used as key — causes bugs when list is reordered or filtered
59. [warning] design-no-redundant-size-axes — packages/ui/components/status.tsx:61
w-2 h-2 → use the shorthand size-2 (Tailwind v3.4+)
60. [warning] no-react19-deprecated-apis — packages/ui/components/ui/toggle-group.tsx:51
useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`
61. [warning] use-lazy-motion — packages/ui/components/password-input.tsx:4
Import "m" with LazyMotion instead of "motion" — saves ~30kb in bundle size
62. [warning] no-array-index-as-key — packages/ui/components/password-input.tsx:156
Array index "index" used as key — causes bugs when list is reordered or filtered
63. [warning] no-react19-deprecated-apis — packages/ui/components/ui/sidebar.tsx:48
useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`
64. [warning] no-derived-useState — packages/ui/components/ui/sidebar.tsx:74
useState initialized from prop "defaultOpen" — if this value should stay in sync with the prop, derive it during render instead
65. [warning] no-usememo-simple-expression — packages/ui/components/ui/sidebar.tsx:610
useMemo wrapping a trivially cheap expression — memo overhead exceeds the computation
66. [warning] no-redundant-roles — packages/ui/components/ui/pagination.tsx:14
The `nav` element has an implicit role of `navigation`. Defining this explicitly is redundant and should be avoided.
67. [warning] design-no-redundant-size-axes — packages/ui/components/ui/navigation-menu.tsx:153
w-2 h-2 → use the shorthand size-2 (Tailwind v3.4+)
❌ Errors (2)
nextjs-no-side-effect-in-get-handler
GET handler has side effects (database.insert()) — use POST to prevent CSRF and unintended prefetch triggers
Move the side effect to a POST handler and use a <form> or fetch with method POST — GET requests can be triggered by prefetching and are vulnerable to CSRF
apps/api/app/keep-alive/route.ts:6
require-reduced-motion
Project uses a motion library but has no prefers-reduced-motion handling — required for accessibility (WCAG 2.3.3)
Add useReducedMotion() from your animation library, or a @media (prefers-reduced-motion: reduce) CSS query
packages/ui/package.json:0
⚠️ Warnings (65)
design-no-redundant-size-axes
w-8 h-8 → use the shorthand size-8 (Tailwind v3.4+)
Collapse w-N h-N to size-N (Tailwind v3.4+) when both axes match
apps/web/app/(home)/components/header/auth-buttons.tsx:51
apps/web/app/(home)/components/header/auth-buttons.tsx:91
apps/web/app/(home)/components/header/auth-buttons.tsx:118
apps/web/app/(home)/components/footer/index.tsx:36
apps/web/app/(home)/components/header/mobile-auth-buttons.tsx:48
apps/web/app/(home)/components/header/mobile-auth-buttons.tsx:64
apps/web/app/(home)/components/header/mobile-auth-buttons.tsx:73
apps/web/app/(home)/components/header/mobile-auth-buttons.tsx:80
apps/web/app/(home)/components/header/index.tsx:36
apps/web/app/(home)/components/header/index.tsx:83
apps/web/app/(home)/components/header/index.tsx:85
apps/web/app/(home)/components/header/index.tsx:113
apps/web/app/(home)/components/header/index.tsx:115
apps/web/app/(unauthenticated)/components/footer.tsx:22
apps/web/app/(unauthenticated)/components/footer.tsx:72
packages/ui/components/ui/menubar.tsx:238
packages/ui/components/ui/chart.tsx:293
packages/ui/components/theme-toggle.tsx:48
packages/ui/components/status.tsx:61
packages/ui/components/ui/navigation-menu.tsx:153
no-array-index-as-key
Array index "index" used as key — causes bugs when list is reordered or filtered
Use a stable unique identifier: key={item.id} or key={item.slug} — index keys break on reorder/filter
apps/web/app/(home)/components/app.tsx:86
apps/web/app/(home)/components/header/mobile-menu.tsx:55
apps/web/app/(home)/components/header/mobile-menu.tsx:92
apps/web/app/(home)/components/header/index.tsx:79
apps/web/app/(home)/components/header/index.tsx:109
packages/ui/components/ui/slider.tsx:55
packages/ui/components/password-input.tsx:156
no-react19-deprecated-apis
useContext is superseded by use() on React 19+ — use() reads context conditionally inside hooks, branches, and loops; switch to import { use } from 'react'
Pass ref as a regular prop on function components — forwardRef is no longer needed in React 19+. Replace useContext(X) with use(X) for branch-aware context reads. Only enabled on projects detected as React 19+.
packages/ui/components/ui/carousel.tsx:36
packages/ui/components/ui/input-otp.tsx:46
packages/ui/components/ui/form.tsx:46
packages/ui/components/ui/form.tsx:47
packages/ui/components/ui/chart.tsx:28
packages/ui/components/ui/toggle-group.tsx:51
packages/ui/components/ui/sidebar.tsx:48
react-compiler-destructure-method
Destructure for clarity: const { push } = useRouter() then call push(...) directly — easier for React Compiler to memoize and clearer about which methods this component depends on
Destructure the method up front: const { push } = useRouter() then call push(...) directly — clearer dependency graph and easier for React Compiler to memoize
apps/web/app/(home)/components/header/auth-buttons.tsx:110
apps/web/app/(home)/components/header/mobile-auth-buttons.tsx:96
apps/web/app/(unauthenticated)/login/email/login-email.tsx:48
apps/web/app/(unauthenticated)/signup/signup.tsx:52
nextjs-missing-metadata
Page without metadata or generateMetadata export — hurts SEO
Add export const metadata = { title: '...', description: '...' } or export async function generateMetadata()
apps/web/app/(home)/page.tsx:1
apps/web/app/(unauthenticated)/login/email/page.tsx:1
apps/web/app/(unauthenticated)/signup/page.tsx:1
apps/web/app/(unauthenticated)/login/page.tsx:1
design-no-bold-heading
font-bold on <h2> crushes counter shapes at display sizes — use font-semibold (600) or font-medium (500)
Use font-semibold (600) or font-medium (500) on headings — 700+ crushes letter counter shapes at display sizes
apps/web/app/(home)/components/app.tsx:53
apps/web/app/(authenticated)/dashboard/page.tsx:4
apps/web/app/(home)/components/hero.tsx:9
design-no-space-on-flex-children
space-y-4 on a flex/grid parent — use gap-y-4 instead. Per-sibling margins phantom-gap on conditional render and don't mirror in RTL
Use gap-* on the flex/grid parent. space-x-* / space-y-* produce phantom gaps when a sibling is conditionally rendered, lose vertical spacing on wrapped lines, and don't mirror in RTL
apps/web/app/(home)/components/header/mobile-menu.tsx:86
apps/web/app/(home)/components/header/index.tsx:34
apps/web/app/(home)/components/header/index.tsx:35
use-lazy-motion
Import "m" with LazyMotion instead of "motion" — saves ~30kb in bundle size
Use import { LazyMotion, m } from "framer-motion" with domAnimation features — saves ~30kb
apps/web/app/(home)/components/header/mobile-menu.tsx:10
packages/ui/components/password-input.tsx:4
js-combine-iterations
.filter().map() iterates the array twice — combine into a single loop with .reduce() or for...of
Combine .map().filter() (or similar chains) into a single pass with .reduce() or a for...of loop to avoid iterating the array twice
apps/web/app/(home)/components/header/index.tsx:75
apps/web/app/(home)/components/header/index.tsx:105
design-no-redundant-padding-axes
px-2 py-2 → use the shorthand p-2
Collapse px-N py-N to p-N when both axes match. Keep them split only when one axis varies at a breakpoint (py-2 md:py-3)
apps/web/app/(home)/components/header/auth-buttons.tsx:65
rendering-hydration-mismatch-time
new Date() reachable from JSX renders differently on server vs client — wrap in useEffect+useState (client-only) or add suppressHydrationWarning to the parent if intentional
Wrap dynamic time/random values in useEffect+useState (client-only) or add suppressHydrationWarning to the parent if intentional
apps/web/app/(unauthenticated)/components/footer.tsx:105
no-prop-callback-in-effect
useEffect calls prop callback "setApi" with local state in deps — this is the "lift state via callback" anti-pattern; lift state into a shared Provider so both sides read the same source
Lift the shared state into a Provider so both sides read the same source — no useEffect-driven sync needed
packages/ui/components/ui/carousel.tsx:93
advanced-event-handler-refs
useEffect re-subscribes a "onSelect" listener every time the handler identity changes — store the handler in a ref and have the listener read handlerRef.current(), then drop it from the deps
Store the handler in a ref and have the listener read handlerRef.current() — the subscription stays put while the latest handler is always called
packages/ui/components/ui/carousel.tsx:96
client-passive-event-listeners
"scroll" listener without { passive: true } — blocks scrolling performance. Only add { passive: true } if the handler does NOT call event.preventDefault() (passive listeners silently ignore preventDefault())
Add { passive: true } as the third argument: addEventListener('scroll', handler, { passive: true }). Only do this if the handler does NOT call event.preventDefault() — passive listeners silently ignore preventDefault(), which breaks features like pull-to-refresh suppression, custom gestures, and nested-scroll containment.
packages/ui/hooks/use-scroll.ts:10
no-danger
Do not use dangerouslySetInnerHTML prop
dangerouslySetInnerHTML is a way to inject HTML into your React component. This is dangerous because it can easily lead to XSS vulnerabilities.
packages/ui/components/ui/chart.tsx:83
prefer-dynamic-import
"recharts" is a heavy library — use React.lazy() or next/dynamic for code splitting
Use const Component = dynamic(() => import('library'), { ssr: false }) from next/dynamic or React.lazy()
packages/ui/components/ui/chart.tsx:4
rerender-memo-before-early-return
useMemo returning JSX runs before an early return — extract the JSX into a memoized child component so the parent bails out before the subtree renders
Extract the JSX into a memoized child component so the parent's early return short-circuits before the child renders
packages/ui/components/ui/chart.tsx:131
rerender-state-only-in-handlers
useState "mounted" is updated but never read in the component's return — use useRef so updates don't trigger re-renders
Replace useState with useRef when the value is only mutated and never read in render — ref.current = ... updates without re-rendering the component
packages/ui/components/theme-toggle.tsx:10
rendering-hydration-no-flicker
useEffect(setState, []) on mount causes a flash — consider useSyncExternalStore or suppressHydrationWarning
Use useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) or add suppressHydrationWarning to the element
packages/ui/components/theme-toggle.tsx:13
no-derived-useState
useState initialized from prop "defaultOpen" — if this value should stay in sync with the prop, derive it during render instead
Remove useState and compute the value inline: const value = transform(propName)
packages/ui/components/ui/sidebar.tsx:74
no-usememo-simple-expression
useMemo wrapping a trivially cheap expression — memo overhead exceeds the computation
Remove useMemo — property access, math, and ternaries are already cheap without memoization
packages/ui/components/ui/sidebar.tsx:610
no-redundant-roles
The nav element has an implicit role of navigation. Defining this explicitly is redundant and should be avoided.
Remove the redundant role navigation from the element nav.
packages/ui/components/ui/pagination.tsx:14
Last scored May 13, 2026 at 7:32 PM UTC. Maintained by React Review.
Score: 91/100 · 2 errors · 65 warnings
Copy as prompt
❌ Errors (2)
nextjs-no-side-effect-in-get-handlerGET handler has side effects (database.insert()) — use POST to prevent CSRF and unintended prefetch triggers
apps/api/app/keep-alive/route.ts:6require-reduced-motionProject uses a motion library but has no prefers-reduced-motion handling — required for accessibility (WCAG 2.3.3)
packages/ui/package.json:0design-no-redundant-size-axesw-8 h-8 → use the shorthand size-8 (Tailwind v3.4+)
apps/web/app/(home)/components/header/auth-buttons.tsx:51apps/web/app/(home)/components/header/auth-buttons.tsx:91apps/web/app/(home)/components/header/auth-buttons.tsx:118apps/web/app/(home)/components/footer/index.tsx:36apps/web/app/(home)/components/header/mobile-auth-buttons.tsx:48apps/web/app/(home)/components/header/mobile-auth-buttons.tsx:64apps/web/app/(home)/components/header/mobile-auth-buttons.tsx:73apps/web/app/(home)/components/header/mobile-auth-buttons.tsx:80apps/web/app/(home)/components/header/index.tsx:36apps/web/app/(home)/components/header/index.tsx:83apps/web/app/(home)/components/header/index.tsx:85apps/web/app/(home)/components/header/index.tsx:113apps/web/app/(home)/components/header/index.tsx:115apps/web/app/(unauthenticated)/components/footer.tsx:22apps/web/app/(unauthenticated)/components/footer.tsx:72packages/ui/components/ui/menubar.tsx:238packages/ui/components/ui/chart.tsx:293packages/ui/components/theme-toggle.tsx:48packages/ui/components/status.tsx:61packages/ui/components/ui/navigation-menu.tsx:153no-array-index-as-keyArray index "index" used as key — causes bugs when list is reordered or filtered
apps/web/app/(home)/components/app.tsx:86apps/web/app/(home)/components/header/mobile-menu.tsx:55apps/web/app/(home)/components/header/mobile-menu.tsx:92apps/web/app/(home)/components/header/index.tsx:79apps/web/app/(home)/components/header/index.tsx:109packages/ui/components/ui/slider.tsx:55packages/ui/components/password-input.tsx:156no-react19-deprecated-apisuseContext is superseded by
use()on React 19+ —use()reads context conditionally inside hooks, branches, and loops; switch toimport { use } from 'react'packages/ui/components/ui/carousel.tsx:36packages/ui/components/ui/input-otp.tsx:46packages/ui/components/ui/form.tsx:46packages/ui/components/ui/form.tsx:47packages/ui/components/ui/chart.tsx:28packages/ui/components/ui/toggle-group.tsx:51packages/ui/components/ui/sidebar.tsx:48react-compiler-destructure-methodDestructure for clarity:
const { push } = useRouter()then callpush(...)directly — easier for React Compiler to memoize and clearer about which methods this component depends onapps/web/app/(home)/components/header/auth-buttons.tsx:110apps/web/app/(home)/components/header/mobile-auth-buttons.tsx:96apps/web/app/(unauthenticated)/login/email/login-email.tsx:48apps/web/app/(unauthenticated)/signup/signup.tsx:52nextjs-missing-metadataPage without metadata or generateMetadata export — hurts SEO
apps/web/app/(home)/page.tsx:1apps/web/app/(unauthenticated)/login/email/page.tsx:1apps/web/app/(unauthenticated)/signup/page.tsx:1apps/web/app/(unauthenticated)/login/page.tsx:1design-no-bold-headingfont-bold on <h2> crushes counter shapes at display sizes — use font-semibold (600) or font-medium (500)
apps/web/app/(home)/components/app.tsx:53apps/web/app/(authenticated)/dashboard/page.tsx:4apps/web/app/(home)/components/hero.tsx:9design-no-space-on-flex-childrenspace-y-4 on a flex/grid parent — use gap-y-4 instead. Per-sibling margins phantom-gap on conditional render and don't mirror in RTL
apps/web/app/(home)/components/header/mobile-menu.tsx:86apps/web/app/(home)/components/header/index.tsx:34apps/web/app/(home)/components/header/index.tsx:35use-lazy-motionImport "m" with LazyMotion instead of "motion" — saves ~30kb in bundle size
apps/web/app/(home)/components/header/mobile-menu.tsx:10packages/ui/components/password-input.tsx:4js-combine-iterations.filter().map() iterates the array twice — combine into a single loop with .reduce() or for...of
apps/web/app/(home)/components/header/index.tsx:75apps/web/app/(home)/components/header/index.tsx:105design-no-redundant-padding-axespx-2 py-2 → use the shorthand p-2
apps/web/app/(home)/components/header/auth-buttons.tsx:65rendering-hydration-mismatch-timenew Date() reachable from JSX renders differently on server vs client — wrap in useEffect+useState (client-only) or add suppressHydrationWarning to the parent if intentional
apps/web/app/(unauthenticated)/components/footer.tsx:105no-prop-callback-in-effectuseEffect calls prop callback "setApi" with local state in deps — this is the "lift state via callback" anti-pattern; lift state into a shared Provider so both sides read the same source
packages/ui/components/ui/carousel.tsx:93advanced-event-handler-refsuseEffect re-subscribes a "onSelect" listener every time the handler identity changes — store the handler in a ref and have the listener read
handlerRef.current(), then drop it from the depspackages/ui/components/ui/carousel.tsx:96client-passive-event-listeners"scroll" listener without { passive: true } — blocks scrolling performance. Only add { passive: true } if the handler does NOT call event.preventDefault() (passive listeners silently ignore preventDefault())
packages/ui/hooks/use-scroll.ts:10no-dangerDo not use
dangerouslySetInnerHTMLproppackages/ui/components/ui/chart.tsx:83prefer-dynamic-import"recharts" is a heavy library — use React.lazy() or next/dynamic for code splitting
packages/ui/components/ui/chart.tsx:4rerender-memo-before-early-returnuseMemo returning JSX runs before an early return — extract the JSX into a memoized child component so the parent bails out before the subtree renders
packages/ui/components/ui/chart.tsx:131rerender-state-only-in-handlersuseState "mounted" is updated but never read in the component's return — use useRef so updates don't trigger re-renders
packages/ui/components/theme-toggle.tsx:10rendering-hydration-no-flickeruseEffect(setState, []) on mount causes a flash — consider useSyncExternalStore or suppressHydrationWarning
packages/ui/components/theme-toggle.tsx:13no-derived-useStateuseState initialized from prop "defaultOpen" — if this value should stay in sync with the prop, derive it during render instead
packages/ui/components/ui/sidebar.tsx:74no-usememo-simple-expressionuseMemo wrapping a trivially cheap expression — memo overhead exceeds the computation
packages/ui/components/ui/sidebar.tsx:610no-redundant-rolesThe
navelement has an implicit role ofnavigation. Defining this explicitly is redundant and should be avoided.packages/ui/components/ui/pagination.tsx:14Last scored May 13, 2026 at 7:32 PM UTC. Maintained by React Review.