CloseWatcher

Limited availability

This feature is not Baseline because it does not work in some of the most widely-used browsers.

Experimental: This is an experimental technology
Check the Browser compatibility table carefully before using this in production.

The CloseWatcher interface allows a custom UI component with open and close semantics to respond to device-specific close actions in the same way as a built-in component.

EventTarget CloseWatcher

The CloseWatcher interface inherits from EventTarget.

Constructor

CloseWatcher() Experimental

Creates a new CloseWatcher instance.

Instance methods

This interface also inherits methods from its parent, EventTarget.

CloseWatcher.requestClose() Experimental

Fires a cancel event and if that event is not canceled with Event.preventDefault(), proceeds to fire a close event, and then finally deactivates the close watcher as if destroy() was called.

CloseWatcher.close() Experimental

Immediately fires the close event, without firing cancel first, and deactivates the close watcher as if destroy() was called.

CloseWatcher.destroy() Experimental

Deactivates the close watcher so that it will no longer receive close events.

Events

cancel Experimental

An event fired before the close event, so that close can be prevented from firing.

close Experimental

An event fired when a close request was received.

Description

Some UI components have "close behavior", meaning that the component appears, and the user can close it when they are finished with it. For example: sidebars, popups, dialogs, or notifications.

Users generally expect to be able to use a particular mechanism to close these elements, and the mechanism tends to be device-specific. For example, on a device with a keyboard it might be the Esc key, but Android might use the back button. For built-in components, such as popover or <dialog> elements, the browser takes care of these differences, closing the element when the user performs the close action appropriate for the device. However, when a web developer implements their own closable UI component (for example, a sidebar), it is hard to implement this kind of device-specific close behavior.

The CloseWatcher interface solves this problem by delivering a cancel event, followed by a close event, when the user executes the device-specific close action. Web applications can use the onclose handler to close the UI element in response to the device-specific event. They can also trigger these same events in response to the UI element's normal closing mechanism, and then implement common close event handling for both the application- and device-specific close action. Once the onclose event handler completes the CloseWatcher is destroyed and the events will no longer be fired.

In some applications the UI element may only be allowed to close when it is in a particular state; for example, when some needed information is populated. To address these cases, applications can prevent the close event from being emitted by implementing a handler for the cancel event that calls Event.preventDefault() if the UI element is not ready to close.

You can create CloseWatcher instances without user activation, and this can be useful to implement cases like session inactivity timeout dialogs. However, if you create more than one CloseWatcher without user activation, then the watchers will be grouped, so a single close request will close them both. In addition, the first close watcher does not necessarily have to be a CloseWatcher object: it could be a modal dialog element, or a popover generated by an element with the popover attribute

Examples

Processing close requests

In this example, you have your own UI component (a picker) and you want to support both, the platform's default close method (e.g. the Esc key) and your custom close method (a close button).

You create a CloseWatcher to handle all close events.

The onclick handler of your UI component can call requestClose to request a close and to route your close request through the same onclose handler the platform close method uses.

js
const watcher = new CloseWatcher();
const picker = setUpAndShowPickerDOMElement();
let chosenValue = null;

watcher.onclose = () => {
  chosenValue = picker.querySelector("input").value;
  picker.remove();
};

picker.querySelector(".close-button").onclick = () => watcher.requestClose();

Closing a sidebar using a platform close request

In this example we have a sidebar component that is displayed when an "Open" button is selected, and hidden using either a "Close" button or platform-native mechanisms. To make it more interesting, this is a live example!

Note also that the example is a little contrived, because normally we would use a toggle button to change a sidebar state. We could certainly do that, but using separate "Open" and "Close" buttons makes it easier to demonstrate the feature.

HTML

The HTML defines "Open" and "Close" <button> elements, along with <div> elements for the main content and the sidebar. CSS is used to animate the display of the sidebar element when the open class is added or removed from the sidebar and content elements (this CSS is hidden because it is not relevant to the example).

html
<button id="sidebar-open" type="button">Open</button>
<button id="sidebar-close" type="button">Close</button>
<div class="sidebar">Sidebar</div>
<div class="main-content">Main content</div>

JavaScript

The code first gets variables for the buttons and <div> elements defined in the HTML. It also defines a function closeSidebar() that is called when the sidebar is closed, to remove the open class from the <div> elements, and adds a click event listener that calls the openSidebar() method when the "Open" button is clicked.

js
const sidebar = document.querySelector(".sidebar");
const mainContent = document.querySelector(".main-content");
const sidebarOpen = document.getElementById("sidebar-open");
const sidebarClose = document.getElementById("sidebar-close");

function closeSidebar() {
  sidebar.classList.remove("open");
  mainContent.classList.remove("open");
}

sidebarOpen.addEventListener("click", openSidebar);

The implementation of openSidebar() is given below. The method first checks if the sidebar is already open, and if not, adds the open class to the elements so that the sidebar is displayed.

We then create a new CloseWatcher and add a listener that will call close() on it if the "Close" button is clicked. This ensures that the close event is called when either platform native close methods or the "Close" button are used. The implementation of the onclose() event handler simply closes the sidebar, and the CloseWatcher is then destroyed automatically.

js
function openSidebar() {
  if (!sidebar.classList.contains("open")) {
    sidebar.classList.add("open");
    mainContent.classList.add("open");

    //Add new CloseWatcher
    const watcher = new CloseWatcher();

    sidebarClose.addEventListener("click", () => watcher.close());

    // Handle close event, invoked by platform mechanisms or "Close" button
    watcher.onclose = () => {
      closeSidebar();
    };
  }
}

Note that we chose to call close() on the watcher instead of CloseWatcher.requestClose() because we don't need the cancel event to be emitted (we would use requestClose() and the cancel event handler if there was a reason to ever prevent the sidebar from closing prematurely).

Result

Select the "Open" button to open the sidebar. You should be able to close the sidebar using the "Close" button or the usual platform method, such as the Esc key on Windows.

Specifications

Specification
HTML Standard
# closewatcher

Browser compatibility

BCD tables only load in the browser

See also