Skip to content
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
83 changes: 56 additions & 27 deletions files/en-us/web/api/htmldialogelement/cancel_event/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,15 @@ browser-compat: api.HTMLDialogElement.cancel_event

{{APIRef("HTML DOM")}}

The **`cancel`** event fires on a {{HTMLElement("dialog")}} element when the user instructs the browser that they wish to dismiss the current open dialog. The browser fires this event when the user presses the <kbd>Esc</kbd> key.
The **`cancel`** event fires on a {{HTMLElement("dialog")}} element when the user sends a [close request](https://html.spec.whatwg.org/multipage/interaction.html#close-request) to the user agent.
Copy link
Collaborator

Choose a reason for hiding this comment

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

  1. Linking to the spec is frowned upon, unless absolutely necessary. MDN is supposed to be a human readable version of the spec. Defining the close request below does the job nicely.
  2. The user doesn't really send anything - the browser does.
  3. Terminology is mixed, but use browser by preference. I tend to use browser agent for web APIs that also exist in node/deno.

Propose

Suggested change
The **`cancel`** event fires on a {{HTMLElement("dialog")}} element when the user sends a [close request](https://html.spec.whatwg.org/multipage/interaction.html#close-request) to the user agent.
The **`cancel`** event fires on a {{HTMLElement("dialog")}} element when the user triggers a close request.


This event is cancelable but can not bubble.
Examples of close requests are:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
Examples of close requests are:
Close requests might be triggered by:


- Pressing the <kbd>Esc</kbd> key on desktop platforms
- Calling the {{domxref("HTMLDialogElement.requestClose()", "requestClose()")}} method.
- The back button on mobile platforms

When a `<dialog>` is dismissed with the <kbd>Esc</kbd> key, both the `cancel` and {{domxref("HTMLDialogElement/close_event", "close")}} events are fired.
This event is cancelable but can not bubble.

## Syntax

Expand All @@ -32,55 +36,80 @@ A generic {{domxref("Event")}}.

### Canceling a dialog

The following example shows a button that, when clicked, opens a {{htmlelement("dialog")}} via the {{domxref("HTMLDialogElement.showModal()", "showModal()")}} method.

From there you can trigger the `cancel` event by either clicking _Request Close_ button to close the dialog (via the {{domxref("HTMLDialogElement.requestClose()", "requestClose()")}} method), or press the <kbd>Esc</kbd> key.

Preventing the dialog from closing is demonstrated with a checkbox.
Comment on lines +39 to +43
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is obviously a lot better than no explanation!

If I am doing a method-specific document, I tend to structure like "
This example shows how to cancel a dialog, and how you can also prevent a dialog from closing by ...
Then either have detailed "how" or interleave in the text.

However in this case we have a number of examples that seem to be the same - such as requestClose. In that case I might keep your current structure, but in requestClose() remove the example, and just have "See the cancel event example for blah blah).

Thoughts?


#### HTML

```html
<dialog class="example-dialog">
<button class="close">Close</button>
<dialog id="dialog">
<div>
<label><input type="checkbox" id="prevent-close" /> prevent close</label>
</div>
<button type="button" id="request-close">Request Close</button>
</dialog>

<button class="open-dialog">Open dialog</button>
<button id="open">Open dialog</button>
```

<div class="result"></div>
```html hidden
<pre id="status-text"></pre>
```

```css hidden
button,
div {
margin: 0.5rem;
#status-text {
height: 120px;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Consider doubling this as well

overflow: scroll;
padding: 0.5rem;
border: 1px solid black;
}
```

#### JavaScript
```js hidden
const statusText = document.getElementById("status-text");
function log(text) {
statusText.innerText = `${statusText.innerText}${text}\n`;
statusText.scrollTop = statusText.scrollHeight;
}
```

```js
const result = document.querySelector(".result");

const dialog = document.querySelector(".example-dialog");
const dialog = document.getElementById("dialog");
const openButton = document.getElementById("open");
const requestCloseButton = document.getElementById("request-close");
const preventCloseInput = document.getElementById("prevent-close");

// Update button opens a modal dialog
openButton.addEventListener("click", () => {
dialog.showModal();
});

dialog.addEventListener("cancel", (event) => {
result.textContent = "dialog was canceled";
// Request close
requestCloseButton.addEventListener("click", () => {
// Triggers the cancel event
dialog.requestClose();
});

const openDialog = document.querySelector(".open-dialog");
openDialog.addEventListener("click", () => {
if (typeof dialog.showModal === "function") {
dialog.showModal();
result.textContent = "";
} else {
result.textContent = "The dialog API is not supported by this browser";
// Fired when requestClose() is called
// Prevent the dialog from closing by calling event.preventDefault()
dialog.addEventListener("cancel", (event) => {
if (preventCloseInput.checked) {
log("Dialog close cancelled");
event.preventDefault();
}
});

const closeButton = document.querySelector(".close");
closeButton.addEventListener("click", () => {
dialog.close();
dialog.addEventListener("close", (event) => {
log("Dialog closed");
});
```

#### Result

{{ EmbedLiveSample('Canceling a dialog', '100%', '100px') }}
{{ EmbedLiveSample('Canceling a dialog', '100%', '250px') }}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Interestingly, I'm showing Chrome sending a close event for the Escape key, while FF follows the spec and sends a cancel events. We should update the compatibility data to reflect that.


## Specifications

Expand Down
98 changes: 52 additions & 46 deletions files/en-us/web/api/htmldialogelement/close/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ browser-compat: api.HTMLDialogElement.close
{{ APIRef("HTML DOM") }}

The **`close()`** method of the {{domxref("HTMLDialogElement")}} interface closes the {{htmlelement("dialog")}}.
An optional string may be passed as an argument, updating the `returnValue` of the dialog.
An optional string may be passed as an argument, updating the {{domxref("HTMLDialogElement.returnValue", "returnValue")}} of the dialog.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Worth noting what event(s) is/are fired? Can closing be prevented?

Copy link
Collaborator

Choose a reason for hiding this comment

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

... and adding those relevant events as See also section at end.

## Syntax

Expand All @@ -29,68 +29,74 @@ None ({{jsxref("undefined")}}).

## Examples

The following example shows a simple button that, when clicked, opens a {{htmlelement("dialog")}} containing a form via the `showModal()` method.
From there you can click the _X_ button to close the dialog (via the `HTMLDialogElement.close()` method), or submit the form via the submit button.
The following example shows a button that, when clicked, opens a {{htmlelement("dialog")}} via the {{domxref("HTMLDialogElement.showModal()", "showModal()")}} method.
From there you can click the either _Close_ button to close the dialog (via the `close()` method).

The _Close_ button closes the dialog without a {{domxref("HTMLDialogElement.returnValue", "returnValue")}}, while the _Close w/ return value_ button closes the dialog with a {{domxref("HTMLDialogElement.returnValue", "returnValue")}}.
Comment on lines +32 to +35
Copy link
Collaborator

Choose a reason for hiding this comment

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

The template likes a level 3 heading for Web API examples, or it should :-)

Suggested change
The following example shows a button that, when clicked, opens a {{htmlelement("dialog")}} via the {{domxref("HTMLDialogElement.showModal()", "showModal()")}} method.
From there you can click the either _Close_ button to close the dialog (via the `close()` method).
The _Close_ button closes the dialog without a {{domxref("HTMLDialogElement.returnValue", "returnValue")}}, while the _Close w/ return value_ button closes the dialog with a {{domxref("HTMLDialogElement.returnValue", "returnValue")}}.
### Closing a dialog
The following example demonstrates how you can close a dialog, optionally passing a return value.
It displays a button that can be clicked to open a {{htmlelement("dialog")}} by calling the {{domxref("HTMLDialogElement.showModal()", "showModal()")}} method.
The dialog that is displayed can be closed by clicking either _Close_ button.
The _Close_ button closes the dialog without a {{domxref("HTMLDialogElement.returnValue", "returnValue")}}, while the _Close w/ return value_ button closes the dialog with a {{domxref("HTMLDialogElement.returnValue", "returnValue")}}.


```html
<!-- Simple pop-up dialog box, containing a form -->
<dialog id="favDialog">
<form method="dialog">
<button type="button" id="close" aria-label="close">X</button>
<section>
<p>
<label for="favAnimal">Favorite animal:</label>
<select id="favAnimal" name="favAnimal">
<option></option>
<option>Brine shrimp</option>
<option>Red panda</option>
<option>Spider monkey</option>
</select>
</p>
</section>
<menu>
<li>
<button type="reset">Reset</button>
</li>
<li>
<button type="submit">Confirm</button>
</li>
</menu>
</form>
<dialog id="dialog">
<button type="button" id="close">Close</button>
<button type="button" id="close-w-value">Close w/ return value</button>
</dialog>

<button id="updateDetails">Update details</button>
<button id="open">Open dialog</button>
```

```html hidden
<pre id="status-text"></pre>
```

```css hidden
#status-text {
height: 120px;
overflow: scroll;
padding: 0.5rem;
border: 1px solid black;
}
```

```js hidden
const statusText = document.getElementById("status-text");
function log(text) {
statusText.innerText = `${statusText.innerText}${text}\n`;
statusText.scrollTop = statusText.scrollHeight;
}
```

```js
const updateButton = document.getElementById("updateDetails");
const dialog = document.getElementById("dialog");
const openButton = document.getElementById("open");
const closeButton = document.getElementById("close");
const dialog = document.getElementById("favDialog");
dialog.returnValue = "favAnimal";

function openCheck(dialog) {
if (dialog.open) {
console.log("Dialog open");
} else {
console.log("Dialog closed");
}
}
const closeWithValueButton = document.getElementById("close-w-value");

// Update button opens a modal dialog
updateButton.addEventListener("click", () => {
openButton.addEventListener("click", () => {
// Reset the return value
dialog.returnValue = "";
// Rhow the dialog
dialog.showModal();
openCheck(dialog);
});

// Form close button closes the dialog box
// Close button closes the dialog box
closeButton.addEventListener("click", () => {
dialog.close("animalNotChosen");
openCheck(dialog);
dialog.close();
});

// Close button closes the dialog box with a return value
closeWithValueButton.addEventListener("click", () => {
dialog.close("some value");
});

// Form close button closes the dialog box
dialog.addEventListener("close", () => {
log(`Dialog closed. Return value: "${dialog.returnValue}"`);
});
```

If the "X" button was of `type="submit"`, the dialog would have closed without requiring JavaScript.
A form submission closes the `<dialog>` it is nested within if the [form's method is `dialog`](/en-US/docs/Web/HTML/Reference/Elements/form#method), so no "close" button is required.
> [!NOTE]
>
> You know you can also automatically close a `<dialog>` by submitting a {{htmlelement("form")}} element with a [`method="dialog"`](/en-US/docs/Web/HTML/Reference/Elements/form#method) attribute.

### Result

Expand Down
47 changes: 29 additions & 18 deletions files/en-us/web/api/htmldialogelement/close_event/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,46 +33,57 @@ A generic {{domxref("Event")}}.
#### HTML
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's change ### Live example above to a better name - up to you - but perhaps "Handling close events". Note that the example macro needs a corresponding name

Copy link
Collaborator

Choose a reason for hiding this comment

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

Did you want to explain it? In particular perhaps link to information on <form method="dialog"> since it isn't clear why closing via method dialog is interesting, other that we have a button for it.


```html
<dialog class="example-dialog">
<dialog id="dialog">
<form method="dialog">
<button>Close via method="dialog"</button>
<button type="submit">Close via method="dialog"</button>
</form>
<button class="close">Close via .close() method</button>
<button id="close">Close via .close() method</button>
<p>Or hit the <kbd>Esc</kbd> key</p>
</dialog>

<button class="open-dialog">Open dialog</button>
<button id="open">Open dialog</button>
```

<div class="result"></div>
```html hidden
<pre id="status-text"></pre>
```

```css hidden
button,
div {
margin: 0.5rem;
#status-text {
height: 120px;
overflow: scroll;
padding: 0.5rem;
border: 1px solid black;
}
```

```js hidden
const statusText = document.getElementById("status-text");
function log(text) {
statusText.innerText = `${statusText.innerText}${text}\n`;
statusText.scrollTop = statusText.scrollHeight;
}
```

#### JavaScript

```js
const result = document.querySelector(".result");

const dialog = document.querySelector(".example-dialog");
dialog.addEventListener("close", (event) => {
result.textContent = "dialog was closed";
});
const dialog = document.getElementById("dialog");
const openButton = document.getElementById("open");
const closeButton = document.getElementById("close");

const openDialog = document.querySelector(".open-dialog");
openDialog.addEventListener("click", () => {
openButton.addEventListener("click", () => {
dialog.showModal();
result.textContent = "";
log("dialog: opened");
});

const closeButton = document.querySelector(".close");
closeButton.addEventListener("click", () => {
dialog.close();
});

dialog.addEventListener("close", (event) => {
log("dialog: closed");
});
```

#### Result
Expand Down
19 changes: 13 additions & 6 deletions files/en-us/web/api/htmldialogelement/closedby/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,18 @@ The **`closedBy`** property of the
A string; possible values are:

- `any`
- : The dialog can be dismissed with a light dismiss user action, a platform-specific user action, or a developer-specified mechanism.
- : The dialog can be dismissed by a [close request](https://html.spec.whatwg.org/multipage/interaction.html#close-request) or clicks outside the dialog.
Copy link
Collaborator

Choose a reason for hiding this comment

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

No spec links

Copy link
Collaborator

@hamishwillee hamishwillee Dec 1, 2025

Choose a reason for hiding this comment

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

Also, I would not purge the term "light dismiss" - its in the spec and other docs. You could define it if you want.

I'd be tempted to revert this. If you want the pattern then maybe define earlier what the different close options are, such as close request and light dismiss and platform-specific user action.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ditto below

- `closerequest`
- : The dialog can be dismissed with a platform-specific user action or a developer-specified mechanism.
- : The dialog can only be dismissed by a [close request](https://html.spec.whatwg.org/multipage/interaction.html#close-request).
- `none`
- : The dialog can only be dismissed with a developer-specified mechanism.
- : No user actions automatically close the dialog. The dialog can only be dismissed with a developer-specified mechanism.
Copy link
Collaborator

Choose a reason for hiding this comment

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

An improvement, but perhaps be even more specific - such as

Suggested change
- : No user actions automatically close the dialog. The dialog can only be dismissed with a developer-specified mechanism.
- : The dialog can only be dismissed with a developer-specified mechanism. User actions such as clicking outside the dialog have no effect.


### Default behaviour

If the `closedby` attribute is absent or invalid, it falls back to the **Auto** state. In the **Auto** state:

- when the `<dialog>` is opened with `showModal()`, it behaves as if: `closedby="closerequest"`
- when the `<dialog>` is opened by any other means, it behaves as if: `closedby="none"`

## Examples

Expand All @@ -30,14 +37,14 @@ A string; possible values are:
<dialog open closedby="any">
<h2>My dialog</h2>
<p>
Closable using the Esc key, or by clicking outside the dialog. "Light
dismiss" behavior.
Closable using the <kbd>Esc</kbd> key, or by clicking outside the dialog
("light dismiss").
</p>
</dialog>
```

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

// Logs "any" to the console
console.log(dialogElem.closedBy);
Expand Down
Loading