From e6b6b5b9f3a7c51c6f55c3141136d980b29fc680 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Djalma=20Ara=C3=BAjo?= Date: Tue, 23 Jun 2026 16:21:41 -0300 Subject: [PATCH 1/2] [Bug Fix] DropdownMenu: fix z-index stacking and default placement (#439) - Default placement changed from `top` to `bottom` so menus open below their trigger (matches dropdown convention). - Removed the static `z-50` from the DropdownMenu container; the controller now sets z-index only while open, so closed sibling dropdowns no longer cover an open menu (they share the same z-50 and DOM order decided paint order). - Dropped `w-full` from the Usage demo trigger so the floating reference matches the visible button instead of a full-width wrapper. --- .../controllers/ruby_ui/dropdown_menu_controller.js | 6 +++++- docs/app/views/docs/dropdown_menu.rb | 4 ++-- gem/lib/ruby_ui/dropdown_menu/dropdown_menu.rb | 1 - gem/lib/ruby_ui/dropdown_menu/dropdown_menu_controller.js | 6 +++++- gem/lib/ruby_ui/dropdown_menu/dropdown_menu_docs.rb | 2 +- 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/docs/app/javascript/controllers/ruby_ui/dropdown_menu_controller.js b/docs/app/javascript/controllers/ruby_ui/dropdown_menu_controller.js index d624eaf5b..6479c8442 100644 --- a/docs/app/javascript/controllers/ruby_ui/dropdown_menu_controller.js +++ b/docs/app/javascript/controllers/ruby_ui/dropdown_menu_controller.js @@ -43,7 +43,7 @@ export default class extends Controller { #computeTooltip() { computePosition(this.triggerTarget, this.contentTarget, { - placement: this.optionsValue.placement || "top", + placement: this.optionsValue.placement || "bottom", middleware: [flip(), shift(), offset(8)], strategy: this.optionsValue.strategy || "absolute", }).then(({ x, y }) => { @@ -73,12 +73,16 @@ export default class extends Controller { this.#deselectAll(); this.#addEventListeners(); this.#computeTooltip(); + // Lift the open menu above sibling dropdowns/elements. The container has no + // static z-index, so closed siblings stack in normal flow and never cover it. + this.element.style.zIndex = "50"; this.contentTarget.classList.remove("hidden"); } close() { this.openValue = false; this.#removeEventListeners(); + this.element.style.zIndex = ""; this.contentTarget.classList.add("hidden"); } diff --git a/docs/app/views/docs/dropdown_menu.rb b/docs/app/views/docs/dropdown_menu.rb index effa942b2..4588a301c 100644 --- a/docs/app/views/docs/dropdown_menu.rb +++ b/docs/app/views/docs/dropdown_menu.rb @@ -11,7 +11,7 @@ def view_template render Docs::VisualCodeExample.new(title: "Example", context: self) do <<~RUBY DropdownMenu do - DropdownMenuTrigger(class: 'w-full') do + DropdownMenuTrigger do Button(variant: :outline) { "Open" } end DropdownMenuContent do @@ -29,7 +29,7 @@ def view_template render Docs::VisualCodeExample.new(title: "Non-navigational item", description: "Use as: :div when the item hosts its own interactive element (e.g. a dialog or form trigger). This avoids nesting a