#688: HTMLInputElement showPicker()

Visit on Github.

Opened Nov 8, 2021

Braw mornin' TAG!

I'm requesting a TAG review of the showPicker() method for HTMLInputElement.

The showPicker() element is a new addition to HTMLInputElement which addresses a very common request from web developers: programmatically showing a picker for controls like date etc.

Further details:

  • I have reviewed the TAG's Web Platform Design Principles
  • Relevant time constraints or deadlines: The next WHATWG HTML triage call is 2021-12-02 and it'd be great to have any feedback by then
  • The group where the work on this specification is currently being done: WHATWG
  • The group where standardization of this work is intended to be done (if current group is a community group or other incubation venue): N/A
  • Major unresolved issues with or opposition to this specification: None known
  • This work is being funded by: Google

We'd prefer the TAG provide feedback as (please delete all but the desired option):

💬 leave review feedback as a comment in this issue and @-notify @domenic, @beaufortfrancois, and @annevk

Discussions

Comment by @kenchris Nov 8, 2021 (See Github)

I think this is a good addition, and solves real user needs

Comment by @kenchris Nov 8, 2021 (See Github)

I believe that with user activation delegation, you need to add something (like feature identifier name) to make this work for iframes etc

Like here: https://github.com/w3c/webappsec-permissions-policy/blob/main/features.md

https://wicg.github.io/capability-delegation/spec.html

Comment by @LeaVerou Nov 9, 2021 (See Github)

I'm definitely familiar with the user needs this addresses (in fact, I believe I've even been on the author end of said use cases!), so it's exciting to see work in that direction. Some questions:

  • Since programmatic clicks already trigger the picker on color and file inputs, why not just specify that programmatic clicks trigger the picker on all inputs and avoid the additional API surface?
  • I'm a little concerned that the name showPicker may be overly constraining. Can all UIs we may want this to trigger be described as pickers, not just now but also in the future?

showPicker() is specified with a few restrictions to improve security:

  • It can only be called with transient user activation. If called without, it will throw a "NotAllowedError" DOMException. (This is similar to how click() behaviors, except click() silently does nothing.)

Doesn't this leak information about whether the user has interacted with the page, that silently doing nothing does not?

Comment by @domenic Nov 9, 2021 (See Github)

Since programmatic clicks already trigger the picker on color and file inputs, why not just specify that programmatic clicks trigger the picker on all inputs and avoid the additional API surface?

That's one direction we could go in, but I worry that it's a bit unexpected. click() rarely has these sorts of side effects, and the fact that it does so on file and color feels like a legacy quirk instead of something we want to extend. There's also a minor compat risk that people are calling click() and expecting no-op behavior today... although I doubt it'd be that risky.

I think the main argument is one I allude to in https://github.com/whatwg/html/issues/3232, which is that by not tying pickers to clicks, we allow a broader possible range of browser UIs for form controls, both now and in the future. Which has always felt important to me, given how we've seen things evolve with smartphones and watches and so on.

I'm a little concerned that the name showPicker may be overly constraining. Can all UIs we may want this to trigger be described as pickers, not just now but also in the future?

I think we're kind of defining "all UIs we may this to trigger" to be pickers. That is, showPicker() implies you want to show a picker... if we had some other sort of UI for entering values (e.g.... a virtual keyboard??) then probably the developer doesn't want that to happen when they call el.showPicker().

Perhaps another way of phrasing this is, are there other non-picker UIs that developers might want to show, in the same situations they want to show pickers? And would it be better for developers to not have to know the difference, but instead just trigger any such UIs? It's hard to say without examples, but I lean toward "picker" being a well-understood paradigm, and believing that it'll extend in the future to other non-pickers might be hard for developers to reason about...

Doesn't this leak information about whether the user has interacted with the page, that silently doing nothing does not?

No; this information is already available in plenty of ways, e.g. by using explicit event listeners for the activation triggering input events.

Comment by @domenic Nov 9, 2021 (See Github)

I believe that with user activation delegation, you need to add something (like feature identifier name) to make this work for iframes etc

Yeah, I noted that under "possible future work" in the mini-explainer:

  • We could add a permissions policy which allows cross-origin iframes to show pickers, when their parent chain allows them to do so.
Discussed Nov 22, 2021 (See Github)

Lea: adding a showpicker method... only for inputs.. so people can programmatically trigger pickers. It's subject to user activation - addresses privacy concerns. This spec changes mandates that the current behaviour change - right now users open the file picker on synthetic clicks... this changes .. my main rservation is that it seems weird to have synthetic clicks only open some pickers.. also though I can see the future possibility some authors may want to make more complex UI... if in the future these needs arise then we can add a separate API call.. this proposed change makes things inconsistent and adds a seperate method... I'm gonna post this from my PoV...

