Repository navigation
Description
Prerequisites
- I have searched for duplicate or closed issues
- I have validated any HTML to avoid common problems
- I have read the contributing guidelines
Describe the issue
A dialog closes when the user opens the file picker of an <input type="file"> inside it and then dismisses the picker without choosing a file.
When a file picker is dismissed, browsers fire a cancel event at the input, and the HTML spec has it bubble (spec). It reaches the <dialog>, where DialogBase listens for cancel to handle Escape. That handler does not check event.target, so it treats the bubbled event as the dialog's own cancel and calls hide():
bootstrap/js/src/dialog-base.ts
Lines 308 to 320 in 7e914e3
| this._cancelHandler = event => { | |
| event.preventDefault() | |
| if (!this._config.keyboard) { | |
| this._triggerBackdropTransition() | |
| return | |
| } | |
| this._onCancel() | |
| this.hide() | |
| } | |
| EventHandler.on(this._element, 'cancel', this._cancelHandler) |
The native cancel event of a <dialog> does not bubble, so any cancel that arrives from a descendant is never the dialog's own. The backdrop click handler a few lines further down already guards with event.target !== this._element.
Steps to reproduce with the test case below:
- Click "Open dialog".
- Click the file input, so the file picker opens.
- Press Cancel in the file picker.
Expected: the dialog stays open.
Actual: the dialog closes. With data-bs-keyboard="false" it plays the static-backdrop animation instead, which is just as unexpected.
Suggested fix: ignore cancel events from descendants at the top of the handler:
this._cancelHandler = event => {
if (event.target !== this._element) {
return
}
event.preventDefault()
// …
}The workaround until then is to stop the event on the input:
input.addEventListener('cancel', event => event.stopPropagation())Reduced test cases
CodePen: https://codepen.io/editor/aloysiu5/pen/01a1a134-60a4-7254-98af-7ffc218ae510
The same as a self-contained page against the alpha.1 CDN build:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Dialog closes when a file picker is cancelled</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@6.0.0-alpha.1/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="p-6">
<button type="button" class="btn-solid theme-primary" data-bs-toggle="dialog" data-bs-target="#upload">Open dialog</button>
<dialog class="dialog" id="upload" aria-labelledby="upload-title">
<div class="dialog-header">
<h2 class="dialog-title" id="upload-title">Upload</h2>
<button type="button" class="btn-close" data-bs-dismiss="dialog" aria-label="Close"></button>
</div>
<div class="dialog-body">
<label for="file" class="form-label">Choose a file, then cancel the picker</label>
<input type="file" class="form-control" id="file">
</div>
</dialog>
<script type="module">
import "https://cdn.jsdelivr.net/npm/bootstrap@6.0.0-alpha.1/dist/js/bootstrap.bundle.min.js"
document.getElementById("file").addEventListener("cancel", (event) => {
console.log("cancel on", event.target.tagName, "bubbles:", event.bubbles)
})
</script>
</body>
</html>The console line shows the event that closes the dialog: cancel on INPUT bubbles: true.
What operating system(s) are you seeing the problem on?
macOS
What browser(s) are you seeing the problem on?
Chrome
What version of Bootstrap are you using?
v6.0.0-alpha.1 (the handler is unchanged on main at 7e914e3)
Activity
samyferhat commentedon Nov 4, 2026
Hi, I've started working on this one. I could reproduce it on
main, and drawers are affected too since they shareDialogBase. The draft PR is up at #43297, I'll mark it ready once I've gone through it again.