From f0cb6b2842c1964e8d189733974bcfddccda1dd4 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Sun, 10 May 2026 07:37:56 -0400 Subject: [PATCH 1/2] Fix slideover closing unexpectedly during text selection When a user starts a drag operation inside the modal (e.g., selecting text in an input field) and their mouse moves outside the modal boundary, the modal closes unexpectedly when they release the mouse button. This happens because the browser fires a click event on the backdrop even when mousedown started inside the slideover content. This fix checks if text is currently selected before closing. If the user has an active text selection, the modal stays open. See #282 for the original modal fix --- src/slideover.js | 5 +++- test/fixtures/slideover.html | 3 +- test/slideover_test.js | 58 ++++++++++++++++++++++++++++++++++-- 3 files changed, 61 insertions(+), 5 deletions(-) diff --git a/src/slideover.js b/src/slideover.js index cf68339..bcdbc9c 100644 --- a/src/slideover.js +++ b/src/slideover.js @@ -33,7 +33,10 @@ export default class extends Controller { } backdropClose(event) { - if (event.target.nodeName == "DIALOG") this.close() + if (event.target.nodeName !== "DIALOG") return; + if (window.getSelection().toString().length > 0) return; + + this.close(); } show() { diff --git a/test/fixtures/slideover.html b/test/fixtures/slideover.html index a37dc09..8dd6fd1 100644 --- a/test/fixtures/slideover.html +++ b/test/fixtures/slideover.html @@ -1,6 +1,7 @@
- +

This slideover dialog has a groovy backdrop!

+
diff --git a/test/slideover_test.js b/test/slideover_test.js index a63e136..8be3aba 100644 --- a/test/slideover_test.js +++ b/test/slideover_test.js @@ -15,10 +15,62 @@ describe('SlideoverController', () => { }) it('opens dialog', () => { - const dialog = document.querySelector("dialog") - expect(dialog.hasAttribute("open")).to.equal(false) + const dialog = document.querySelector('dialog') + expect(dialog.hasAttribute('open')).to.equal(false) document.querySelector("[data-action='slideover#open']").click() - expect(dialog.hasAttribute("open")).to.equal(true) + expect(dialog.hasAttribute('open')).to.equal(true) + }) + + it('closes the slideover when clicking on the backdrop', async () => { + const dialog = document.querySelector('dialog') + const openSlideoverButton = document.querySelector("[data-action='slideover#open']") + openSlideoverButton.click() + expect(dialog.hasAttribute('open')).to.equal(true) + + // Simulate clicking on the dialog element itself (the backdrop) + const clickEvent = new MouseEvent('click', { bubbles: true }) + Object.defineProperty(clickEvent, 'target', { value: dialog }) + dialog.dispatchEvent(clickEvent) + + expect(dialog.hasAttribute('closing')).to.equal(true) + }) + + it('does not close the slideover when clicking inside slideover content', async () => { + const dialog = document.querySelector('dialog') + const openSlideoverButton = document.querySelector("[data-action='slideover#open']") + const input = document.querySelector("[data-testid='slideover-input']") + openSlideoverButton.click() + expect(dialog.hasAttribute('open')).to.equal(true) + + // Simulate clicking on the input inside the modal + input.click() + + expect(dialog.hasAttribute('closing')).to.equal(false) + expect(dialog.hasAttribute('open')).to.equal(true) + }) + + it('does not close the slideover when text is selected', async () => { + const dialog = document.querySelector('dialog') + const openSlideoverButton = document.querySelector("[data-action='slideover#open']") + openSlideoverButton.click() + expect(dialog.hasAttribute('open')).to.equal(true) + + // Simulate text selection + const selection = window.getSelection() + const input = document.querySelector("[data-testid='slideover-input']") + input.select() + + // Simulate clicking on the backdrop while text is selected + const clickEvent = new MouseEvent('click', { bubbles: true }) + Object.defineProperty(clickEvent, 'target', { value: dialog }) + dialog.dispatchEvent(clickEvent) + + // Modal should stay open because text is selected + expect(dialog.hasAttribute('closing')).to.equal(false) + expect(dialog.hasAttribute('open')).to.equal(true) + + // Clear selection + selection.removeAllRanges() }) }) }) From 0dccb745a73b73deda43229e6045839b8cb5f611 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Sun, 10 May 2026 07:43:06 -0400 Subject: [PATCH 2/2] update release notes --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bd241ee..4d13169 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Unreleased +* Fix premeture closing of modals and slideovers (#284, #289) +* Update Tailwind v4 documentation + + # 6.1.3 * Support multiple classes for dropdown transitions