fix(web): render in-context editor in browser top layer#3519
Conversation
The in-context editor (Quick translation modal) was rendered via MUI's Dialog, which lives in the normal stacking context. When a host page opened a translation key inside a modal <dialog> via showModal(), the host dialog was promoted to the browser top layer and painted above the editor regardless of z-index, and its focus scope kept stealing keystrokes from the editor's inputs. Wrap the existing MUI Dialog in a native <dialog> and call showModal() on mount. That promotes the editor to the same top layer as any host modal, and because the top layer is a stack, the most-recently-shown modal paints on top and receives focus. Native dialog UA defaults are neutralised via GlobalStyles (full viewport, transparent backdrop, pointer-events fall through to MUI's own backdrop). The native cancel event is preventDefault'd so the existing Escape handler in dialogContext remains the single source of truth for closing. The browser-window mode is untouched. A "Translation inside dialog" example is added to the React testapp's TranslationMethods page so the scenario is reproducible going forward.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
WalkthroughThe PR adds native HTML ChangesNative HTML Dialog Implementation
Sequence DiagramsequenceDiagram
participant User
participant DialogButton
participant NativeDialog
participant CancelHandler
User->>DialogButton: Click open button
DialogButton->>NativeDialog: showModal()
NativeDialog->>CancelHandler: attach cancel event listener
User->>NativeDialog: Trigger cancel (e.g., Escape key)
NativeDialog->>CancelHandler: dispatch cancel event
CancelHandler->>CancelHandler: preventDefault()
CancelHandler->>NativeDialog: close() [if needed]
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@dkrizan for some reason And another note. Seems like tooltips stopped working - they're shown behind the popup window:
|
bdshadow
left a comment
There was a problem hiding this comment.
check 2 notes in the previous comment (this comment is to "Request changes" when submitting review - doesn't go without a comment)

Problem
When a translation key sits inside a native
<dialog>opened withshowModal(), alt-clicking it opens the Tolgee Quick translation editor — but the host dialog paints on top of the editor and steals focus from its inputs. The editor becomes unusable: you can see the form behind the host dialog, but you can't type into it.Repro on this branch:
testapps/react→/translation-methods→ "Open dialog" → alt-click the translation inside.Cause
A modal
<dialog>element (one opened via.showModal()) is promoted to the browser's top layer, a special render layer that sits above the entire normal stacking context.z-indexcannot reach the top layer, and the dialog enforces a focus scope.The in-context editor was rendered via MUI's
<Dialog>(packages/web/src/package/ui/KeyDialog/TranslationDialogWrapper.tsx) — a portal'd<div>withzIndex: DEVTOOLS_Z_INDEX. No matter how large that z-index is, a host modal<dialog>paints above it.Solution
Wrap the existing MUI
<Dialog>in a native<dialog>element and callshowModal()on mount. That promotes the editor into the same top layer as any host modal. The top layer behaves like a stack — the most-recently-shown modal paints above earlier ones and receives focus — so the editor now overlays the host dialog and takes focus from it.Implementation notes:
<dialog>UA defaults (border, padding, centred sizing) are flattened viaGlobalStyles. The native::backdropis set transparent because MUI's own backdrop continues to provide the dim overlay.pointer-events: noneon the native<dialog>withpointer-events: autoon its children lets MUI's backdrop keep handling outside-click-to-close.cancelevent (Escape) ispreventDefault-ed so the existing Escape handler indialogContextremains the single source of truth for closing.useBrowserWindowpath (open editor in a detached window) is untouched.<dialog>inside shadow DOM is still promoted to the document's top layer.Test plan
testapps/reactat/translation-methods, open the new "Translation inside dialog" example and alt-click the key inside — Quick translation editor paints above the host<dialog>and the English input receives focus.useBrowserWindowpath) still works.<dialog>so its own focus trap resumes.Summary by CodeRabbit