aidenybai / aidenybai/react-grab
React Review Audit
- Lenguaje dominante
- TypeScript
- Estrellas
- 7.6k
- Forks
- 340
- Merge medio
- 5 h 12 min
- PR fusionados (30 d)
- 6
Descripción
⚠️ 252 warnings
Copy as prompt
```text
Fix the following React Review diagnostics in my codebase.
## Warnings (252)
1. [warning] design-no-bold-heading — apps/e2e-app/src/perf-grid.tsx:44
font-bold on
crushes counter shapes at display sizes — use font-semibold (600) or font-medium (500)
2. [warning] design-no-bold-heading — apps/e2e-app/src/App.tsx:30
font-bold on
crushes counter shapes at display sizes — use font-semibold (600) or font-medium (500)
3. [warning] button-has-type — apps/e2e-app/src/App.tsx:59
`` elements must have an explicit `type` attribute.
4. [warning] design-no-bold-heading — apps/e2e-app/src/App.tsx:77
font-bold on
crushes counter shapes at display sizes — use font-semibold (600) or font-medium (500)
5. [warning] control-has-associated-label — apps/e2e-app/src/App.tsx:83
A control must be associated with a text label — add visible text, `aria-label`, or `aria-labelledby`.
6. [warning] control-has-associated-label — apps/e2e-app/src/App.tsx:97
A control must be associated with a text label — add visible text, `aria-label`, or `aria-labelledby`.
7. [warning] design-no-vague-button-label — apps/e2e-app/src/App.tsx:107
Vague button label "Submit" — name the action ("Save changes", "Send invite", "Delete account") so screen readers and hesitant users know what happens
8. [warning] design-no-bold-heading — apps/e2e-app/src/App.tsx:136
font-bold on
crushes counter shapes at display sizes — use font-semibold (600) or font-medium (500)
9. [warning] design-no-bold-heading — apps/e2e-app/src/App.tsx:175
font-bold on
crushes counter shapes at display sizes — use font-semibold (600) or font-medium (500)
10. [warning] button-has-type — apps/e2e-app/src/App.tsx:184
`` elements must have an explicit `type` attribute.
11. [warning] button-has-type — apps/e2e-app/src/App.tsx:194
`` elements must have an explicit `type` attribute.
12. [warning] design-no-bold-heading — apps/e2e-app/src/App.tsx:239
font-bold on
crushes counter shapes at display sizes — use font-semibold (600) or font-medium (500)
13. [warning] anchor-is-valid — apps/e2e-app/src/App.tsx:253
`` element has invalid `href` (`#`, `javascript:`, or empty) — provide a real destination.
14. [warning] button-has-type — apps/e2e-app/src/App.tsx:256
`` elements must have an explicit `type` attribute.
15. [warning] design-no-redundant-size-axes — apps/e2e-app/src/App.tsx:309
w-12 h-12 → use the shorthand size-12 (Tailwind v3.4+)
16. [warning] design-no-bold-heading — apps/e2e-app/src/App.tsx:333
font-bold on
crushes counter shapes at display sizes — use font-semibold (600) or font-medium (500)
17. [warning] design-no-redundant-size-axes — apps/e2e-app/src/App.tsx:336
w-8 h-8 → use the shorthand size-8 (Tailwind v3.4+)
18. [warning] design-no-redundant-size-axes — apps/e2e-app/src/App.tsx:339
w-8 h-8 → use the shorthand size-8 (Tailwind v3.4+)
19. [warning] no-inline-bounce-easing — apps/e2e-app/src/App.tsx:340
animate-bounce feels dated and tacky — use a subtle ease-out transform for natural deceleration
20. [warning] design-no-redundant-size-axes — apps/e2e-app/src/App.tsx:340
w-8 h-8 → use the shorthand size-8 (Tailwind v3.4+)
21. [warning] design-no-bold-heading — apps/e2e-app/src/App.tsx:349
font-bold on
crushes counter shapes at display sizes — use font-semibold (600) or font-medium (500)
22. [warning] design-no-redundant-size-axes — apps/e2e-app/src/App.tsx:351
w-0 h-0 → use the shorthand size-0 (Tailwind v3.4+)
23. [warning] design-no-bold-heading — apps/e2e-app/src/App.tsx:392
font-bold on
crushes counter shapes at display sizes — use font-semibold (600) or font-medium (500)
24. [warning] button-has-type — apps/e2e-app/src/App.tsx:394
`` elements must have an explicit `type` attribute.
25. [warning] button-has-type — apps/e2e-app/src/App.tsx:406
`` elements must have an explicit `type` attribute.
26. [warning] button-has-type — apps/e2e-app/src/App.tsx:412
`` elements must have an explicit `type` attribute.
27. [warning] button-has-type — apps/e2e-app/src/App.tsx:418
`` elements must have an explicit `type` attribute.
28. [warning] no-cascading-set-state — apps/e2e-app/src/App.tsx:437
3 setState calls in a single useEffect — consider using useReducer or deriving state
29. [warning] design-no-bold-heading — apps/e2e-app/src/App.tsx:461
font-bold on
crushes counter shapes at display sizes — use font-semibold (600) or font-medium (500)
30. [warning] button-has-type — apps/e2e-app/src/App.tsx:462
`` elements must have an explicit `type` attribute.
31. [warning] design-no-bold-heading — apps/e2e-app/src/App.tsx:481
font-bold on
crushes counter shapes at display sizes — use font-semibold (600) or font-medium (500)
32. [warning] button-has-type — apps/e2e-app/src/App.tsx:485
`` elements must have an explicit `type` attribute.
33. [warning] button-has-type — apps/e2e-app/src/App.tsx:491
`` elements must have an explicit `type` attribute.
34. [warning] design-no-bold-heading — apps/e2e-app/src/App.tsx:546
font-bold on
crushes counter shapes at display sizes — use font-semibold (600) or font-medium (500)
35. [warning] button-has-type — apps/e2e-app/src/App.tsx:549
`` elements must have an explicit `type` attribute.
36. [warning] design-no-bold-heading — apps/e2e-app/src/App.tsx:567
font-bold on
crushes counter shapes at display sizes — use font-semibold (600) or font-medium (500)
37. [warning] button-has-type — apps/e2e-app/src/App.tsx:569
`` elements must have an explicit `type` attribute.
38. [warning] button-has-type — apps/e2e-app/src/App.tsx:575
`` elements must have an explicit `type` attribute.
39. [warning] design-no-bold-heading — apps/e2e-app/src/App.tsx:595
font-bold on
crushes counter shapes at display sizes — use font-semibold (600) or font-medium (500)
40. [warning] button-has-type — apps/e2e-app/src/App.tsx:596
`` elements must have an explicit `type` attribute.
41. [warning] design-no-bold-heading — apps/e2e-app/src/App.tsx:645
font-bold on
crushes counter shapes at display sizes — use font-semibold (600) or font-medium (500)
42. [warning] server-fetch-without-revalidate — apps/website/app/api/og/route.tsx:13
fetch(url) in a Server Component / route handler defaults to forever-caching — pass { next: { revalidate: } } / { next: { tags: [...] } } / { cache: "no-store" } so stale data doesn't quietly persist
43. [warning] server-fetch-without-revalidate — apps/website/app/api/og/route.tsx:22
fetch(url) in a Server Component / route handler defaults to forever-caching — pass { next: { revalidate: } } / { next: { tags: [...] } } / { cache: "no-store" } so stale data doesn't quietly persist
44. [warning] rendering-svg-precision — apps/website/app/api/og/route.tsx:34
SVG d attribute uses 4+ decimal precision — truncate to 1–2 decimals to shrink markup with no visible difference
45. [warning] server-sequential-independent-await — apps/website/app/api/og/route.tsx:69
Sequential `await` without a data dependency on the previous result — wrap the independent calls in `Promise.all([...])` so they race instead of waterfalling
46. [warning] no-inline-exhaustive-style — apps/website/app/api/og/route.tsx:73
8 inline style properties — extract to a CSS class, CSS module, or styled component for maintainability and reuse
47. [warning] no-array-index-key — apps/website/app/changelog/page.tsx:90
Array index in `key` doesn't uniquely identify the element — re-renders may use stale state.
48. [warning] nextjs-no-native-script — apps/website/app/layout.tsx:65
Use next/script instead of <script> — provides loading strategy optimization and deferred loading
49. [warning] nextjs-missing-metadata — apps/website/app/page.tsx:1
Page without metadata or generateMetadata export — hurts SEO
50. [warning] no-danger — apps/website/components/icons/icon-vite.tsx:10
Do not use `dangerouslySetInnerHTML` — it injects raw HTML and is a common XSS vector.
51. [warning] no-danger — apps/website/components/icons/icon-tanstack.tsx:10
Do not use `dangerouslySetInnerHTML` — it injects raw HTML and is a common XSS vector.
52. [warning] prefer-useReducer — apps/website/components/install-tabs.tsx:243
Component "InstallTabs" has 6 useState calls — consider useReducer for related state
53. [warning] no-initialize-state — apps/website/components/install-tabs.tsx:264
Avoid initializing state in an effect. Instead, initialize "isMobile"'s `useState()` with "detectMobile()". For SSR hydration, prefer `useSyncExternalStore()`.
54. [warning] rendering-hydration-no-flicker — apps/website/components/install-tabs.tsx:262
useEffect(setState, []) on mount causes a flash — consider useSyncExternalStore or suppressHydrationWarning
55. [warning] no-derived-state — apps/website/components/install-tabs.tsx:290
Avoid storing derived state. "highlightedCodes" is only set here, and thus could be computed directly during render.
56. [warning] no-chain-state-updates — apps/website/components/install-tabs.tsx:294
Avoid chaining state changes. When possible, update all relevant state simultaneously.
57. [warning] no-derived-state-effect — apps/website/components/install-tabs.tsx:293
State reset in useEffect — use a key prop to reset component state when props change
58. [warning] no-danger — apps/website/components/install-tabs.tsx:468
Do not use `dangerouslySetInnerHTML` — it injects raw HTML and is a common XSS vector.
59. [warning] no-danger — apps/website/components/install-tabs.tsx:492
Do not use `dangerouslySetInnerHTML` — it injects raw HTML and is a common XSS vector.
60. [warning] nextjs-no-a-element — apps/website/components/install-tabs.tsx:512
Use next/link instead of <a> for internal links — enables client-side navigation and prefetching
61. [warning] nextjs-no-a-element — apps/website/components/demo-footer.tsx:32
Use next/link instead of <a> for internal links — enables client-side navigation and prefetching
62. [warning] use-lazy-motion — apps/website/components/blocks/streaming-text.tsx:3
Import "m" with LazyMotion instead of "motion" — saves ~30kb in bundle size
63. [warning] no-array-index-key — apps/website/components/blocks/streaming-text.tsx:77
Array index in `key` doesn't uniquely identify the element — re-renders may use stale state.
64. [warning] no-array-index-as-key — apps/website/components/blocks/streaming-text.tsx:77
Array index "index" used as key — causes bugs when list is reordered or filtered
65. [warning] no-array-index-key — apps/website/components/blocks/streaming-text.tsx:86
Array index in `key` doesn't uniquely identify the element — re-renders may use stale state.
66. [warning] no-array-index-as-key — apps/website/components/blocks/streaming-text.tsx:86
Array index "index" used as key — causes bugs when list is reordered or filtered
67. [warning] no-array-index-key — apps/website/components/blocks/streaming-text.tsx:91
Array index in `key` doesn't uniquely identify the element — re-renders may use stale state.
68. [warning] no-array-index-as-key — apps/website/components/blocks/streaming-text.tsx:91
Array index "index" used as key — causes bugs when list is reordered or filtered
69. [warning] use-lazy-motion — apps/website/components/ui/collapsible.tsx:4
Import "m" with LazyMotion instead of "motion" — saves ~30kb in bundle size
70. [warning] design-no-redundant-size-axes — apps/website/components/ui/collapsible.tsx:49
w-3 h-3 → use the shorthand size-3 (Tailwind v3.4+)
71. [warning] design-no-redundant-size-axes — apps/website/components/ui/collapsible.tsx:51
w-3 h-3 → use the shorthand size-3 (Tailwind v3.4+)
72. [warning] no-react19-deprecated-apis — apps/website/components/hotkey-context.tsx:3
useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`
73. [warning] jsx-no-constructed-context-values — apps/website/components/hotkey-context.tsx:21
Context `value` prop is constructed inline — wrap with `useMemo`/`useCallback` or hoist a constant to avoid re-renders.
74. [warning] use-lazy-motion — apps/website/components/grab-element-button.tsx:12
Import "m" with LazyMotion instead of "motion" — saves ~30kb in bundle size
75. [warning] no-effect-chain — apps/website/components/grab-element-button.tsx:232
useEffect reacts to "isMobile" which is set by another useEffect — chains of effects add an extra render per link and become rigid as code evolves. Compute what you can during render and write all related state inside the event handler that originally fires the chain
76. [warning] no-giant-component — apps/website/components/grab-element-button.tsx:89
Component "GrabElementButton" is 414 lines — consider breaking it into smaller focused components
77. [warning] prefer-useReducer — apps/website/components/grab-element-button.tsx:93
Component "GrabElementButton" has 6 useState calls — consider useReducer for related state
78. [warning] advanced-event-handler-refs — apps/website/components/grab-element-button.tsx:208
useEffect re-subscribes a "handleHotkeyKeyDown" 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
79. [warning] no-initialize-state — apps/website/components/grab-element-button.tsx:227
Avoid initializing state in an effect. Instead, initialize "isMac"'s `useState()` with "<expression>("MAC") >= 0". For SSR hydration, prefer `useSyncExternalStore()`.
80. [warning] no-initialize-state — apps/website/components/grab-element-button.tsx:228
Avoid initializing state in an effect. Instead, initialize "isMobile"'s `useState()` with "detectMobile()". For SSR hydration, prefer `useSyncExternalStore()`.
81. [warning] no-adjust-state-on-prop-change — apps/website/components/grab-element-button.tsx:234
Avoid adjusting state when a prop changes. Instead, adjust the state directly during render, or refactor your state to avoid this need entirely.
82. [warning] no-chain-state-updates — apps/website/components/grab-element-button.tsx:234
Avoid chaining state changes. When possible, update all relevant state simultaneously.
83. [warning] no-event-handler — apps/website/components/grab-element-button.tsx:233
Avoid using state and effects as an event handler. Instead, call the event handling code directly when the event occurs.
84. [warning] no-event-handler — apps/website/components/grab-element-button.tsx:233
Avoid using state and effects as an event handler. Instead, call the event handling code directly when the event occurs.
85. [warning] no-prop-callback-in-effect — apps/website/components/grab-element-button.tsx:235
useEffect calls prop callback "onSelect" 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
86. [warning] no-initialize-state — apps/website/components/grab-element-button.tsx:258
Avoid initializing state in an effect. Instead, initialize "isActivated"'s `useState()` with "undefined". For SSR hydration, prefer `useSyncExternalStore()`.
87. [warning] exhaustive-deps — apps/website/components/grab-element-button.tsx:290
React Hook `useEffect` is missing dependency `setIsActivated` — list it in the dependency array, or call the hook unconditionally.
88. [warning] no-cascading-set-state — apps/website/components/grab-element-button.tsx:264
3 setState calls in a single useEffect — consider using useReducer or deriving state
89. [warning] click-events-have-key-events — apps/website/components/grab-element-button.tsx:335
Visible non-interactive elements with click handlers must have a corresponding keyboard listener (`onKeyUp`, `onKeyDown`, or `onKeyPress`).
90. [warning] no-static-element-interactions — apps/website/components/grab-element-button.tsx:335
Static HTML elements with event handlers require a role — add `role="…"` or use a semantic HTML element instead.
91. [warning] no-render-in-render — apps/website/components/grab-element-button.tsx:343
Inline render function "renderHotkeyDisplay()" — extract to a separate component for proper reconciliation
92. [warning] no-render-in-render — apps/website/components/grab-element-button.tsx:406
Inline render function "renderActivationPrompt()" — extract to a separate component for proper reconciliation
93. [warning] design-no-redundant-size-axes — apps/website/components/view-docs-button.tsx:16
w-[15px] h-[15px] → use the shorthand size-[15px] (Tailwind v3.4+)
94. [warning] no-danger — apps/website/components/icons/icon-nextjs.tsx:10
Do not use `dangerouslySetInnerHTML` — it injects raw HTML and is a common XSS vector.
95. [warning] click-events-have-key-events — apps/website/components/react-grab-logo.tsx:33
Visible non-interactive elements with click handlers must have a corresponding keyboard listener (`onKeyUp`, `onKeyDown`, or `onKeyPress`).
96. [warning] no-static-element-interactions — apps/website/components/react-grab-logo.tsx:33
Static HTML elements with event handlers require a role — add `role="…"` or use a semantic HTML element instead.
97. [warning] no-generic-handler-names — apps/website/components/react-grab-logo.tsx:40
Non-descriptive handler name "handleClick" — name should describe what it does, not when it runs
98. [warning] rendering-svg-precision — apps/website/components/react-grab-logo.tsx:65
SVG d attribute uses 4+ decimal precision — truncate to 1–2 decimals to shrink markup with no visible difference
99. [warning] rendering-svg-precision — apps/website/components/react-grab-logo.tsx:69
SVG d attribute uses 4+ decimal precision — truncate to 1–2 decimals to shrink markup with no visible difference
100. [warning] exhaustive-deps — apps/website/components/blocks/read-tool-call-block.tsx:19
The ref value `timeoutRef.current` will likely have changed by the time this effect cleanup function runs. Copy it to a variable inside the hook callback and use that variable in cleanup.
101. [warning] button-has-type — apps/website/components/blocks/read-tool-call-block.tsx:38
`<button>` elements must have an explicit `type` attribute.
102. [warning] no-generic-handler-names — apps/website/components/blocks/read-tool-call-block.tsx:39
Non-descriptive handler name "handleClick" — name should describe what it does, not when it runs
103. [warning] rendering-svg-precision — apps/website/components/mobile-demo-animation.tsx:97
SVG d attribute uses 4+ decimal precision — truncate to 1–2 decimals to shrink markup with no visible difference
104. [warning] no-giant-component — apps/website/components/mobile-demo-animation.tsx:223
Component "MobileDemoAnimation" is 682 lines — consider breaking it into smaller focused components
105. [warning] prefer-useReducer — apps/website/components/mobile-demo-animation.tsx:223
Component "MobileDemoAnimation" has 9 useState calls — consider useReducer for related state
106. [warning] client-passive-event-listeners — apps/website/components/mobile-demo-animation.tsx:306
"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())
107. [warning] async-defer-await — apps/website/components/mobile-demo-animation.tsx:358
await blocks the function before an early-return that doesn't use the awaited value — move the await after the synchronous guard so the skip path stays fast
108. [warning] async-defer-await — apps/website/components/mobile-demo-animation.tsx:362
await blocks the function before an early-return that doesn't use the awaited value — move the await after the synchronous guard so the skip path stays fast
109. [warning] async-defer-await — apps/website/components/mobile-demo-animation.tsx:371
await blocks the function before an early-return that doesn't use the awaited value — move the await after the synchronous guard so the skip path stays fast
110. [warning] async-defer-await — apps/website/components/mobile-demo-animation.tsx:376
await blocks the function before an early-return that doesn't use the awaited value — move the await after the synchronous guard so the skip path stays fast
111. [warning] async-defer-await — apps/website/components/mobile-demo-animation.tsx:384
await blocks the function before an early-return that doesn't use the awaited value — move the await after the synchronous guard so the skip path stays fast
112. [warning] async-defer-await — apps/website/components/mobile-demo-animation.tsx:389
await blocks the function before an early-return that doesn't use the awaited value — move the await after the synchronous guard so the skip path stays fast
113. [warning] async-defer-await — apps/website/components/mobile-demo-animation.tsx:403
await blocks the function before an early-return that doesn't use the awaited value — move the await after the synchronous guard so the skip path stays fast
114. [warning] async-defer-await — apps/website/components/mobile-demo-animation.tsx:408
await blocks the function before an early-return that doesn't use the awaited value — move the await after the synchronous guard so the skip path stays fast
115. [warning] async-defer-await — apps/website/components/mobile-demo-animation.tsx:414
await blocks the function before an early-return that doesn't use the awaited value — move the await after the synchronous guard so the skip path stays fast
116. [warning] async-defer-await — apps/website/components/mobile-demo-animation.tsx:424
await blocks the function before an early-return that doesn't use the awaited value — move the await after the synchronous guard so the skip path stays fast
117. [warning] async-defer-await — apps/website/components/mobile-demo-animation.tsx:431
await blocks the function before an early-return that doesn't use the awaited value — move the await after the synchronous guard so the skip path stays fast
118. [warning] async-defer-await — apps/website/components/mobile-demo-animation.tsx:441
await blocks the function before an early-return that doesn't use the awaited value — move the await after the synchronous guard so the skip path stays fast
119. [warning] async-defer-await — apps/website/components/mobile-demo-animation.tsx:447
await blocks the function before an early-return that doesn't use the awaited value — move the await after the synchronous guard so the skip path stays fast
120. [warning] async-defer-await — apps/website/components/mobile-demo-animation.tsx:457
await blocks the function before an early-return that doesn't use the awaited value — move the await after the synchronous guard so the skip path stays fast
121. [warning] async-defer-await — apps/website/components/mobile-demo-animation.tsx:464
await blocks the function before an early-return that doesn't use the awaited value — move the await after the synchronous guard so the skip path stays fast
122. [warning] async-defer-await — apps/website/components/mobile-demo-animation.tsx:474
await blocks the function before an early-return that doesn't use the awaited value — move the await after the synchronous guard so the skip path stays fast
123. [warning] async-defer-await — apps/website/components/mobile-demo-animation.tsx:482
await blocks the function before an early-return that doesn't use the awaited value — move the await after the synchronous guard so the skip path stays fast
124. [warning] async-defer-await — apps/website/components/mobile-demo-animation.tsx:492
await blocks the function before an early-return that doesn't use the awaited value — move the await after the synchronous guard so the skip path stays fast
125. [warning] async-defer-await — apps/website/components/mobile-demo-animation.tsx:495
await blocks the function before an early-return that doesn't use the awaited value — move the await after the synchronous guard so the skip path stays fast
126. [warning] async-await-in-loop — apps/website/components/mobile-demo-animation.tsx:506
await inside a while-loop runs the calls sequentially — for independent operations, collect them and use `await Promise.all(items.map(...))` to run them concurrently
127. [warning] click-events-have-key-events — apps/website/components/mobile-demo-animation.tsx:685
Visible non-interactive elements with click handlers must have a corresponding keyboard listener (`onKeyUp`, `onKeyDown`, or `onKeyPress`).
128. [warning] no-static-element-interactions — apps/website/components/mobile-demo-animation.tsx:685
Static HTML elements with event handlers require a role — add `role="…"` or use a semantic HTML element instead.
129. [warning] design-no-redundant-size-axes — apps/website/components/mobile-demo-animation.tsx:753
w-5 h-5 → use the shorthand size-5 (Tailwind v3.4+)
130. [warning] design-no-redundant-size-axes — apps/website/components/mobile-demo-animation.tsx:840
w-0 h-0 → use the shorthand size-0 (Tailwind v3.4+)
131. [warning] no-pure-black-background — apps/website/components/mobile-demo-animation.tsx:889
Pure black background (bg-black) looks harsh — use a near-black tinted toward your brand hue (e.g. bg-gray-950)
132. [warning] use-lazy-motion — apps/website/components/user-message.tsx:4
Import "m" with LazyMotion instead of "motion" — saves ~30kb in bundle size
133. [warning] design-no-redundant-size-axes — apps/website/components/homepage-demo.tsx:256
w-3 h-3 → use the shorthand size-3 (Tailwind v3.4+)
134. [warning] design-no-redundant-size-axes — apps/website/components/github-button.tsx:17
w-[18px] h-[18px] → use the shorthand size-[18px] (Tailwind v3.4+)
135. [warning] no-adjust-state-on-prop-change — apps/website/components/ui/scrollable.tsx:45
Avoid adjusting state when a prop changes. Instead, adjust the state directly during render, or refactor your state to avoid this need entirely.
136. [warning] no-cascading-set-state — apps/website/components/ui/scrollable.tsx:23
3 setState calls in a single useEffect — consider using useReducer or deriving state
137. [warning] client-passive-event-listeners — apps/website/components/ui/scrollable.tsx:46
"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())
138. [warning] no-static-element-interactions — apps/website/components/ui/scrollable.tsx:98
Static HTML elements with event handlers require a role — add `role="…"` or use a semantic HTML element instead.
139. [warning] no-adjust-state-on-prop-change — apps/website/hooks/use-stream.ts:146
Avoid adjusting state when a prop changes. Instead, adjust the state directly during render, or refactor your state to avoid this need entirely.
140. [warning] no-chain-state-updates — apps/website/hooks/use-stream.ts:128
Avoid chaining state changes. When possible, update all relevant state simultaneously.
141. [warning] no-chain-state-updates — apps/website/hooks/use-stream.ts:146
Avoid chaining state changes. When possible, update all relevant state simultaneously.
142. [warning] no-derived-state — apps/website/hooks/use-stream.ts:128
Avoid storing derived state. Compute "state" directly during render, optionally with `useMemo` if it's expensive.
143. [warning] no-event-handler — apps/website/hooks/use-stream.ts:121
Avoid using props and effects as an event handler. Instead, move the handler to the parent component.
144. [warning] no-event-handler — apps/website/hooks/use-stream.ts:121
Avoid using props and effects as an event handler. Instead, move the handler to the parent component.
145. [warning] no-pass-data-to-parent — apps/website/hooks/use-stream.ts:128
Avoid passing data to parents in an effect. Instead, return the data from the hook.
146. [warning] no-cascading-set-state — apps/website/hooks/use-stream.ts:161
12 setState calls in a single useEffect — consider using useReducer or deriving state
147. [warning] design-no-bold-heading — apps/website/app/privacy/page.tsx:56
font-bold on <h1> crushes counter shapes at display sizes — use font-semibold (600) or font-medium (500)
148. [warning] rendering-hydration-mismatch-time — apps/website/app/privacy/page.tsx:57
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
149. [warning] design-no-bold-heading — apps/website/app/privacy/page.tsx:66
font-bold on <h2> crushes counter shapes at display sizes — use font-semibold (600) or font-medium (500)
150. [warning] nextjs-missing-metadata — apps/website/app/open-file/page.tsx:1
Page without metadata or generateMetadata export — hurts SEO
151. [warning] prefer-use-effect-event — apps/website/app/open-file/page.tsx:106
"handleOpen" is read only inside `setTimeout` — wrap it with useEffectEvent and remove it from the dep array so the effect doesn't re-synchronize on every parent render
152. [warning] prefer-use-effect-event — apps/website/app/open-file/page.tsx:117
"handleOpen" is read only inside `addEventListener` — wrap it with useEffectEvent and remove it from the dep array so the effect doesn't re-synchronize on every parent render
153. [warning] prefer-useReducer — apps/website/app/open-file/page.tsx:43
Component "OpenFileContent" has 5 useState calls — consider useReducer for related state
154. [warning] rerender-state-only-in-handlers — apps/website/app/open-file/page.tsx:70
useState "didAttemptOpen" is updated but never read in the component's return — use useRef so updates don't trigger re-renders
155. [warning] js-set-map-lookups — apps/website/app/sitemap.ts:53
array.includes() in a loop is O(n) per call — convert to a Set for O(1) lookups
156. [warning] prefer-tag-over-role — apps/website-v2/components/ui/item.tsx:11
Prefer the semantic `<menu>` element over `role="list"` on a generic tag.
157. [warning] nextjs-no-native-script — apps/website-v2/app/layout.tsx:39
Use next/script <Script> instead of <script> — provides loading strategy optimization and deferred loading
158. [warning] nextjs-missing-metadata — apps/website-v2/app/page.tsx:1
Page without metadata or generateMetadata export — hurts SEO
159. [warning] no-giant-component — apps/website-v2/app/page.tsx:161
Component "Home" is 737 lines — consider breaking it into smaller focused components
160. [warning] design-no-bold-heading — apps/website-v2/app/page.tsx:171
font-bold on <h1> crushes counter shapes at display sizes — use font-semibold (600) or font-medium (500)
161. [warning] design-no-em-dash-in-jsx-text — apps/website-v2/app/page.tsx:811
Em dash (—) in JSX text reads as model output — replace with comma, colon, semicolon, or parentheses
162. [warning] no-multi-comp — apps/website-v2/components/ui/native-select.tsx:35
Declare only one React component per file. Found extra component: NativeSelectOption.
163. [warning] no-multi-comp — apps/website-v2/components/ui/native-select.tsx:45
Declare only one React component per file. Found extra component: NativeSelectOptGroup.
164. [warning] no-react19-deprecated-apis — apps/website-v2/components/ui/carousel.tsx:34
useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`
165. [warning] no-pass-data-to-parent — apps/website-v2/components/ui/carousel.tsx:91
Avoid passing data to parents in an effect. Instead, fetch the data in the parent and pass it down to the child as a prop.
166. [warning] no-prop-callback-in-effect — apps/website-v2/components/ui/carousel.tsx:91
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
167. [warning] advanced-event-handler-refs — apps/website-v2/components/ui/carousel.tsx:94
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
168. [warning] jsx-no-constructed-context-values — apps/website-v2/components/ui/carousel.tsx:107
Context `value` prop is constructed inline — wrap with `useMemo`/`useCallback` or hoist a constant to avoid re-renders.
169. [warning] prefer-tag-over-role — apps/website-v2/components/ui/carousel.tsx:121
Prefer the semantic `<section>` element over `role="region"` on a generic tag.
170. [warning] prefer-tag-over-role — apps/website-v2/components/ui/carousel.tsx:150
Prefer the semantic `<address>` element over `role="group"` on a generic tag.
171. [warning] prefer-tag-over-role — apps/website-v2/components/ui/breadcrumb.tsx:58
Prefer the semantic `<a>` element over `role="link"` on a generic tag.
172. [warning] no-array-index-as-key — apps/website-v2/components/ui/slider.tsx:46
Array index "index" used as key — causes bugs when list is reordered or filtered
173. [warning] prefer-tag-over-role — apps/website-v2/components/ui/field.tsx:76
Prefer the semantic `<address>` element over `role="group"` on a generic tag.
174. [warning] rerender-memo-before-early-return — apps/website-v2/components/ui/field.tsx:175
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
175. [warning] no-array-index-key — apps/website-v2/components/ui/field.tsx:192
Array index in `key` doesn't uniquely identify the element — re-renders may use stale state.
176. [warning] no-array-index-as-key — apps/website-v2/components/ui/field.tsx:192
Array index "index" used as key — causes bugs when list is reordered or filtered
177. [warning] no-multi-comp — apps/website-v2/components/ui/collapsible.tsx:9
Declare only one React component per file. Found extra component: CollapsibleTrigger.
178. [warning] no-multi-comp — apps/website-v2/components/ui/collapsible.tsx:15
Declare only one React component per file. Found extra component: CollapsibleContent.
179. [warning] prefer-tag-over-role — apps/website-v2/components/ui/button-group.tsx:31
Prefer the semantic `<address>` element over `role="group"` on a generic tag.
180. [warning] jsx-no-constructed-context-values — apps/website-v2/components/ui/toggle-group.tsx:49
Context `value` prop is constructed inline — wrap with `useMemo`/`useCallback` or hoist a constant to avoid re-renders.
181. [warning] no-react19-deprecated-apis — apps/website-v2/components/ui/toggle-group.tsx:63
useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`
182. [warning] no-multi-comp — apps/website-v2/components/ui/input-otp.tsx:43
Declare only one React component per file. Found extra component: InputOTPSlot.
183. [warning] no-multi-comp — apps/website-v2/components/ui/input-otp.tsx:73
Declare only one React component per file. Found extra component: InputOTPSeparator.
184. [warning] no-react19-deprecated-apis — apps/website-v2/components/ui/input-otp.tsx:50
useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`
185. [warning] prefer-tag-over-role — apps/website-v2/components/ui/input-otp.tsx:78
Prefer the semantic `<hr>` element over `role="separator"` on a generic tag.
186. [warning] prefer-dynamic-import — apps/website-v2/components/ui/chart.tsx:4
"recharts" is a heavy library — use React.lazy() or next/dynamic for code splitting
187. [warning] no-react19-deprecated-apis — apps/website-v2/components/ui/chart.tsx:33
useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`
188. [warning] jsx-no-constructed-context-values — apps/website-v2/components/ui/chart.tsx:61
Context `value` prop is constructed inline — wrap with `useMemo`/`useCallback` or hoist a constant to avoid re-renders.
189. [warning] no-danger — apps/website-v2/components/ui/chart.tsx:89
Do not use `dangerouslySetInnerHTML` — it injects raw HTML and is a common XSS vector.
190. [warning] rerender-memo-before-early-return — apps/website-v2/components/ui/chart.tsx:138
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
191. [warning] js-combine-iterations — apps/website-v2/components/ui/chart.tsx:177
.filter().map() iterates the array twice — combine into a single loop with .reduce() or for...of
192. [warning] no-array-index-key — apps/website-v2/components/ui/chart.tsx:186
Array index in `key` doesn't uniquely identify the element — re-renders may use stale state.
193. [warning] no-array-index-as-key — apps/website-v2/components/ui/chart.tsx:186
Array index "index" used as key — causes bugs when list is reordered or filtered
194. [warning] js-combine-iterations — apps/website-v2/components/ui/chart.tsx:276
.filter().map() iterates the array twice — combine into a single loop with .reduce() or for...of
195. [warning] no-array-index-key — apps/website-v2/components/ui/chart.tsx:284
Array index in `key` doesn't uniquely identify the element — re-renders may use stale state.
196. [warning] no-array-index-as-key — apps/website-v2/components/ui/chart.tsx:284
Array index "index" used as key — causes bugs when list is reordered or filtered
197. [warning] design-no-redundant-size-axes — apps/website-v2/components/ui/chart.tsx:293
w-2 h-2 → use the shorthand size-2 (Tailwind v3.4+)
198. [warning] no-multi-comp — apps/website-v2/components/ui/hover-card.tsx:12
Declare only one React component per file. Found extra component: HoverCardTrigger.
199. [warning] no-multi-comp — apps/website-v2/components/ui/hover-card.tsx:16
Declare only one React component per file. Found extra component: HoverCardContent.
200. [warning] design-no-redundant-size-axes — apps/website-v2/components/ui/navigation-menu.tsx:145
w-2 h-2 → use the shorthand size-2 (Tailwind v3.4+)
201. [warning] no-redundant-roles — apps/website-v2/components/ui/pagination.tsx:10
`<nav>` already has implicit role `navigation` — remove the redundant `role` attribute.
202. [warning] anchor-has-content — apps/website-v2/components/ui/pagination.tsx:41
Anchor must have accessible content — provide visible text, `aria-label`, or `aria-labelledby`.
203. [warning] no-multi-comp — apps/website-v2/components/ui/resizable.tsx:17
Declare only one React component per file. Found extra component: ResizablePanel.
204. [warning] no-multi-comp — apps/website-v2/components/ui/resizable.tsx:21
Declare only one React component per file. Found extra component: ResizableHandle.
205. [warning] no-event-handler — apps/website-v2/components/ui/calendar.tsx:157
Avoid using props and effects as an event handler. Instead, move the handler to the parent component.
206. [warning] no-multi-comp — apps/website-v2/components/ui/input-group.tsx:44
Declare only one React component per file. Found extra component: InputGroupAddon.
207. [warning] no-multi-comp — apps/website-v2/components/ui/input-group.tsx:99
Declare only one React component per file. Found extra component: InputGroupText.
208. [warning] prefer-tag-over-role — apps/website-v2/components/ui/input-group.tsx:15
Prefer the semantic `<address>` element over `role="group"` on a generic tag.
209. [warning] click-events-have-key-events — apps/website-v2/components/ui/input-group.tsx:50
Visible non-interactive elements with click handlers must have a corresponding keyboard listener (`onKeyUp`, `onKeyDown`, or `onKeyPress`).
210. [warning] prefer-tag-over-role — apps/website-v2/components/ui/input-group.tsx:51
Prefer the semantic `<address>` element over `role="group"` on a generic tag.
211. [warning] no-initialize-state — apps/website-v2/hooks/use-mobile.ts:14
Avoid initializing state in an effect. Instead, initialize "isMobile"'s `useState()` with "window.innerWidth < MOBILE_BREAKPOINT". For SSR hydration, prefer `useSyncExternalStore()`.
212. [warning] unused-file — apps/website-v2/components/ui/button-group.tsx:0
Unused file — not reachable from any entry point
213. [warning] unused-file — apps/website-v2/components/ui/carousel.tsx:0
Unused file — not reachable from any entry point
214. [warning] unused-file — apps/website-v2/components/ui/chart.tsx:0
Unused file — not reachable from any entry point
215. [warning] unused-file — apps/website-v2/components/ui/combobox.tsx:0
Unused file — not reachable from any entry point
216. [warning] unused-file — apps/website-v2/components/ui/command.tsx:0
Unused file — not reachable from any entry point
217. [warning] unused-file — apps/website-v2/components/ui/context-menu.tsx:0
Unused file — not reachable from any entry point
218. [warning] unused-file — apps/website-v2/components/ui/direction.tsx:0
Unused file — not reachable from any entry point
219. [warning] unused-file — apps/website-v2/components/ui/drawer.tsx:0
Unused file — not reachable from any entry point
220. [warning] unused-file — apps/website-v2/components/ui/empty.tsx:0
Unused file — not reachable from any entry point
221. [warning] unused-file — apps/website-v2/components/ui/field.tsx:0
Unused file — not reachable from any entry point
222. [warning] unused-file — apps/website-v2/components/ui/input-group.tsx:0
Unused file — not reachable from any entry point
223. [warning] unused-file — apps/website-v2/components/ui/input-otp.tsx:0
Unused file — not reachable from any entry point
224. [warning] unused-file — apps/website-v2/components/ui/item.tsx:0
Unused file — not reachable from any entry point
225. [warning] unused-file — apps/website-v2/components/ui/native-select.tsx:0
Unused file — not reachable from any entry point
226. [warning] unused-file — apps/website-v2/components/ui/sonner.tsx:0
Unused file — not reachable from any entry point
227. [warning] unused-file — apps/website-v2/hooks/use-mobile.ts:0
Unused file — not reachable from any entry point
228. [warning] unused-dependency — apps/website-v2/package.json:0
Unused dependency: `date-fns`
229. [warning] button-has-type — packages/react-grab/src/components/selection-label/completion-view.tsx:17
`<button>` elements must have an explicit `type` attribute.
230. [warning] no-render-in-render — packages/react-grab/src/components/selection-label/tag-badge.tsx:47
Inline render function "renderTagLabel()" — extract to a separate component for proper reconciliation
231. [warning] no-render-in-render — packages/react-grab/src/components/selection-label/tag-badge.tsx:62
Inline render function "renderTagLabel()" — extract to a separate component for proper reconciliation
232. [warning] client-passive-event-listeners — packages/react-grab/src/components/selection-label/index.tsx:152
"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())
233. [warning] no-generic-handler-names — packages/react-grab/src/components/selection-label/index.tsx:521
Non-descriptive handler name "handleInput" — name should describe what it does, not when it runs
234. [warning] client-passive-event-listeners — packages/react-grab/src/core/index.tsx:2874
"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())
235. [warning] js-length-check-first — packages/react-grab/src/core/index.tsx:3035
.every() over an array compared to another array — short-circuit with `a.length === b.length && a.every(...)` so unequal-length arrays exit immediately
236. [warning] rendering-svg-precision — packages/react-grab/src/components/icons/icon-command.tsx:23
SVG d attribute uses 4+ decimal precision — truncate to 1–2 decimals to shrink markup with no visible difference
237. [warning] rendering-svg-precision — packages/react-grab/src/components/icons/icon-return.tsx:23
SVG d attribute uses 4+ decimal precision — truncate to 1–2 decimals to shrink markup with no visible difference
238. [warning] rendering-svg-precision — packages/react-grab/src/components/icons/icon-check.tsx:23
SVG d attribute uses 4+ decimal precision — truncate to 1–2 decimals to shrink markup with no visible difference
239. [warning] rendering-svg-precision — packages/react-grab/src/components/icons/icon-submit.tsx:23
SVG d attribute uses 4+ decimal precision — truncate to 1–2 decimals to shrink markup with no visible difference
240. [warning] rendering-svg-precision — packages/react-grab/src/components/icons/icon-select.tsx:35
SVG d attribute uses 4+ decimal precision — truncate to 1–2 decimals to shrink markup with no visible difference
241. [warning] rendering-svg-precision — packages/react-grab/src/components/icons/icon-retry.tsx:23
SVG d attribute uses 4+ decimal precision — truncate to 1–2 decimals to shrink markup with no visible difference
242. [warning] button-has-type — packages/react-grab/src/components/selection-label/discard-prompt.tsx:60
`<button>` elements must have an explicit `type` attribute.
243. [warning] button-has-type — packages/react-grab/src/components/selection-label/discard-prompt.tsx:69
`<button>` elements must have an explicit `type` attribute.
244. [warning] client-passive-event-listeners — packages/react-grab/src/components/toolbar/index.tsx:462
"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())
245. [warning] rendering-svg-precision — packages/react-grab/src/components/icons/icon-chevron.tsx:23
SVG d attribute uses 4+ decimal precision — truncate to 1–2 decimals to shrink markup with no visible difference
246. [warning] client-passive-event-listeners — packages/react-grab/src/utils/create-anchored-dropdown.ts:87
"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())
247. [warning] async-await-in-loop — packages/react-grab/src/core/plugin-registry.ts:208
await inside a for…of loop runs the calls sequentially — for independent operations, collect them and use `await Promise.all(items.map(...))` to run them concurrently
248. [warning] js-set-map-lookups — packages/react-grab/src/core/store.ts:488
array.includes() in a loop is O(n) per call — convert to a Set for O(1) lookups
249. [warning] rendering-svg-precision — packages/react-grab/src/components/icons/icon-ellipsis.tsx:23
SVG d attribute uses 4+ decimal precision — truncate to 1–2 decimals to shrink markup with no visible difference
250. [warning] server-sequential-independent-await — packages/react-grab/src/primitives.ts:60
Sequential `await` without a data dependency on the previous result — wrap the independent calls in `Promise.all([...])` so they race instead of waterfalling
251. [warning] js-set-map-lookups — packages/react-grab/src/utils/create-element-selector.ts:84
array.indexOf() in a loop is O(n) per call — convert to a Set for O(1) lookups
252. [warning] client-passive-event-listeners — packages/react-grab/src/utils/register-overlay-dismiss.ts:49
"touchstart" listener without { passive: true } — blocks scrolling performance. Only add { passive: true } if the handler does NOT call event.preventDefault() (passive listeners silently ignore preventDefault())
```
</details>
---
### ⚠️ Warnings (252)
<details>
<summary>`<button>` elements must have an explicit `type` attribute. <sub>· 19 in 4 files</sub></summary>
<sub><code>button-has-type</code></sub>
> Set `type="button"` (or `"submit"` / `"reset"`) explicitly on every `<button>`.
| File | Lines |
| --- | --- |
| [`apps/e2e-app/src/App.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/e2e-app/src/App.tsx#L59) | 59, 184, 194, 256, 394, 406, 412, 418, +7 more |
| [`packages/react-grab/src/components/selection-label/discard-prompt.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/packages/react-grab/src/components/selection-label/discard-prompt.tsx#L60) | 60, 69 |
| [`apps/website/components/blocks/read-tool-call-block.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website/components/blocks/read-tool-call-block.tsx#L38) | 38 |
| [`packages/react-grab/src/components/selection-label/completion-view.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/packages/react-grab/src/components/selection-label/completion-view.tsx#L17) | 17 |
</details>
<details>
<summary>await blocks the function before an early-return that doesn't use the awaited value — move the await after the synchronous guard so the skip path stays fast <sub>· 19 in 1 file</sub></summary>
<sub><code>async-defer-await</code></sub>
> Move the `await` after the synchronous early-return guard so the skip path stays fast
| File | Lines |
| --- | --- |
| [`apps/website/components/mobile-demo-animation.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website/components/mobile-demo-animation.tsx#L358) | 358, 362, 371, 376, 384, 389, 403, 408, +11 more |
</details>
<details>
<summary>font-bold on <h1> crushes counter shapes at display sizes — use font-semibold (600) or font-medium (500) <sub>· 18 in 4 files</sub></summary>
<sub><code>design-no-bold-heading</code></sub>
> Use `font-semibold` (600) or `font-medium` (500) on headings — 700+ crushes letter counter shapes at display sizes
| File | Lines |
| --- | --- |
| [`apps/e2e-app/src/App.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/e2e-app/src/App.tsx#L30) | 30, 77, 136, 175, 239, 333, 349, 392, +6 more |
| [`apps/website/app/privacy/page.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website/app/privacy/page.tsx#L56) | 56, 66 |
| [`apps/e2e-app/src/perf-grid.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/e2e-app/src/perf-grid.tsx#L44) | 44 |
| [`apps/website-v2/app/page.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website-v2/app/page.tsx#L171) | 171 |
</details>
<details>
<summary>Unused file — not reachable from any entry point <sub>· 16 in 16 files</sub></summary>
<sub><code>unused-file</code></sub>
> Delete the file if it is truly unreachable, or import it from an entry point.
| File | Lines |
| --- | --- |
| [`apps/website-v2/components/ui/button-group.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website-v2/components/ui/button-group.tsx#L0) | 0 |
| [`apps/website-v2/components/ui/carousel.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website-v2/components/ui/carousel.tsx#L0) | 0 |
| [`apps/website-v2/components/ui/chart.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website-v2/components/ui/chart.tsx#L0) | 0 |
| [`apps/website-v2/components/ui/combobox.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website-v2/components/ui/combobox.tsx#L0) | 0 |
| [`apps/website-v2/components/ui/command.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website-v2/components/ui/command.tsx#L0) | 0 |
| _…and 11 more files_ | [view on react.review](https://react.review/repo/aidenybai/react-grab) |
</details>
<details>
<summary>w-12 h-12 → use the shorthand size-12 (Tailwind v3.4+) <sub>· 14 in 8 files</sub></summary>
<sub><code>design-no-redundant-size-axes</code></sub>
> Collapse `w-N h-N` to `size-N` (Tailwind v3.4+) when both axes match
| File | Lines |
| --- | --- |
| [`apps/e2e-app/src/App.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/e2e-app/src/App.tsx#L309) | 309, 336, 339, 340, 351 |
| [`apps/website/components/ui/collapsible.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website/components/ui/collapsible.tsx#L49) | 49, 51 |
| [`apps/website/components/mobile-demo-animation.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website/components/mobile-demo-animation.tsx#L753) | 753, 840 |
| [`apps/website/components/view-docs-button.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website/components/view-docs-button.tsx#L16) | 16 |
| [`apps/website/components/homepage-demo.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website/components/homepage-demo.tsx#L256) | 256 |
| _…and 3 more files_ | [view on react.review](https://react.review/repo/aidenybai/react-grab) |
</details>
<details>
<summary>SVG d attribute uses 4+ decimal precision — truncate to 1–2 decimals to shrink markup with no visible difference <sub>· 12 in 11 files</sub></summary>
<sub><code>rendering-svg-precision</code></sub>
> Truncate path/points/transform decimals to 1–2 digits — sub-pixel precision adds bytes with no visible difference
| File | Lines |
| --- | --- |
| [`apps/website/components/react-grab-logo.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website/components/react-grab-logo.tsx#L65) | 65, 69 |
| [`apps/website/app/api/og/route.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website/app/api/og/route.tsx#L34) | 34 |
| [`apps/website/components/mobile-demo-animation.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website/components/mobile-demo-animation.tsx#L97) | 97 |
| [`packages/react-grab/src/components/icons/icon-command.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/packages/react-grab/src/components/icons/icon-command.tsx#L23) | 23 |
| [`packages/react-grab/src/components/icons/icon-return.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/packages/react-grab/src/components/icons/icon-return.tsx#L23) | 23 |
| _…and 6 more files_ | [view on react.review](https://react.review/repo/aidenybai/react-grab) |
</details>
<details>
<summary>Declare only one React component per file. Found extra component: NativeSelectOption. <sub>· 12 in 6 files</sub></summary>
<sub><code>no-multi-comp</code></sub>
> Move secondary components into their own files.
| File | Lines |
| --- | --- |
| [`apps/website-v2/components/ui/native-select.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website-v2/components/ui/native-select.tsx#L35) | 35, 45 |
| [`apps/website-v2/components/ui/collapsible.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website-v2/components/ui/collapsible.tsx#L9) | 9, 15 |
| [`apps/website-v2/components/ui/input-otp.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website-v2/components/ui/input-otp.tsx#L43) | 43, 73 |
| [`apps/website-v2/components/ui/hover-card.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website-v2/components/ui/hover-card.tsx#L12) | 12, 16 |
| [`apps/website-v2/components/ui/resizable.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website-v2/components/ui/resizable.tsx#L17) | 17, 21 |
| _…and 1 more file_ | [view on react.review](https://react.review/repo/aidenybai/react-grab) |
</details>
<details>
<summary>Prefer the semantic `<menu>` element over `role="list"` on a generic tag. <sub>· 9 in 7 files</sub></summary>
<sub><code>prefer-tag-over-role</code></sub>
> Replace `role` with the semantic HTML element when one exists.
| File | Lines |
| --- | --- |
| [`apps/website-v2/components/ui/carousel.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website-v2/components/ui/carousel.tsx#L121) | 121, 150 |
| [`apps/website-v2/components/ui/input-group.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website-v2/components/ui/input-group.tsx#L15) | 15, 51 |
| [`apps/website-v2/components/ui/item.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website-v2/components/ui/item.tsx#L11) | 11 |
| [`apps/website-v2/components/ui/breadcrumb.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website-v2/components/ui/breadcrumb.tsx#L58) | 58 |
| [`apps/website-v2/components/ui/field.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website-v2/components/ui/field.tsx#L76) | 76 |
| _…and 2 more files_ | [view on react.review](https://react.review/repo/aidenybai/react-grab) |
</details>
<details>
<summary>Array index in `key` doesn't uniquely identify the element — re-renders may use stale state. <sub>· 7 in 4 files</sub></summary>
<sub><code>no-array-index-key</code></sub>
> Use a stable, data-derived `key` instead of the array index.
| File | Lines |
| --- | --- |
| [`apps/website/components/blocks/streaming-text.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website/components/blocks/streaming-text.tsx#L77) | 77, 86, 91 |
| [`apps/website-v2/components/ui/chart.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website-v2/components/ui/chart.tsx#L186) | 186, 284 |
| [`apps/website/app/changelog/page.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website/app/changelog/page.tsx#L90) | 90 |
| [`apps/website-v2/components/ui/field.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website-v2/components/ui/field.tsx#L192) | 192 |
</details>
<details>
<summary>Array index "index" used as key — causes bugs when list is reordered or filtered <sub>· 7 in 4 files</sub></summary>
<sub><code>no-array-index-as-key</code></sub>
> Use a stable unique identifier: `key={item.id}` or `key={item.slug}` — index keys break on reorder/filter
| File | Lines |
| --- | --- |
| [`apps/website/components/blocks/streaming-text.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website/components/blocks/streaming-text.tsx#L77) | 77, 86, 91 |
| [`apps/website-v2/components/ui/chart.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website-v2/components/ui/chart.tsx#L186) | 186, 284 |
| [`apps/website-v2/components/ui/slider.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website-v2/components/ui/slider.tsx#L46) | 46 |
| [`apps/website-v2/components/ui/field.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website-v2/components/ui/field.tsx#L192) | 192 |
</details>
<details>
<summary>"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()) <sub>· 7 in 7 files</sub></summary>
<sub><code>client-passive-event-listeners</code></sub>
> 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.
| File | Lines |
| --- | --- |
| [`apps/website/components/mobile-demo-animation.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website/components/mobile-demo-animation.tsx#L306) | 306 |
| [`apps/website/components/ui/scrollable.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website/components/ui/scrollable.tsx#L46) | 46 |
| [`packages/react-grab/src/components/selection-label/index.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/packages/react-grab/src/components/selection-label/index.tsx#L152) | 152 |
| [`packages/react-grab/src/core/index.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/packages/react-grab/src/core/index.tsx#L2874) | 2874 |
| [`packages/react-grab/src/components/toolbar/index.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/packages/react-grab/src/components/toolbar/index.tsx#L462) | 462 |
| _…and 2 more files_ | [view on react.review](https://react.review/repo/aidenybai/react-grab) |
</details>
<details>
<summary>Do not use `dangerouslySetInnerHTML` — it injects raw HTML and is a common XSS vector. <sub>· 6 in 5 files</sub></summary>
<sub><code>no-danger</code></sub>
> Render trusted content as React children rather than injecting raw HTML.
| File | Lines |
| --- | --- |
| [`apps/website/components/install-tabs.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website/components/install-tabs.tsx#L468) | 468, 492 |
| [`apps/website/components/icons/icon-vite.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website/components/icons/icon-vite.tsx#L10) | 10 |
| [`apps/website/components/icons/icon-tanstack.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website/components/icons/icon-tanstack.tsx#L10) | 10 |
| [`apps/website/components/icons/icon-nextjs.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website/components/icons/icon-nextjs.tsx#L10) | 10 |
| [`apps/website-v2/components/ui/chart.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website-v2/components/ui/chart.tsx#L89) | 89 |
</details>
<details>
<summary>Avoid initializing state in an effect. Instead, initialize "isMobile"'s `useState()` with "detectMobile()". For SSR hydration, prefer `useSyncExternalStore()`. <sub>· 5 in 3 files</sub></summary>
<sub><code>no-initialize-state</code></sub>
> Pass the initial value directly to useState() instead of setting it from a mount-only useEffect. For SSR hydration, prefer useSyncExternalStore().
| File | Lines |
| --- | --- |
| [`apps/website/components/grab-element-button.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website/components/grab-element-button.tsx#L227) | 227, 228, 258 |
| [`apps/website/components/install-tabs.tsx`](https://github.com/aidenybai/react-grab/blob/f424da637d845042efcc5043de83c8cd5c232a01/apps/website/components/install-tabs.tsx#L264) | 264 |
|
---
_Issue body truncated. See the full report at [react.review/dashboard](https://react.review/dashboard)._
Guía de contribución
Evaluación
Este issue todavía no se ha evaluado.