Peter: modal?

Lea: some modal some not... file p

Peter: [ for a synthetic click ] show file picker would not fire event listeners

Lea: correct.

Peter: what does this API surface buy ... over calling the click method or dispatching a click event.

Lea: there's value in the predictability - of triggering it with a click event... have seen comments on StackOverflow asking about this.

Peter: for me the biggest problem with date pickers that they're inconsistently implemented...

Lea: this doesn't help with that.

Peter: it's hard to feature detect.

Lea: if you have a colour input ..... it's weird if you use showpicker and it shows the data list instead of the picker. It's more natural that a synthetic click just does what a click would have done, it's easier to have a mental model about this. [will comment]

Comment by @LeaVerou Nov 22, 2021 (See Github)

Since programmatic clicks already trigger the picker on color and file inputs, why not just specify that programmatic clicks trigger the picker on all inputs and avoid the additional API surface?

That's one direction we could go in, but I worry that it's a bit unexpected. click() rarely has these sorts of side effects, and the fact that it does so on file and color feels like a legacy quirk instead of something we want to extend.

.click() has major side effects already, e.g. calling it on an <a> element can navigate to another page! Doesn't get any more side effect-y than that! 😁

There's also a minor compat risk that people are calling click() and expecting no-op behavior today... although I doubt it'd be that risky.

Yeah, I agree I wouldn't expect that to be common.

The way I see it, the advantages of .click() triggering the picker instead of a separate method are:

  • It's usually the first thing authors try, even before they research the API surface, so it's good for discoverability
  • If there are any event listeners attached to clicks with the assumption that they will be triggered every time the picker is opened, this will trigger them too

One downside is that it couples synthetic clicks with opening the picker: is there any case where authors may want to do one without the other?

I think the main argument is one I allude to in whatwg/html#3232, which is that by not tying pickers to clicks, we allow a broader possible range of browser UIs for form controls, both now and in the future. Which has always felt important to me, given how we've seen things evolve with smartphones and watches and so on.

If I understand your point correctly (?), you are saying that browsers in the future may want to provide more granular UIs which display different pickers depending on the location of the click, and thus a general .click() cannot really describe these kinds of interactions, whereas .showPicker() can be extended to support granularity via arguments.

I see that in theory, though why not add a separate API call then, if that happens? They're not mutually exclusive. Then .click() can do the same thing as .showPicker() if called with no arguments.

I could be wrong, but it seems inconsistent to me to have .click() trigger only some pickers, and add a separate method to trigger the rest. 🤷🏽‍♀️

It's also a bit unclear what a "picker" is. E.g. in an <input type=color> .showPicker() would open the OS color picker. However, in an <input type=color list="paletteid"> .showPicker() would not open the OS color picker, but a popup displaying the datalist options. I wonder if this would confuse authors that may expect .showPicker() to display a consistent type of UI for a given input type. Whereas .click() is easier to have a mental model about.

Comment by @annevk Nov 22, 2021 (See Github)

Such UI already exists, e.g., try <input type=date> in Chrome. Clicking the calendar icon shows the picker, clicking the control merely focuses it.

Similar situation with <input type=password> in Safari, although the icon doesn't show until the control is focused.

Discussed Dec 13, 2021 (See Github)

Tess: cool idea.. definitely some questions, need to read it to see if they're answered. What happens if you call showPicker on input type text?

Rossen: you might get suggestions...

Peter: input type password might activate your password managers. The hardest thing historically with datetime inptus was detecting whether the browser supports it properly

Tess: at least it's easy to feature detect if showPicker is there. Does it do something useful...

Peter: I can see browsers implementing it for certain types of inputs but not with a good widget

Ken: depends on platform as well, what is applicable

Tess: show if picker is applicable... reading spec text ... has a fallback... any relevent user interface.. if no UI applies, does nothing.

Peter: my concern is I need to know whether it showed something or not. Maybe I have my own UI, but want to defer to the browser if the browser has one. Fair to give me a result that says I can't do this vs user hit escape

Ken: you don't want to show a button if it doesn't do anything

Tess: I don't think there's a way to detect that

Peter: feels problematic

Rossen: behaviour discoverability is important. If you're going to trigger a UI, successful or not, you need to know what actions to take, whether before you call the API or as a result of it. This is missing.

Peter: will leave comment

Rossen: alternatively they can start by restricting this to file picker. They will throw an exception if it's not supported.

Peter: isn't there a situation where it may silently do nothing?

Tess: that's correct

