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 <noreply@paperclip.ing>
This commit is contained in:
dotta 2026-03-26 07:22:24 -05:00
parent e186449f94
commit 0a32e3838a

View file

@ -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,11 +560,12 @@ export const MarkdownEditor = forwardRef<MarkdownEditorRef, MarkdownEditorProps>
plugins={plugins}
/>
{/* Mention dropdown */}
{mentionActive && filteredMentions.length > 0 && (
{/* Mention dropdown — rendered via portal so it isn't clipped by overflow containers */}
{mentionActive && filteredMentions.length > 0 &&
createPortal(
<div
className="absolute z-50 min-w-[180px] max-h-[200px] overflow-y-auto rounded-md border border-border bg-popover shadow-md"
style={{ top: mentionState.top + 4, left: mentionState.left }}
className="fixed z-[9999] min-w-[180px] max-h-[200px] overflow-y-auto rounded-md border border-border bg-popover shadow-md"
style={{ top: mentionState.viewportTop + 4, left: mentionState.viewportLeft }}
>
{filteredMentions.map((option, i) => (
<button
@ -592,7 +599,8 @@ export const MarkdownEditor = forwardRef<MarkdownEditorRef, MarkdownEditorProps>
)}
</button>
))}
</div>
</div>,
document.body,
)}
{isDragOver && canDropImage && (