Score: 69/100 · 8 errors · 133 warnings
Copy as prompt
Fix the following React Review diagnostics in my codebase.
## Errors (8)
1. [error] alt-text — src/modules/shared/components/Sidebar/Sidebar.tsx:17
Missing `alt` attribute.
2. [error] alt-text — src/modules/shared/components/Sidebar/Sidebar.tsx:17
Missing `alt` attribute.
3. [error] jsx-key — src/modules/editor/plugins/MentionsPlugin/index.tsx:621
Missing "key" prop for element in iterator.
4. [error] effect-needs-cleanup — src/modules/editor/plugins/TableCellResizer/index.tsx:87
useEffect schedules `setTimeout(...)` but never returns a cleanup — leaks the registration on every re-run and on unmount. Return a cleanup function that calls clearTimeout(...)
5. [error] effect-needs-cleanup — src/modules/editor/plugins/SpeechToTextPlugin/index.ts:57
useEffect subscribes via `addEventListener(...)` but never returns a cleanup — leaks the registration on every re-run and on unmount. Return a cleanup function that calls the matching remove/unsubscribe call
6. [error] alt-text — src/modules/editor/nodes/ImageComponent.tsx:126
Missing `alt` attribute.
7. [error] no-nested-component-definition — src/modules/editor/nodes/ExcalidrawNode/ExcalidrawModal.tsx:183
Component "ShowDiscardDialog" defined inside "ExcalidrawModal" — creates new instance every render, destroying state
8. [error] effect-needs-cleanup — src/modules/editor/nodes/StickyComponent.tsx:133
useEffect schedules `setTimeout(...)` but never returns a cleanup — leaks the registration on every re-run and on unmount. Return a cleanup function that calls clearTimeout(...)
## Warnings (133)
9. [warning] click-events-have-key-events — src/modules/editor/plugins/EmojiPickerPlugin/index.tsx:60
Enforce a clickable non-interactive element has at least one keyboard event listener.
10. [warning] no-array-index-as-key — src/modules/shared/components/SidebarItems/SidebarItems.tsx:19
Array index "index" used as key — causes bugs when list is reordered or filtered
11. [warning] click-events-have-key-events — src/modules/editor/plugins/ContextMenuPlugin/index.tsx:43
Enforce a clickable non-interactive element has at least one keyboard event listener.
12. [warning] async-await-in-loop — src/modules/editor/plugins/ContextMenuPlugin/index.tsx:136
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
13. [warning] click-events-have-key-events — src/modules/editor/plugins/ComponentPickerPlugin/index.tsx:101
Enforce a clickable non-interactive element has at least one keyboard event listener.
14. [warning] no-array-index-as-key — src/modules/editor/plugins/ComponentPickerPlugin/index.tsx:342
Array index "index" used as key — causes bugs when list is reordered or filtered
15. [warning] async-await-in-loop — src/modules/editor/utils/docSerialization.ts:17
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
16. [warning] click-events-have-key-events — src/modules/shared/components/Navbar/Navbar.tsx:108
Enforce a clickable non-interactive element has at least one keyboard event listener.
17. [warning] click-events-have-key-events — src/modules/shared/components/Navbar/Navbar.tsx:116
Enforce a clickable non-interactive element has at least one keyboard event listener.
18. [warning] click-events-have-key-events — src/modules/shared/components/Navbar/Navbar.tsx:125
Enforce a clickable non-interactive element has at least one keyboard event listener.
19. [warning] no-derived-useState — src/modules/editor/ui/KatexEquationAlterer.tsx:28
useState initialized from prop "initialEquation" — if this value should stay in sync with the prop, derive it during render instead
20. [warning] no-default-props — src/modules/shared/components/LazyLoad/LazyLoad.tsx:24
LazyLoad.defaultProps — React 19 removes `defaultProps` for function components and discourages it for class components. Move defaults into the destructured props parameter (e.g. `function LazyLoad({ size = "md", ...rest })`) so the rule applies cleanly to both shapes
21. [warning] js-batch-dom-css — src/modules/editor/ui/ImageResizer.tsx:169
Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows
22. [warning] js-batch-dom-css — src/modules/editor/ui/ImageResizer.tsx:199
Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows
23. [warning] no-array-index-as-key — src/modules/shared/routes/index.tsx:27
Array index "index" used as key — causes bugs when list is reordered or filtered
24. [warning] click-events-have-key-events — src/modules/shared/components/Input/Input.tsx:69
Enforce a clickable non-interactive element has at least one keyboard event listener.
25. [warning] no-default-props — src/modules/shared/components/Input/Input.tsx:90
Input.defaultProps — React 19 removes `defaultProps` for function components and discourages it for class components. Move defaults into the destructured props parameter (e.g. `function Input({ size = "md", ...rest })`) so the rule applies cleanly to both shapes
26. [warning] no-autofocus — src/modules/editor/ui/EquationEditor.tsx:36
The `autoFocus` attribute is found here, which can cause usability issues for sighted and non-sighted users.
27. [warning] no-react19-deprecated-apis — src/modules/editor/ui/EquationEditor.tsx:13
forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly
28. [warning] click-events-have-key-events — src/modules/shared/components/DropDown/DropDown.tsx:48
Enforce a clickable non-interactive element has at least one keyboard event listener.
29. [warning] no-static-element-interactions — src/modules/shared/components/DropDown/DropDown.tsx:48
Static HTML elements with event handlers require a role.
30. [warning] click-events-have-key-events — src/modules/dashboard/features/Test.tsx:18
Enforce a clickable non-interactive element has at least one keyboard event listener.
31. [warning] no-static-element-interactions — src/modules/dashboard/features/Test.tsx:18
Static HTML elements with event handlers require a role.
32. [warning] no-static-element-interactions — src/modules/editor/ui/DropDown.tsx:127
Static HTML elements with event handlers require a role.
33. [warning] no-react19-deprecated-apis — src/modules/editor/ui/DropDown.tsx:37
useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`
34. [warning] rerender-state-only-in-handlers — src/modules/editor/ui/DropDown.tsx:68
useState "highlightedItem" is updated but never read in the component's return — use useRef so updates don't trigger re-renders
35. [warning] js-batch-dom-css — src/modules/editor/ui/DropDown.tsx:171
Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows
36. [warning] client-passive-event-listeners — src/modules/editor/ui/DropDown.tsx:213
"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())
37. [warning] no-default-props — src/modules/shared/components/Button/Button.tsx:67
Button.defaultProps — React 19 removes `defaultProps` for function components and discourages it for class components. Move defaults into the destructured props parameter (e.g. `function Button({ size = "md", ...rest })`) so the rule applies cleanly to both shapes
38. [warning] no-static-element-interactions — src/modules/editor/ui/ColorPicker.tsx:211
Static HTML elements with event handlers require a role.
39. [warning] no-effect-chain — src/modules/editor/ui/ColorPicker.tsx:92
useEffect reacts to "selfColor" 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
40. [warning] rerender-lazy-state-init — src/modules/editor/ui/ColorPicker.tsx:46
useState(transformColor()) calls initializer on every render — use useState(() => transformColor()) for lazy initialization
41. [warning] no-derived-useState — src/modules/editor/ui/ColorPicker.tsx:47
useState initialized from prop "color" — if this value should stay in sync with the prop, derive it during render instead
42. [warning] no-prop-callback-in-effect — src/modules/editor/ui/ColorPicker.tsx:95
useEffect calls prop callback "onChange" 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
43. [warning] click-events-have-key-events — src/modules/editor/plugins/CommentPlugin/index.tsx:570
Enforce a clickable non-interactive element has at least one keyboard event listener.
44. [warning] js-batch-dom-css — src/modules/editor/plugins/CommentPlugin/index.tsx:86
Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows
45. [warning] advanced-event-handler-refs — src/modules/editor/plugins/CommentPlugin/index.tsx:90
useEffect re-subscribes a "updatePosition" listener every time the handler identity changes — store the handler in a ref and have the listener read `handlerRef.current()`, then drop it from the deps
46. [warning] js-batch-dom-css — src/modules/editor/plugins/CommentPlugin/index.tsx:237
Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows
47. [warning] advanced-event-handler-refs — src/modules/editor/plugins/CommentPlugin/index.tsx:283
useEffect re-subscribes a "updateLocation" 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
48. [warning] rerender-state-only-in-handlers — src/modules/editor/plugins/CommentPlugin/index.tsx:511
useState "counter" is updated but never read in the component's return — use useRef so updates don't trigger re-renders
49. [warning] js-hoist-intl — src/modules/editor/plugins/CommentPlugin/index.tsx:515
new Intl.RelativeTimeFormat() inside a function — hoist to module scope or wrap in useMemo so it isn't recreated each call
50. [warning] rerender-functional-setstate — src/modules/editor/plugins/CommentPlugin/index.tsx:526
setCounter(counter + ...) — use functional update to avoid stale closures
51. [warning] no-effect-event-handler — src/modules/editor/plugins/CommentPlugin/index.tsx:696
useEffect simulating an event handler — move logic to an actual event handler instead
52. [warning] no-prop-callback-in-effect — src/modules/editor/plugins/CommentPlugin/index.tsx:698
useEffect calls prop callback "providerFactory" 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
53. [warning] no-cascading-set-state — src/modules/editor/plugins/CommentPlugin/index.tsx:797
6 setState calls in a single useEffect — consider using useReducer or deriving state
54. [warning] client-passive-event-listeners — src/modules/editor/utils/swipe.ts:52
"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())
55. [warning] client-passive-event-listeners — src/modules/editor/utils/swipe.ts:53
"touchend" listener without { passive: true } — blocks scrolling performance. Only add { passive: true } if the handler does NOT call event.preventDefault() (passive listeners silently ignore preventDefault())
56. [warning] js-batch-dom-css — src/modules/editor/utils/setFloatingElemPositionForLinkEditor.ts:45
Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows
57. [warning] js-batch-dom-css — src/modules/editor/utils/setFloatingElemPositionForLinkEditor.ts:22
Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows
58. [warning] js-batch-dom-css — src/modules/editor/utils/setFloatingElemPosition.ts:50
Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows
59. [warning] js-batch-dom-css — src/modules/editor/utils/setFloatingElemPosition.ts:23
Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows
60. [warning] click-events-have-key-events — src/modules/editor/plugins/FloatingLinkEditorPlugin/index.tsx:233
Enforce a clickable non-interactive element has at least one keyboard event listener.
61. [warning] click-events-have-key-events — src/modules/editor/plugins/FloatingLinkEditorPlugin/index.tsx:243
Enforce a clickable non-interactive element has at least one keyboard event listener.
62. [warning] click-events-have-key-events — src/modules/editor/plugins/FloatingLinkEditorPlugin/index.tsx:260
Enforce a clickable non-interactive element has at least one keyboard event listener.
63. [warning] click-events-have-key-events — src/modules/editor/plugins/FloatingLinkEditorPlugin/index.tsx:270
Enforce a clickable non-interactive element has at least one keyboard event listener.
64. [warning] client-passive-event-listeners — src/modules/editor/plugins/FloatingLinkEditorPlugin/index.tsx:127
"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())
65. [warning] no-cascading-set-state — src/modules/editor/plugins/FloatingLinkEditorPlugin/index.tsx:294
4 setState calls in a single useEffect — consider using useReducer or deriving state
66. [warning] no-full-lodash-import — src/modules/editor/plugins/CodeActionMenuPlugin/utils.ts:8
Importing entire lodash library — import from 'lodash/functionName' instead
67. [warning] rerender-state-only-in-handlers — src/modules/editor/plugins/CodeActionMenuPlugin/index.tsx:43
useState "shouldListenMouseMove" is updated but never read in the component's return — use useRef so updates don't trigger re-renders
68. [warning] advanced-event-handler-refs — src/modules/editor/plugins/CodeActionMenuPlugin/index.tsx:98
useEffect re-subscribes a "debouncedOnMouseMove" 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
69. [warning] js-set-map-lookups — src/modules/editor/commenting/index.ts:190
array.indexOf() in a loop is O(n) per call — convert to a Set for O(1) lookups
70. [warning] js-index-maps — src/modules/editor/commenting/index.ts:351
array.find() in a loop is O(n*m) — build a Map for O(1) lookups
71. [warning] rerender-lazy-state-init — src/modules/editor/commenting/index.ts:446
useState(getComments()) calls initializer on every render — use useState(() => getComments()) for lazy initialization
72. [warning] no-generic-handler-names — src/modules/editor/plugins/CodeActionMenuPlugin/components/PrettierButton/index.tsx:138
Non-descriptive handler name "handleClick" — name should describe what it does, not when it runs
73. [warning] no-generic-handler-names — src/modules/editor/plugins/CodeActionMenuPlugin/components/CopyButton/index.tsx:61
Non-descriptive handler name "handleClick" — name should describe what it does, not when it runs
74. [warning] click-events-have-key-events — src/modules/editor/plugins/AutoEmbedPlugin/index.tsx:175
Enforce a clickable non-interactive element has at least one keyboard event listener.
75. [warning] no-effect-event-handler — src/modules/editor/plugins/PasteLogPlugin/index.tsx:19
useEffect simulating an event handler — move logic to an actual event handler instead
76. [warning] no-many-boolean-props — src/modules/editor/plugins/FloatingTextFormatToolbarPlugin/index.tsx:41
Component "TextFormatFloatingToolbar" takes 5 boolean-like props (isLink, isBold, isItalic…) — consider compound components or explicit variants instead of stacking flags
77. [warning] client-passive-event-listeners — src/modules/editor/plugins/FloatingTextFormatToolbarPlugin/index.tsx:148
"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())
78. [warning] advanced-event-handler-refs — src/modules/editor/plugins/FloatingTextFormatToolbarPlugin/index.tsx:354
useEffect re-subscribes a "updatePopup" 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] prefer-useReducer — src/modules/editor/plugins/ToolbarPlugin/index.tsx:538
Component "ToolbarPlugin" has 23 useState calls — consider useReducer for related state
80. [warning] no-giant-component — src/modules/editor/plugins/ToolbarPlugin/index.tsx:534
Component "ToolbarPlugin" is 758 lines — consider breaking it into smaller focused components
81. [warning] no-cascading-set-state — src/modules/editor/plugins/ToolbarPlugin/index.tsx:710
3 setState calls in a single useEffect — consider using useReducer or deriving state
82. [warning] click-events-have-key-events — src/modules/editor/plugins/TableOfContentsPlugin/index.tsx:132
Enforce a clickable non-interactive element has at least one keyboard event listener.
83. [warning] click-events-have-key-events — src/modules/editor/plugins/TableOfContentsPlugin/index.tsx:151
Enforce a clickable non-interactive element has at least one keyboard event listener.
84. [warning] no-cascading-set-state — src/modules/editor/plugins/TableOfContentsPlugin/index.tsx:59
3 setState calls in a single useEffect — consider using useReducer or deriving state
85. [warning] client-passive-event-listeners — src/modules/editor/plugins/TableOfContentsPlugin/index.tsx:121
"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())
86. [warning] click-events-have-key-events — src/modules/editor/plugins/MentionsPlugin/index.tsx:591
Enforce a clickable non-interactive element has at least one keyboard event listener.
87. [warning] no-cascading-set-state — src/modules/editor/plugins/MentionsPlugin/index.tsx:507
3 setState calls in a single useEffect — consider using useReducer or deriving state
88. [warning] no-mirror-prop-effect — src/modules/editor/plugins/ToolbarPlugin/fontSize.tsx:185
useState "inputValue" is mirrored from prop "selectionFontSize" via this effect — delete both the useState and the effect, and read the prop directly in render
89. [warning] no-derived-useState — src/modules/editor/plugins/ToolbarPlugin/fontSize.tsx:35
useState initialized from prop "selectionFontSize" — if this value should stay in sync with the prop, derive it during render instead
90. [warning] no-derived-state-effect — src/modules/editor/plugins/ToolbarPlugin/fontSize.tsx:185
Derived state in useEffect — compute during render instead
91. [warning] rerender-state-only-in-handlers — src/modules/editor/plugins/TableHoverActionsPlugin/index.tsx:39
useState "shouldListenMouseMove" is updated but never read in the component's return — use useRef so updates don't trigger re-renders
92. [warning] advanced-event-handler-refs — src/modules/editor/plugins/TableHoverActionsPlugin/index.tsx:134
useEffect re-subscribes a "debouncedOnMouseMove" 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
93. [warning] js-batch-dom-css — src/modules/editor/plugins/TestRecorderPlugin/index.tsx:22
Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows
94. [warning] js-set-map-lookups — src/modules/editor/plugins/TestRecorderPlugin/index.tsx:123
array.indexOf() in a loop is O(n) per call — convert to a Set for O(1) lookups
95. [warning] no-effect-event-handler — src/modules/editor/plugins/TestRecorderPlugin/index.tsx:298
useEffect simulating an event handler — move logic to an actual event handler instead
96. [warning] no-static-element-interactions — src/modules/editor/plugins/TableCellResizer/index.tsx:409
Static HTML elements with event handlers require a role.
97. [warning] no-static-element-interactions — src/modules/editor/plugins/TableCellResizer/index.tsx:414
Static HTML elements with event handlers require a role.
98. [warning] no-giant-component — src/modules/editor/plugins/TableCellResizer/index.tsx:47
Component "TableCellResizer" is 377 lines — consider breaking it into smaller focused components
99. [warning] no-cascading-set-state — src/modules/editor/plugins/TableCellResizer/index.tsx:87
3 setState calls in a single useEffect — consider using useReducer or deriving state
100. [warning] no-react19-deprecated-apis — src/modules/editor/plugins/TablePlugin/TablePlugin.tsx:25
useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`
101. [warning] click-events-have-key-events — src/modules/editor/plugins/TableActionMenuPlugin/index.tsx:473
Enforce a clickable non-interactive element has at least one keyboard event listener.
102. [warning] prefer-useReducer — src/modules/editor/plugins/TableActionMenuPlugin/index.tsx:124
Component "TableActionMenu" has 5 useState calls — consider useReducer for related state
103. [warning] rerender-state-only-in-handlers — src/modules/editor/plugins/TableActionMenuPlugin/index.tsx:132
useState "canMergeCells" is updated but never read in the component's return — use useRef so updates don't trigger re-renders
104. [warning] rerender-state-only-in-handlers — src/modules/editor/plugins/TableActionMenuPlugin/index.tsx:133
useState "canUnmergeCell" is updated but never read in the component's return — use useRef so updates don't trigger re-renders
105. [warning] no-giant-component — src/modules/editor/plugins/TableActionMenuPlugin/index.tsx:117
Component "TableActionMenu" is 480 lines — consider breaking it into smaller focused components
106. [warning] no-derived-useState — src/modules/editor/plugins/TableActionMenuPlugin/index.tsx:127
useState initialized from prop "_tableCellNode" — if this value should stay in sync with the prop, derive it during render instead
107. [warning] js-batch-dom-css — src/modules/editor/plugins/TableActionMenuPlugin/index.tsx:679
Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows
108. [warning] js-batch-dom-css — src/modules/editor/plugins/TableActionMenuPlugin/index.tsx:682
Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows
109. [warning] no-react19-deprecated-apis — src/modules/editor/plugins/TablePlugin.tsx:25
useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`
110. [warning] rendering-conditional-render — src/modules/editor/components/editor/editor.tsx:374
Conditional rendering with a numeric value can render '0' — use `value > 0`, `Boolean(value)`, or a ternary
111. [warning] no-derived-useState — src/modules/editor/nodes/EquationComponent.tsx:39
useState initialized from prop "equation" — if this value should stay in sync with the prop, derive it during render instead
112. [warning] no-effect-event-handler — src/modules/editor/nodes/EquationComponent.tsx:65
useEffect simulating an event handler — move logic to an actual event handler instead
113. [warning] rerender-state-only-in-handlers — src/modules/editor/plugins/SpeechToTextPlugin/index.ts:50
useState "isEnabled" is updated but never read in the component's return — use useRef so updates don't trigger re-renders
114. [warning] rerender-lazy-state-init — src/modules/editor/nodes/InlineImageNode/InlineImageComponent.tsx:109
useState(getAltText()) calls initializer on every render — use useState(() => getAltText()) for lazy initialization
115. [warning] rerender-lazy-state-init — src/modules/editor/nodes/InlineImageNode/InlineImageComponent.tsx:110
useState(getShowCaption()) calls initializer on every render — use useState(() => getShowCaption()) for lazy initialization
116. [warning] rerender-lazy-state-init — src/modules/editor/nodes/InlineImageNode/InlineImageComponent.tsx:111
useState(getPosition()) calls initializer on every render — use useState(() => getPosition()) for lazy initialization
117. [warning] no-cascading-set-state — src/modules/editor/nodes/InlineImageNode/InlineImageComponent.tsx:275
3 setState calls in a single useEffect — consider using useReducer or deriving state
118. [warning] no-react19-deprecated-apis — src/modules/editor/context/SharedHistoryContext.tsx:13
useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`
119. [warning] js-batch-dom-css — src/modules/editor/hooks/useReport.ts:18
Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows
120. [warning] js-batch-dom-css — src/modules/editor/hooks/useReport.ts:19
Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows
121. [warning] js-batch-dom-css — src/modules/editor/hooks/useReport.ts:20
Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows
122. [warning] js-batch-dom-css — src/modules/editor/hooks/useReport.ts:21
Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows
123. [warning] js-batch-dom-css — src/modules/editor/hooks/useReport.ts:22
Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows
124. [warning] js-batch-dom-css — src/modules/editor/hooks/useReport.ts:23
Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows
125. [warning] js-batch-dom-css — src/modules/editor/hooks/useReport.ts:24
Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows
126. [warning] no-giant-component — src/modules/editor/nodes/ImageComponent.tsx:138
Component "ImageComponent" is 311 lines — consider breaking it into smaller focused components
127. [warning] advanced-event-handler-refs — src/modules/editor/nodes/ImageComponent.tsx:273
useEffect re-subscribes a "onRightClick" 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
128. [warning] no-react19-deprecated-apis — src/modules/editor/context/SharedAutocompleteContext.tsx:13
useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`
129. [warning] iframe-has-title — src/modules/editor/nodes/FigmaNode.tsx:45
Missing `title` attribute for the `iframe` element.
130. [warning] no-react19-deprecated-apis — src/modules/editor/context/SettingsContext.tsx:12
useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`
131. [warning] js-batch-dom-css — src/modules/editor/nodes/ExcalidrawNode/index.tsx:142
Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows
132. [warning] no-react19-deprecated-apis — src/modules/editor/context/FlashMessageContext.tsx:9
useContext is superseded by `use()` on React 19+ — `use()` reads context conditionally inside hooks, branches, and loops; switch to `import { use } from 'react'`
133. [warning] no-effect-event-handler — src/modules/editor/context/FlashMessageContext.tsx:30
useEffect simulating an event handler — move logic to an actual event handler instead
134. [warning] no-danger — src/modules/editor/nodes/ExcalidrawNode/ExcalidrawImage.tsx:129
Do not use `dangerouslySetInnerHTML` prop
135. [warning] no-derived-useState — src/modules/editor/nodes/ExcalidrawNode/ExcalidrawModal.tsx:92
useState initialized from prop "initialElements" — if this value should stay in sync with the prop, derive it during render instead
136. [warning] no-derived-useState — src/modules/editor/nodes/ExcalidrawNode/ExcalidrawModal.tsx:93
useState initialized from prop "initialFiles" — if this value should stay in sync with the prop, derive it during render instead
137. [warning] click-events-have-key-events — src/modules/editor/nodes/ExcalidrawNode/ExcalidrawComponent.tsx:227
Enforce a clickable non-interactive element has at least one keyboard event listener.
138. [warning] no-effect-event-handler — src/modules/editor/nodes/ExcalidrawNode/ExcalidrawComponent.tsx:65
useEffect simulating an event handler — move logic to an actual event handler instead
139. [warning] no-render-in-render — src/app/App.tsx:23
Inline render function "renderRoutes()" — extract to a separate component for proper reconciliation
140. [warning] no-cascading-set-state — src/modules/editor/plugins/ActionsPlugin/index.tsx:137
3 setState calls in a single useEffect — consider using useReducer or deriving state
141. [warning] rendering-hydration-mismatch-time — src/modules/editor/plugins/ActionsPlugin/index.tsx:228
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❌ Errors (8)
alt-text
Missing alt attribute.
Must have
altprop, either with meaningful text, or an empty string for decorative images.
src/modules/shared/components/Sidebar/Sidebar.tsx:17
src/modules/shared/components/Sidebar/Sidebar.tsx:17
src/modules/editor/nodes/ImageComponent.tsx:126
effect-needs-cleanup
useEffect schedules setTimeout(...) but never returns a cleanup — leaks the registration on every re-run and on unmount. Return a cleanup function that calls clearTimeout(...)
Return a cleanup function that releases the subscription / timer:
return () => target.removeEventListener(name, handler)for listeners,return () => clearInterval(id)/clearTimeout(id)for timers, orreturn unsubscribeif the subscribe call already returned one
src/modules/editor/plugins/TableCellResizer/index.tsx:87
src/modules/editor/plugins/SpeechToTextPlugin/index.ts:57
src/modules/editor/nodes/StickyComponent.tsx:133
jsx-key
Missing "key" prop for element in iterator.
Add a "key" prop to the element in the iterator (https://react.dev/learn/rendering-lists#keeping-list-items-in-order-with-key).
src/modules/editor/plugins/MentionsPlugin/index.tsx:621
no-nested-component-definition
Component "ShowDiscardDialog" defined inside "ExcalidrawModal" — creates new instance every render, destroying state
Move to a separate file or to module scope above the parent component
src/modules/editor/nodes/ExcalidrawNode/ExcalidrawModal.tsx:183
⚠️ Warnings (133)
click-events-have-key-events
Enforce a clickable non-interactive element has at least one keyboard event listener.
Visible, non-interactive elements with click handlers must have one of
keyup,keydown, orkeypresslistener.
src/modules/editor/plugins/EmojiPickerPlugin/index.tsx:60
src/modules/editor/plugins/ContextMenuPlugin/index.tsx:43
src/modules/editor/plugins/ComponentPickerPlugin/index.tsx:101
src/modules/shared/components/Navbar/Navbar.tsx:108
src/modules/shared/components/Navbar/Navbar.tsx:116
src/modules/shared/components/Navbar/Navbar.tsx:125
src/modules/shared/components/Input/Input.tsx:69
src/modules/shared/components/DropDown/DropDown.tsx:48
src/modules/dashboard/features/Test.tsx:18
src/modules/editor/plugins/CommentPlugin/index.tsx:570
src/modules/editor/plugins/FloatingLinkEditorPlugin/index.tsx:233
src/modules/editor/plugins/FloatingLinkEditorPlugin/index.tsx:243
src/modules/editor/plugins/FloatingLinkEditorPlugin/index.tsx:260
src/modules/editor/plugins/FloatingLinkEditorPlugin/index.tsx:270
src/modules/editor/plugins/AutoEmbedPlugin/index.tsx:175
src/modules/editor/plugins/TableOfContentsPlugin/index.tsx:132
src/modules/editor/plugins/TableOfContentsPlugin/index.tsx:151
src/modules/editor/plugins/MentionsPlugin/index.tsx:591
src/modules/editor/plugins/TableActionMenuPlugin/index.tsx:473
src/modules/editor/nodes/ExcalidrawNode/ExcalidrawComponent.tsx:227
js-batch-dom-css
Multiple sequential element.style assignments — batch with cssText or classList for fewer reflows
Batch DOM/CSS reads and writes — interleaving them inside a loop causes layout thrashing. Read first, then write
src/modules/editor/ui/ImageResizer.tsx:169
src/modules/editor/ui/ImageResizer.tsx:199
src/modules/editor/ui/DropDown.tsx:171
src/modules/editor/plugins/CommentPlugin/index.tsx:86
src/modules/editor/plugins/CommentPlugin/index.tsx:237
src/modules/editor/utils/setFloatingElemPositionForLinkEditor.ts:45
src/modules/editor/utils/setFloatingElemPositionForLinkEditor.ts:22
src/modules/editor/utils/setFloatingElemPosition.ts:50
src/modules/editor/utils/setFloatingElemPosition.ts:23
src/modules/editor/plugins/TestRecorderPlugin/index.tsx:22
src/modules/editor/plugins/TableActionMenuPlugin/index.tsx:679
src/modules/editor/plugins/TableActionMenuPlugin/index.tsx:682
src/modules/editor/hooks/useReport.ts:18
src/modules/editor/hooks/useReport.ts:19
src/modules/editor/hooks/useReport.ts:20
src/modules/editor/hooks/useReport.ts:21
src/modules/editor/hooks/useReport.ts:22
src/modules/editor/hooks/useReport.ts:23
src/modules/editor/hooks/useReport.ts:24
src/modules/editor/nodes/ExcalidrawNode/index.tsx:142
no-react19-deprecated-apis
forwardRef is no longer needed on React 19+ — refs are regular props on function components; remove forwardRef and pass ref directly
Pass
refas a regular prop on function components —forwardRefis no longer needed in React 19+. ReplaceuseContext(X)withuse(X)for branch-aware context reads. Only enabled on projects detected as React 19+.
src/modules/editor/ui/EquationEditor.tsx:13
src/modules/editor/ui/DropDown.tsx:37
src/modules/editor/plugins/TablePlugin/TablePlugin.tsx:25
src/modules/editor/plugins/TablePlugin.tsx:25
src/modules/editor/context/SharedHistoryContext.tsx:13
src/modules/editor/context/SharedAutocompleteContext.tsx:13
src/modules/editor/context/SettingsContext.tsx:12
src/modules/editor/context/FlashMessageContext.tsx:9
no-cascading-set-state
6 setState calls in a single useEffect — consider using useReducer or deriving state
Combine into useReducer:
const [state, dispatch] = useReducer(reducer, initialState)
src/modules/editor/plugins/CommentPlugin/index.tsx:797
src/modules/editor/plugins/FloatingLinkEditorPlugin/index.tsx:294
src/modules/editor/plugins/ToolbarPlugin/index.tsx:710
src/modules/editor/plugins/TableOfContentsPlugin/index.tsx:59
src/modules/editor/plugins/MentionsPlugin/index.tsx:507
src/modules/editor/plugins/TableCellResizer/index.tsx:87
src/modules/editor/nodes/InlineImageNode/InlineImageComponent.tsx:275
src/modules/editor/plugins/ActionsPlugin/index.tsx:137
no-derived-useState
useState initialized from prop "initialEquation" — if this value should stay in sync with the prop, derive it during render instead
Remove useState and compute the value inline:
const value = transform(propName)
src/modules/editor/ui/KatexEquationAlterer.tsx:28
src/modules/editor/ui/ColorPicker.tsx:47
src/modules/editor/plugins/ToolbarPlugin/fontSize.tsx:35
src/modules/editor/plugins/TableActionMenuPlugin/index.tsx:127
src/modules/editor/nodes/EquationComponent.tsx:39
src/modules/editor/nodes/ExcalidrawNode/ExcalidrawModal.tsx:92
src/modules/editor/nodes/ExcalidrawNode/ExcalidrawModal.tsx:93
rerender-state-only-in-handlers
useState "highlightedItem" is updated but never read in the component's return — use useRef so updates don't trigger re-renders
Replace useState with useRef when the value is only mutated and never read in render —
ref.current = ...updates without re-rendering the component
src/modules/editor/ui/DropDown.tsx:68
src/modules/editor/plugins/CommentPlugin/index.tsx:511
src/modules/editor/plugins/CodeActionMenuPlugin/index.tsx:43
src/modules/editor/plugins/TableHoverActionsPlugin/index.tsx:39
src/modules/editor/plugins/TableActionMenuPlugin/index.tsx:132
src/modules/editor/plugins/TableActionMenuPlugin/index.tsx:133
src/modules/editor/plugins/SpeechToTextPlugin/index.ts:50
no-static-element-interactions
Static HTML elements with event handlers require a role.
Add a role attribute to this element, or use a semantic HTML element instead.
src/modules/shared/components/DropDown/DropDown.tsx:48
src/modules/dashboard/features/Test.tsx:18
src/modules/editor/ui/DropDown.tsx:127
src/modules/editor/ui/ColorPicker.tsx:211
src/modules/editor/plugins/TableCellResizer/index.tsx:409
src/modules/editor/plugins/TableCellResizer/index.tsx:414
client-passive-event-listeners
"scroll" listener without { passive: true } — blocks scrolling performance. Only add { passive: true } if the handler does NOT call event.preventDefault() (passive listeners silently ignore preventDefault())
Add
{ passive: true }as the third argument:addEventListener('scroll', handler, { passive: true }). Only do this if the handler does NOT callevent.preventDefault()— passive listeners silently ignorepreventDefault(), which breaks features like pull-to-refresh suppression, custom gestures, and nested-scroll containment.
src/modules/editor/ui/DropDown.tsx:213
src/modules/editor/utils/swipe.ts:52
src/modules/editor/utils/swipe.ts:53
src/modules/editor/plugins/FloatingLinkEditorPlugin/index.tsx:127
src/modules/editor/plugins/FloatingTextFormatToolbarPlugin/index.tsx:148
src/modules/editor/plugins/TableOfContentsPlugin/index.tsx:121
advanced-event-handler-refs
useEffect re-subscribes a "updatePosition" listener every time the handler identity changes — store the handler in a ref and have the listener read handlerRef.current(), then drop it from the deps
Store the handler in a ref and have the listener read
handlerRef.current()— the subscription stays put while the latest handler is always called
src/modules/editor/plugins/CommentPlugin/index.tsx:90
src/modules/editor/plugins/CommentPlugin/index.tsx:283
src/modules/editor/plugins/CodeActionMenuPlugin/index.tsx:98
src/modules/editor/plugins/FloatingTextFormatToolbarPlugin/index.tsx:354
src/modules/editor/plugins/TableHoverActionsPlugin/index.tsx:134
src/modules/editor/nodes/ImageComponent.tsx:273
no-effect-event-handler
useEffect simulating an event handler — move logic to an actual event handler instead
Move the conditional logic into onClick, onChange, or onSubmit handlers directly
src/modules/editor/plugins/CommentPlugin/index.tsx:696
src/modules/editor/plugins/PasteLogPlugin/index.tsx:19
src/modules/editor/plugins/TestRecorderPlugin/index.tsx:298
src/modules/editor/nodes/EquationComponent.tsx:65
src/modules/editor/context/FlashMessageContext.tsx:30
src/modules/editor/nodes/ExcalidrawNode/ExcalidrawComponent.tsx:65
rerender-lazy-state-init
useState(transformColor()) calls initializer on every render — use useState(() => transformColor()) for lazy initialization
Wrap in an arrow function so it only runs once:
useState(() => expensiveComputation())
src/modules/editor/ui/ColorPicker.tsx:46
src/modules/editor/commenting/index.ts:446
src/modules/editor/nodes/InlineImageNode/InlineImageComponent.tsx:109
src/modules/editor/nodes/InlineImageNode/InlineImageComponent.tsx:110
src/modules/editor/nodes/InlineImageNode/InlineImageComponent.tsx:111
no-giant-component
Component "ToolbarPlugin" is 758 lines — consider breaking it into smaller focused components
Extract logical sections into focused components:
<UserHeader />,<UserActions />, etc.
src/modules/editor/plugins/ToolbarPlugin/index.tsx:534
src/modules/editor/plugins/TableCellResizer/index.tsx:47
src/modules/editor/plugins/TableActionMenuPlugin/index.tsx:117
src/modules/editor/nodes/ImageComponent.tsx:138
no-array-index-as-key
Array index "index" used as key — causes bugs when list is reordered or filtered
Use a stable unique identifier:
key={item.id}orkey={item.slug}— index keys break on reorder/filter
src/modules/shared/components/SidebarItems/SidebarItems.tsx:19
src/modules/editor/plugins/ComponentPickerPlugin/index.tsx:342
src/modules/shared/routes/index.tsx:27
no-default-props
LazyLoad.defaultProps — React 19 removes defaultProps for function components and discourages it for class components. Move defaults into the destructured props parameter (e.g. function LazyLoad({ size = "md", ...rest })) so the rule applies cleanly to both shapes
React 19 removes
Component.defaultPropsfor function components. Move the defaults into the destructured props parameter:function Foo({ size = "md", variant = "primary" })instead ofFoo.defaultProps = { size: "md", variant: "primary" }.
src/modules/shared/components/LazyLoad/LazyLoad.tsx:24
src/modules/shared/components/Input/Input.tsx:90
src/modules/shared/components/Button/Button.tsx:67
async-await-in-loop
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
Collect the items and use
await Promise.all(items.map(...))to run independent operations concurrently
src/modules/editor/plugins/ContextMenuPlugin/index.tsx:136
src/modules/editor/utils/docSerialization.ts:17
no-prop-callback-in-effect
useEffect calls prop callback "onChange" with local state in deps — this is the "lift state via callback" anti-pattern; lift state into a shared Provider so both sides read the same source
Lift the shared state into a Provider so both sides read the same source — no useEffect-driven sync needed
src/modules/editor/ui/ColorPicker.tsx:95
src/modules/editor/plugins/CommentPlugin/index.tsx:698
js-set-map-lookups
array.indexOf() in a loop is O(n) per call — convert to a Set for O(1) lookups
Use a
SetorMapfor repeated membership tests / keyed lookups —Array.includes/findis O(n) per call
src/modules/editor/commenting/index.ts:190
src/modules/editor/plugins/TestRecorderPlugin/index.tsx:123
no-generic-handler-names
Non-descriptive handler name "handleClick" — name should describe what it does, not when it runs
Rename to describe the action: e.g.
handleSubmit→saveUserProfile,handleClick→toggleSidebar
src/modules/editor/plugins/CodeActionMenuPlugin/components/PrettierButton/index.tsx:138
src/modules/editor/plugins/CodeActionMenuPlugin/components/CopyButton/index.tsx:61
prefer-useReducer
Component "ToolbarPlugin" has 23 useState calls — consider useReducer for related state
Group related state:
const [state, dispatch] = useReducer(reducer, { field1, field2, ... })
src/modules/editor/plugins/ToolbarPlugin/index.tsx:538
src/modules/editor/plugins/TableActionMenuPlugin/index.tsx:124
no-autofocus
The autoFocus attribute is found here, which can cause usability issues for sighted and non-sighted users.
Remove the
autoFocusattribute.
src/modules/editor/ui/EquationEditor.tsx:36
no-effect-chain
useEffect reacts to "selfColor" 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
Compute as much as possible during render (e.g.
const isGameOver = round > 5) and write all related state inside the event handler that originally fires the chain. Each ef
Issue body truncated. See the full report at react.review/dashboard.
Activity
0No activity yet.