Rossen: if the elements relevant global object does not have transient activation it will throw a not allowed error... but to the point of input type text.. can be used to suggest stuff to the user

Peter: I can't see picker cases for text.. there are other flavours of text input. I'll leave a comment.

Rossen: otherwise direction and general intent is good. This is needed. a step in the right direction.

Comment by @plinss Dec 13, 2021 (See Github)

One concern here is feature detection, which is already difficult and fragile for various input types. I want to be sure that developers can detect if the browser can display a picker so they have the option to adjust their UI and/or display a custom picker when needed.

Otherwise we're generally happy with this and are glad to see it moving forward.

Comment by @beaufortfrancois Dec 14, 2021 (See Github)

Rejecting the showPicker() promise with NotSupportedError may help with whether picker was shown or not. What do you think @domenic?

if ("showPicker" in HTMLInputElement.prototype) {
  try {
    await document.querySelector("input").showPicker();
  }
  catch (error) {
    if (error == "NotSupportedError") {
      /* Show custom picker */
    }
  }
} else {
  /* Show custom picker */
}
Comment by @domenic Dec 14, 2021 (See Github)

Thanks for bringing this up; it's quite a worthwhile discussion.

I think this is a tradeoff. By changing the behavior to make whether a picker was shown or not detectable, we introduce compat issues that constrain browsers from changing their UI in the future. I.e., adding or removing pickers from controls could now become a breaking change for websites. This is an area browsers have been hesitant to be constrained on, in the past.

It also introduces potential interop issues. Right now, if you call showPicker(), it will never throw. But with that proposal, it might work fine in some browsers, and throw in others. This could lead to scenarios where, in the browsers you test with, there's no need for a catch block, and so the developer doesn't add one. But then other browsers can't access your site. The same is true for other APIs that expose support, e.g. a boolean return value or a separate canShowPicker() function.

So adding any sort of feature-detection which exposes whether a browser supports a given picker, or not, creates new interop and compat risks that the current proposal doesn't have. But, it makes the proposal more useful for the specific case where a developer definitely wants to show a picker, even if a browser doesn't support it, and thus plans to perform good feature testing and add good fallbacks for such non-supporting browsers.

My instinct is to wait to gather more data on in-the-wild usage to see whether the majority of use cases are:

  • It'd be nice to show a picker here, if the browser supports it; otherwise the user can just type; vs.
  • I definitely need to show a picker here, and need to know if that won't work, so that I can display my own fallback.

The current API is designed more for the former. If we find out that in the wild people are actually more interested in the latter, then we can consider adding feature detection abilities to serve that use case, and having a cross-browser discussion about whether that's worth the compat and interop risks.

Comment by @plinss Dec 14, 2021 (See Github)

It's anecdata (and real-world data wins ofc), but I can assure you that the 'I really want a picker here (because users typing dates is extremely error-prone), and would prefer the native one, but will roll my own if I have to' situation has happened to me. There are also a lot of UI widgets out there implementing date pickers, and I expect most of them fail somewhere on a11y, i18n, and l10n, so user experience would be well served if they can use a native picker that gets it right when available.

Provided that showPicker() fails predictably when a given picker isn't available from day one I think the potential risk of interop problems is fairly low. Especially as not all UAs are likely to implement all the possible pickers at the same time, authors will have plenty of incentive to detect failure. Historically some UAs didn't even support date pickers on all platforms (not sure about current reality there).

If showPicker() sometimes throwing exception is problematic, there are other approaches like simply returning null that would be less disruptive. Note also it's important to be able to tell the difference between a UA failing to display a picker vs the user dismissing the picker with no selection. (Maybe if a user dismiss also throws an exception then everyone has to deal with exceptions...)

Which brings up another thought, what about accepting an AbortSignal in showPicker()?

Comment by @domenic Dec 14, 2021 (See Github)

Which brings up another thought, what about accepting an AbortSignal in showPicker()?

To allow the web developer to dismiss a picker even if the user is interacting with it? Yeah, we mentioned

It's possible closePicker() might be useful, and we could consider adding that if developers ask for it.

as a possible future extension in the explainer.

Comment by @plinss Dec 14, 2021 (See Github)

A closePicker() method could be useful, but it's not quite the same as accepting an AbortSignal. The latter has the advantage of closing the picker when something somewhat unrelated (and isolated from the code handling the picker) happens without having to add a bunch of glue code. Seems useful to me, but just a suggestion.

Comment by @domenic Dec 14, 2021 (See Github)

Yeah, I agree that's probably a better API than closePicker() in particular, if we do hear requests of that sort.

Discussed Feb 14, 2022 (See Github)

