[PR #31066] fix(web): use portal for variable picker in code editor (Fixes #31063) #33074

Closed
opened 2026-02-21 20:52:37 -05:00 by yindo · 0 comments
Owner

Original Pull Request: https://github.com/langgenius/dify/pull/31066

State: closed
Merged: Yes


Important

  1. Make sure you have read our contribution guidelines
  2. Ensure there is an associated issue and you have been assigned to it
  3. Use the correct syntax to link this PR: Fixes #<issue number>.

Summary

Fixes the issue where clicking on variables in the Jinja mode code editor popup does not insert the variable on Chrome browser.

Fixes #31063

Problem

The variable picker popup was rendered inside the component's DOM tree. When clicking on the popup, Monaco Editor detected an "external click" which triggered focus change and cursor position reset, causing handleCursorPositionChange to unmount the popup before the click event could fire.

Why only User/Assistant Message is affected: These messages are wrapped in a ReactSortable component with a .handle class for drag-and-drop. SortableJS intercepts mousedown events on .handle elements, which interferes with Monaco Editor's focus handling. System Message doesn't have the .handle class (it's not draggable), so it's not affected.

This issue only occurs in Chrome/Chromium-based browsers due to differences in focus event timing. Firefox and Safari are not affected.

Solution

Use React's createPortal to render the variable picker popup to document.body, completely separating it from Monaco Editor's DOM tree. This prevents Monaco from detecting the click as an external event, keeping focus and cursor position stable so the click event fires correctly.

Screenshots

Before After
Clicking variable in popup does nothing on Chrome Variable is correctly inserted when clicking image

Checklist

  • This change requires a documentation update, included: Dify Document
  • I understand that this PR may be closed in case there was no previous discussion or issues. (This doesn't apply to typos!)
  • I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change.
  • I've updated the documentation accordingly.
  • I ran make lint and make type-check (backend) and cd web && npx lint-staged (frontend) to appease the lint gods

Testing

  1. Use Chrome
  2. Open Workflow configuration page
  3. Create or edit an LLM node
  4. Enable Jinja mode in User or Assistant Message area
  5. Type / to trigger variable picker popup
  6. Click on any variable
  7. Variable is correctly inserted, replacing / with {{ variable_name }}
  8. Also verified System Message still works correctly
**Original Pull Request:** https://github.com/langgenius/dify/pull/31066 **State:** closed **Merged:** Yes --- > [!IMPORTANT] > > 1. Make sure you have read our [contribution guidelines](https://github.com/langgenius/dify/blob/main/CONTRIBUTING.md) > 1. Ensure there is an associated issue and you have been assigned to it > 1. Use the correct syntax to link this PR: `Fixes #<issue number>`. ## Summary Fixes the issue where clicking on variables in the Jinja mode code editor popup does not insert the variable on Chrome browser. Fixes #31063 ### Problem The variable picker popup was rendered inside the component's DOM tree. When clicking on the popup, Monaco Editor detected an "external click" which triggered focus change and cursor position reset, causing `handleCursorPositionChange` to unmount the popup before the `click` event could fire. **Why only User/Assistant Message is affected:** These messages are wrapped in a `ReactSortable` component with a `.handle` class for drag-and-drop. SortableJS intercepts `mousedown` events on `.handle` elements, which interferes with Monaco Editor's focus handling. System Message doesn't have the `.handle` class (it's not draggable), so it's not affected. This issue only occurs in Chrome/Chromium-based browsers due to differences in focus event timing. Firefox and Safari are not affected. ### Solution Use React's `createPortal` to render the variable picker popup to `document.body`, completely separating it from Monaco Editor's DOM tree. This prevents Monaco from detecting the click as an external event, keeping focus and cursor position stable so the `click` event fires correctly. ## Screenshots | Before | After | |--------|-------| | Clicking variable in popup does nothing on Chrome | Variable is correctly inserted when clicking <img width="602" height="182" alt="image" src="https://github.com/user-attachments/assets/0f8c9ef8-69f7-4b88-bd9f-e0101b3e4c4c" />| ## Checklist - [ ] This change requires a documentation update, included: [Dify Document](https://github.com/langgenius/dify-docs) - [x] I understand that this PR may be closed in case there was no previous discussion or issues. (This doesn't apply to typos!) - [x] I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change. - [x] I've updated the documentation accordingly. - [x] I ran `make lint` and `make type-check` (backend) and `cd web && npx lint-staged` (frontend) to appease the lint gods ## Testing 0. Use Chrome 1. Open Workflow configuration page 2. Create or edit an LLM node 3. Enable Jinja mode in User or Assistant Message area 4. Type `/` to trigger variable picker popup 5. Click on any variable 6. ✅ Variable is correctly inserted, replacing `/` with `{{ variable_name }}` 7. Also verified System Message still works correctly
yindo added the pull-request label 2026-02-21 20:52:37 -05:00
yindo closed this issue 2026-02-21 20:52:37 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langgenius/dify#33074