aidenybai / aidenybai/react-grab

React Review Audit

Ouverte
#352 0 commentaires 0 réactions 0 personnes assignées Voir sur GitHub
Langage dominant
TypeScript
Étoiles
7.6k
Forks
340
Merge moyen
5 h 12 min
PR mergées (30 j)
6

Description

⚠️ 252 warnings
86 score

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>`&lt;button&gt;` 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 `&lt;button&gt;`.

| 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 &lt;h1&gt; 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 `&lt;menu&gt;` 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)._

Guide de contribution

Ouvrir le guide de contribution

Évaluation

Cette issue n'a pas encore été évaluée.

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.