anvil: stale closure in click handler captures drag state at mount time - canvas clicks not suppressed during active widget drag
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 78/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Quiet
- Tech stack
- react, typescript
- Domain
- frontend
Research direction
Start in app/client/src/layoutSystems/anvil/editor/canvas/AnvilEditorCanvas.tsx and trace handleOnClickCapture into hooks/useClickToClearSelections.ts. Reproduce a widget drag followed by a canvas click, then verify the registered handler uses current drag, resize, and space-distribution state and does not trigger selection or property-pane actions during the drag.
Written by the indexing model from the issue text.
Description
Bug Description
AnvilEditorCanvas registers a click handler via ddEventListener in a useEffect with an empty dependency array ([]). The handler closes over drag/resize state values from Redux. Because the effect never re-runs, the handler always uses the state captured at mount time. When drag state changes, the click guard reads stale values and fails to suppress canvas clicks during active drag operations.
Affected files
pp/client/src/layoutSystems/anvil/editor/canvas/AnvilEditorCanvas.tsx, lines 47-53:
ypescript useEffect(() => { canvasRef.current?.addEventListener("click", handleOnClickCapture); return () => { canvasRef.current?.removeEventListener("click", handleOnClickCapture); }; }, []); // empty deps - handler never updated
pp/client/src/layoutSystems/anvil/editor/canvas/hooks/useClickToClearSelections.ts, lines 18-31:
` ypescript
const isDragging = useSelector(state => state.ui.widgetDragResize.isDragging);
const isCanvasResizing = useSelector(state => state.ui.widgetDragResize.isAutoCanvasResizing);
const isDistributingSpace = useSelector(getAnvilSpaceDistributionStatus);
return (e) => {
if (!(isDragging || isCanvasResizing || isDistributingSpace)) { // stale values
goToWidgetAdd();
focusWidget(widgetId);
showPropertyPane();
e.preventDefault();
}
};
`
Failure scenario
- User opens the Anvil editor. At mount, isDragging = false.
- User starts dragging a widget. Redux updates isDragging = true.
- useClickToClearSelections returns a new function with the updated value.
- useCallback creates a new handleOnClickCapture reference.
- The useEffect with [] deps does NOT re-run - the old handler (with isDragging = false) remains registered.
- User clicks the canvas during the drag.
- The stale handler sees isDragging = false, passes the guard, and calls goToWidgetAdd(), ocusWidget(), and showPropertyPane().
- Widget selection is disrupted mid-drag. The property pane jumps to a different widget. The drag may be cancelled unexpectedly.
Fix
Add handleOnClickCapture to the dependency array, or use a ref to hold the latest handler:
` ypescript
const handleOnClickCaptureRef = useRef(handleOnClickCapture);
useEffect(() => { handleOnClickCaptureRef.current = handleOnClickCapture; });
useEffect(() => {
const handler = (e: MouseEvent) => handleOnClickCaptureRef.current(e);
canvasRef.current?.addEventListener("click", handler);
return () => { canvasRef.current?.removeEventListener("click", handler); };
}, []);
`
Environment
Appsmith elease branch (2026-08-13), React 18.
- Dominant language
- TypeScript
- Stars
- 40.9k
- Forks
- 4.8k
- Avg merge
- 1d 12h
- Merged PRs (30d)
- 47
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from appsmithorg/appsmith
-
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
appsmithorg/appsmith#42115 · 1 comment ·
-
close-labeler workflow uses break instead of continue, dropping the QA label on multi-issue PRs OpenContributor Expressed Interest
Difficulty 1/5 Under an hour Newbie friendliness 88/100
appsmithorg/appsmith#41983 · 2 comments ·
-
Contributor Expressed Interest
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
appsmithorg/appsmith#41876 · 2 comments ·
-
Frontend Good First Issue Integrations Pod General Integrations Product Medium Production Query & JS Pod Query Widgets & IDE Pod REST API plugin Task
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
appsmithorg/appsmith#31059 · 23 comments ·
-
Difficulty 3/5 1-2 days Newbie friendliness 72/100
appsmithorg/appsmith#42267 · 1 comment ·
All issues in appsmithorg/appsmith
Similar issues
-
calcite-components needs triage refactor
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
Esri/calcite-design-system#15203 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 91/100
-
community first-timers-only good first issue hacktoberfest help wanted low hanging fruit up-for-grabs
Difficulty 1/5 Under an hour Newbie friendliness 95/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Automattic/studio#4908 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 90/100