Skip to content

Technical review: Document <dialog> closeby attribute #39082

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions files/en-us/web/api/htmldialogelement/closedby/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
---
title: "HTMLDialogElement: closedBy property"
short-title: closedBy
slug: Web/API/HTMLDialogElement/closedBy
page-type: web-api-instance-property
browser-compat: api.HTMLDialogElement.closedBy
---

{{ APIRef("HTML DOM") }}

The **`closedBy`** property of the
{{domxref("HTMLDialogElement")}} interface indicates the types of user actions that can be used to close the associated {{htmlelement("dialog")}} element. It sets or returns the dialog's [`closedby`](/en-US/docs/Web/HTML/Reference/Elements/dialog#closedby) attribute value.

## Value

A string; possible values are:

- `none`

- : No user actions can be used to close the `<dialog>` element, only developer-specified mechanisms such as a close {{htmlelement("button")}} (for example with a [`click`](/en-US/docs/Web/API/Element/click_event) handler that invokes {{domxref("HTMLDialogElement.close()")}}) or a {{htmlelement("form")}} submission.

- `closerequest`

- : The `<dialog>` element can be closed via relevant platform-specific user actions, such as pressing the <kbd>Esc</kbd> key on desktop platforms, or a "back" or "dismiss" gesture on mobile platforms.

- `any`

