From 0fd75aa579a56babc8d5d310201058d0518e30bd Mon Sep 17 00:00:00 2001 From: dotta Date: Thu, 26 Mar 2026 07:22:24 -0500 Subject: [PATCH] fix: render mention autocomplete via portal to prevent overflow clipping The mention suggestion dropdown was getting clipped when typing at the end of a long description inside modals/dialogs because parent containers had overflow-y-auto. Render it via createPortal to document.body with fixed positioning and z-index 9999 so it always appears above all UI. Co-Authored-By: Paperclip --- ui/src/components/MarkdownEditor.tsx | 88 +++++++++++++++------------- 1 file changed, 48 insertions(+), 40 deletions(-) diff --git a/ui/src/components/MarkdownEditor.tsx b/ui/src/components/MarkdownEditor.tsx index 342a74de..68469761 100644 --- a/ui/src/components/MarkdownEditor.tsx +++ b/ui/src/components/MarkdownEditor.tsx @@ -8,6 +8,7 @@ import { useState, type DragEvent, } from "react"; +import { createPortal } from "react-dom"; import { CodeMirrorEditor, MDXEditor, @@ -82,6 +83,9 @@ interface MentionState { query: string; top: number; left: number; + /** Viewport-relative coords for portal positioning */ + viewportTop: number; + viewportLeft: number; textNode: Text; atPos: number; endPos: number; @@ -155,6 +159,8 @@ function detectMention(container: HTMLElement): MentionState | null { query, top: rect.bottom - containerRect.top, left: rect.left - containerRect.left, + viewportTop: rect.bottom, + viewportLeft: rect.left, textNode: textNode as Text, atPos, endPos: offset, @@ -554,46 +560,48 @@ export const MarkdownEditor = forwardRef plugins={plugins} /> - {/* Mention dropdown */} - {mentionActive && filteredMentions.length > 0 && ( -
- {filteredMentions.map((option, i) => ( - - ))} -
- )} + {/* Mention dropdown — rendered via portal so it isn't clipped by overflow containers */} + {mentionActive && filteredMentions.length > 0 && + createPortal( +
+ {filteredMentions.map((option, i) => ( + + ))} +
, + document.body, + )} {isDragOver && canDropImage && (