8000 Proposal: Enable Custom Form Controls to (Optionally) Conceal Internal/Irrelevant Events · Issue #1368 · whatwg/dom · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
Proposal: Enable Custom Form Controls to (Optionally) Conceal Internal/Irrelevant Events #1368
Open
@ITenthusiasm

Description

@ITenthusiasm

What problem are you trying to solve?

Currently, there is no way for a Custom Form Control composed of primitive form controls to prevent "the outside world" from receiving undesirable/noisy events from said primitives. Consider the following example:

Use Case: Comboboxes (where only valid values are accepted)

Many combobox components in the wild effectively act as stylable <select> elements whose restricted values can be conveniently searched via a textbox. In such cases, the combobox's value is only permitted to be empty or a valid option value -- just as in the <select>'s case.

From an event dispatching standpoint, the <select> element only dispatches input/change events when a user interaction updates the value. Similarly, many of these comboboxes desire to only dispatch an input/change event when a new valid value is selected. And this is where things get tricky...

Typically, searchable comboboxes are implemented with a native <input> (or some other contenteditable element). But these emit input events on every keystroke -- creating undesirable noise for delegated event listeners which are trying to watch for updates to the Combobox Value only. Particularly, the delegated event listeners will see input events whenever the textbox is typed into, and whenever a valid option is selected (in which case the Combobox will dispatch its own custom input event). But ideally, these events should only be detected/observed in the latter case to avoid noise/confusion.

There is currently no way to prevent this undesirable behavior. Even if someone tried to use a Shadow DOM, both open and closed Shadow DOMs will propagate input events to the Light DOM because input is composed. But closed Shadow DOMs will yield a slightly worse UX because they make it impossible to know whether the input came from the Combobox itself or the inner <input>. (I guess technically, someone could check event.isTrusted, but that requires knowledge of implementation details.)

(Sidenote for Clarity: the Combobox value should not be updated until the user selects a valid option. If the user bails out while searching, the textfield should revert its text content back to the last valid value of the Combobox, and the Combobox should not emit an input/change event. This prevents bad data from being sent to the server.)

Depending on how a <checkbox-group> component with minimum-selected items would be implemented, it might run into similar issues.

What solutions exist today?

There technically aren't any real/genuine solutions to this problem today. Probably the best thing that developers can do is tell users how to filter out the events that they don't want in their delegated event listeners. However, this will almost certainly entail exposing implementation details, which is not optimal. For example, a developer could say, "Check for event.isTrusted === false or event instanceof CustomEvent to distinguish between the correct input/change events."

Perhaps another option is for the developer to create very clever listeners for keydown (composed textboxes), click (composed checkboxes), and the like which could call event.preventDefault() as needed. But it's possible that this approach could get out of hand quickly. And it might not cover all use cases.

How would you solve it?

I've noticed that a number of new ShadowDOM-related attributes/options have appeared in the spec to resolve problems like these. Perhaps a new one could be created for this scenario? Something like:

this.attachShadow({ mode: "closed", concealsEvents: true });

or

<template shadowrootmode="closed" shadowrootconcealsevents>

Another alternative is perhaps to enable ElementInternals to specify that it conceals its own events through a togglable property.

const internals = this.attachInternals();
internals.concealsEvents = true;

Could also be a static property, perhaps, like formAssociated and observedAttributes.

class ComboboxField extends HTMLElement {
  static get concealedEvents() {
    return ["input", "change"];
  }

  // ...
}

The main idea is that in some way, the Web Component would be able to dictate that it conceals its events (or a specific set of events) within the class declaration.

Anything else?

After writing up this issue, I'm starting to conclude that the issue may surround Custom Form Controls and the events which they want to emit more than it does the Shadow DOM. In simple terms, the issue is that a Custom Form Control may wish to take full responsibility over a specific set of events, because the events are irrelevant/noisy if they bubble up from any children (e.g., input/change in the combobox scenario). To that end, I'd probably prefer the static concealedEvents approach, with an ability to specify some kind of "all" option as needed.

Whether it's related to this problem or not, I feel like I can still make this comparison: Developers can't listen to click events on <option> elements in a <select> element -- nor do they need to. All that they really need to listen for is input/change from the <select> element itself. A sophisticated Custom Form Control leveraging "subcomponents"/"primitive controls" may require similar behavior. On that note... Perhaps the greater issue is needing the ability to conceal all events from specific sub-elements (as with the <select>/<option> combination)?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0