Concers about feature detection don't seem to be answered, propose closing with concerns at plenary to give Lea/Tess a change to have input.

Discussed Apr 4, 2022 (See Github)

Peter: my real concern is that it's not detectable... I think this needs to be detectable.

Dan: that's the guidance in the design guidelines.

Peter: yes...

Rossen: there was one suggestion from Francois but didn't go anywhere...

Rossen: The only thing remaining before we can close this is detectability. Everyone agrees the feature is needed and good.

Peter: Domenic's last comment "wait and gather more data"... implement now and wait and see and get data? would like to see a plan for how that data is gathered and loop back. Or we have consensus that it really needs to be detectable to cover all use cases, then just do it, and we can say that.

Rossen: this is only for pickers that are browser native? or any picker? some browsers invoke a platform native picker... font picker, etc... is intent for showpicker to work with those cases as well?

discussion on types of pickers

Tess: missed that distinction but now I get it.. UI provided by browser which may be OS or browser UI, vs picker supplied by a custom component.

Rossen: already talking about component vs browser

Peter: that's what I've been talking about. I want date input, if browser has a decent one I'll use it, if not I want to fall back to mine, which may have issues but is better than them typing text

Tess: you want to know is the one you have crap so I can use my own

Peter: or do you even have one. Whether it's OS or browser, in theory should be detectable. Is there another factor?

Rossen: if showpicker .. if the only way to detect it right now is to call showpicker and look at promise result you're potentially going to invoke something unexpected .. it's very clunky.

Peter: totally fine with a hasPicker method. Also okay with showpicker throwing new methods.. not going to complain if a picker shows up

Rossen: maybe I like the colour picker in firefox native browser UI but I prefer to see the native fontpicker from Windows.. if they tell me they have their own font picker I want to show my library font picker because I don't have a way to invoke the OS native picker which I like.. it's three choices I'm trying to make.. I can detect between the first two (browser or OS native UI) and the third. But you're not allowing me to make the further distinction down the path. Which I'm pretty sure is important for some platforms and some browsers

Peter: similar case historically.. on one OS the date picker is really nice and on the same browser but a different OS the browser has one but it's shit. The only way to detect that is UA string... browser is going to just say yeah I've got a date picker. No feedback of if it's a good one or not. Not sure it's fair to ask for how good is your picker.

Rossen: detectibility further fine grained is needed..

Peter: has picker gives back an enum, native, OS, none.. Leave that feedback?

Rossen: [leaves feedback]

Peter: do we have consensus that we really want detectability?

Rossen: I don't see the reason why this is not needed. If you don't care about detectability just call showPicker and deal with what is there

Peter: Dominic's feedback is he thinks if showpicker throws an exception that will break code. Makes the argument we should implement it and get data. My argument is if you implement it without throwing an exception you're going to have a whole lot of code out there that will never expect an exception and we can never change it

Tess: self-fulfilling prophecy...

Peter: we can always make it not throw later without breaking any code

Rossen: on top of it you're not allowing... nicer ... [behaviour]

Peter: if we have consensus that it should throw if you don't have one we should leave that feedback

Rossen: yep [leaves comment]

Comment by @atanassov Apr 4, 2022 (See Github)

@domenic, we had another round of discussions with TAG today and our consensus is still wanting to see detectability of the proposed feature. We want to close the review with this last issue addressed.

(assuming detectability is provided) Another question I have is whether you considered exposing finer granularity of UI detectability? In the case a picker is supported, that picker can be UI implemented by the browser vs the OS native picker. This type of distinction will be just as important when component implementers are making the decision to show native vs theirs.

Comment by @domenic Apr 4, 2022 (See Github)

Thanks for the feedback! My current position is that it's not a worthwhile tradeoff, to constrain and expose browser UI specifics in that way, but I understand we differ in that regard.

Discussed Apr 11, 2022 (See Github)

Peter: needs to be feature detectable

Dan: close based on feedback from Dominic? Satisfied with concerns? Or unsatisfied?

Peter: somewhere in between.. I want the feature but I think this is a huge mistake and really needs to be detectable in a way that will be backward compatible. The path Dominic is going down we cannot add detectability in a reasonable way. Unsatisfied.

Lea: agree with Peter

Dan: to plenary..

Discussed Jun 6, 2022 (See Github)

Rossen: closing as unsatisfied.

closed

Comment by @atanassov Jun 6, 2022 (See Github)

Thank you for confirming your position @domenic. As you stated, we do differ in our opinions, and it doesn't look we can add anything else for now, thus closing the review. Thank you for working with us and if you want us to do another round of reviews, please reopen.