- : The `<dialog>` element can be closed via relevant platform-specific user actions, or by clicking or tapping outside the `<dialog>`. This is equivalent to the ["light dismiss" behavior of "auto" state popovers](/en-US/docs/Web/API/Popover_API/Using#auto_state_and_light_dismiss).

> [!NOTE]
> If the `<dialog>` element does not have a `closedby` value specified, or it is specified with an invalid value, it behaves as if the value was `"closerequest"` if the `<dialog>` was shown via {{domxref("HTMLDialogElement.showModal()", "showModal()")}}, or `"none"` if it was not.

## Examples

### Basic `closedBy` usage

In this example, we'll declare a `<dialog>` element, then access its `closedby` attribute value via JavaScript.

#### HTML

We first declare an open `<dialog>` element with a `closedby` value of `any`:

```html
<dialog open closedby="any">
<h2>My dialog</h2>
<p>
Closable using the Esc key, or by clicking outside the dialog. "Light
dismiss" behavior.
</p>
</dialog>
```

#### JavaScript

We then grab a reference to the `<dialog>` element in JavaScript and log its `closedby` value to the console, accessing it via the `closedBy` property:

```js
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would an HTML example be good to include, perhaps first? <dialog closedby=any>?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. I've done so, and added some more explanation.

const dialogElem = document.querySelector("dialog");

// Logs "any" to the console
console.log(dialogElem.closedBy);
```

## Specifications

{{Specifications}}

## Browser compatibility

{{Compat}}

## See also

- {{ HTMLElement("dialog") }}
2 changes: 2 additions & 0 deletions files/en-us/web/api/htmldialogelement/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ The **`HTMLDialogElement`** interface provides methods to manipulate {{HTMLEleme

_Also inherits properties from its parent interface, {{domxref("HTMLElement")}}._

- {{domxref("HTMLDialogElement.closedBy")}}
- : A string that sets or returns the [`closedby`](/en-US/docs/Web/HTML/Reference/Elements/dialog#closedby) attribute value of the `<dialog>` element, which indicates the types of user actions that can be used to close it.
- {{domxref("HTMLDialogElement.open")}}
- : A boolean value reflecting the [`open`](/en-US/docs/Web/HTML/Reference/Elements/dialog#open) HTML attribute, indicating whether the dialog is available for interaction.
- {{domxref("HTMLDialogElement.returnValue")}}
Expand Down
129 changes: 129 additions & 0 deletions files/en-us/web/html/reference/elements/dialog/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,25 @@ This element includes the [global attributes](/en-US/docs/Web/HTML/Reference/Glo
> [!WARNING]
> The `tabindex` attribute must not be used on the `<dialog>` element. See [usage notes](#usage_notes).

- `closedby`

- : Specifies the types of user actions that can be used to close the `<dialog>` element. Possible values are:

- `none`

- : No user actions can be used to close the `<dialog>` element, only developer-specified mechanisms such as a close {{htmlelement("button")}} (for example with a [`click`](/en-US/docs/Web/API/Element/click_event) handler that invokes {{domxref("HTMLDialogElement.close()")}}) or a {{htmlelement("form")}} submission.

- `closerequest`

- : The `<dialog>` element can be closed via relevant platform-specific user actions, such as pressing the <kbd>Esc</kbd> key on desktop platforms, or a "back" or "dismiss" gesture on mobile platforms.

- `any`

- : The `<dialog>` element can be closed via relevant platform-specific user actions, or by clicking or tapping outside the `<dialog>`. This is equivalent to the ["light dismiss" behavior of "auto" state popovers](/en-US/docs/Web/API/Popover_API/Using#auto_state_and_light_dismiss).

> [!NOTE]
> If the `<dialog>` element does not have a `closedby` value specified, or it is specified with an invalid value, it behaves as if the value was `"closerequest"` if the `<dialog>` was shown via {{domxref("HTMLDialogElement.showModal()", "showModal()")}}, or `"none"` if it was not.

- `open`

- : Indicates that the dialog box is active and is available for interaction. If the `open` attribute is not set, the dialog box will not be visible to the user.
Expand Down Expand Up @@ -272,6 +291,116 @@ jsCloseBtn.addEventListener("click", (e) => {

From the output, we see it is impossible to close the dialog using the _Normal close_ button. But the dialog can be closed if we bypass the form validation using the `formnovalidate` attribute on the _Cancel_ button. Programmatically, `dialog.close()` will also close such dialog.

### Comparison of different closedby behaviors

This example demonstrates the difference in behavior between different values of the [`closedby`](#closedby) attribute.

#### HTML

We provide three {{htmlelement("button")}} elements and three {{htmlelement("dialog")}} elements. Each button will be programmed to open a different dialog that demonstrates the behavior one of the three values of the `closedby` attribute — `none`, `closedby`, and `any`. Note that each `<dialog>` element contains a `<button>` element that will be used to close it.

```html live-sample___closedbyvalues
<p>Choose a <code>&lt;dialog&gt;</code> type to show:</p>
<div id="controls">
<button id="none-btn"><code>closedby="none"</code></button>
<button id="closerequest-btn">
<code>closedby="closerequest"</code>
</button>
<button id="any-btn"><code>closedby="any"</code></button>
</div>

<dialog closedby="none">
<h2><code>closedby="none"</code></h2>
<p>
Only closable using a specific provided mechanism, which in this case is
pressing the "Close" button below.
</p>
<button class="close">Close</button>
</dialog>

<dialog closedby="closerequest">
<h2><code>closedby="closerequest"</code></h2>
<p>Closable using the "Close" button or the Esc key.</p>
<button class="close">Close</button>
</dialog>

<dialog closedby="any">
<h2><code>closedby="any"</code></h2>
<p>
Closable using the "Close" button, the Esc key, or by clicking outside the
dialog. "Light dismiss" behavior.
</p>
<button class="close">Close</button>
</dialog>
```

```css hidden live-sample___closedbyvalues
body {
font-family: sans-serif;
}

#controls {
display: flex;
justify-content: space-around;
}

dialog {
width: 480px;
border-radius: 5px;
border-color: rgb(0 0 0 / 0.3);
}

dialog h2 {
margin: 0;
}

dialog p {
line-height: 1.4;
}
```

#### JavaScript

Here we assign different variables to reference the main control `<button>` elements, the `<dialog>` elements, and the "Close" `<button>` elements inside the dialogs. First we assign a [`click`](/en-US/docs/Web/API/Element/click_event) event listener to each control button using [`addEventListener`](/en-US/docs/Web/API/EventTarget/addEventListener), the event handler function of which opens the associated `<dialog>` element via [`showModal()`](/en-US/docs/Web/API/HTMLDialogElement/showModal). We then loop through the "Close" `<button>` references, assigning each one a `click` event handler function that closes its `<dialog>` element via [`close()`](/en-US/docs/Web/API/HTMLDialogElement/close).

```js live-sample___closedbyvalues
const noneBtn = document.getElementById("none-btn");
const closerequestBtn = document.getElementById("closerequest-btn");
const anyBtn = document.getElementById("any-btn");

const noneDialog = document.querySelector("[closedby='none']");
const closerequestDialog = document.querySelector("[closedby='closerequest']");
const anyDialog = document.querySelector("[closedby='any']");

const closeBtns = document.querySelectorAll(".close");

noneBtn.addEventListener("click", () => {
noneDialog.showModal();
});

closerequestBtn.addEventListener("click", () => {
closerequestDialog.showModal();
});

anyBtn.addEventListener("click", () => {
anyDialog.showModal();
});

closeBtns.forEach((btn) => {
btn.addEventListener("click", () => {
btn.parentElement.close();
});
});
```

#### Result

The rendered result is as follows:

{{EmbedLiveSample("closedby-values", "100%", 300)}}

Try clicking each button to open a dialog. The first one can only be closed by clicking its "Close" button. The second one can also be closed via a device specific user action such as pressing the <kbd>Esc</kbd> key. The third one has full ["light-dismiss" behavior](/en-US/docs/Web/API/Popover_API/Using#auto_state_and_light_dismiss), and can additionally be closed by clicking or tapping outside the dialog.

### Animating dialogs

`<dialog>`s are set to [`display: none;`](/en-US/docs/Web/CSS/display) when hidden and `display: block;` when shown, as well as being removed from / added to the {{glossary("top layer")}} and the [accessibility tree](/en-US/docs/Web/Performance/Guides/How_browsers_work#building_the_accessibility_tree). Therefore, for `<dialog>` elements to be animated the {{cssxref("display")}} property needs to be animatable. [Supporting browsers](/en-US/docs/Web/CSS/display#browser_compatibility) animate `display` with a variation on the [discrete animation type](/en-US/docs/Web/CSS/CSS_animated_properties#discrete). Specifically, the browser will flip between `none` and another value of `display` so that the animated content is shown for the entire animation duration.
Expand Down