Closed beaufortfrancois closed 2 years ago
Should this also come along with an open
attribute, similar to dialog
?
show a browser picker (if supported) for
<input type="date">
,<input type="month">
,<input type="week">
,<input type="datetime-local">
, and<input type="time">
Should this explicitly only work for these inputs? Other inputs which have pickers in some browsers are tel
/email
(contact picker), url
(history picker), password
(password manager), number
, color
, and file
.
Also <select>
.
(The other thing I was thinking about, which is somewhat off-topic, is that you might want to display the picker exclusively as some sites do (i.e., without the input box), but perhaps that's best left to libraries as there's often additional requirements.)
Should this also come along with an
open
attribute, similar todialog
?
I'm not sure. According to the spec, a dialog element without an open attribute specified should not be shown to the user. Shall we then have an "open" attribute for HTMLInputElement
that prevents user to show a picker? I don't think so. Thoughts?
show a browser picker (if supported) for
<input type="date">
,<input type="month">
,<input type="week">
,<input type="datetime-local">
, and<input type="time">
Should this explicitly only work for these inputs? Other inputs which have pickers in some browsers are
tel
/url
(history picker),password
(password manager),number
,color
, andfile
.
FYI There's a JS API already for Contact picker
Currently tel
, email
, url
, password
, and number
have no pickers from what I can see. color
however seems like a good candidate that would benefit from this.
Having showPicker()
for file
may not be appropriate as we already have showOpenFilePicker().
Also
<select>
.
We'd have to find out if that's something developers need.
In Chrome I agree those do not have pickers. In other browsers they do. (In some cases historical browsers like Opera.)
Having
showPicker()
forfile
may not be appropriate as we already have showOpenFilePicker().
Not supported in Firefox or Safari though. And we could still have a more general method even with an existing method for a specific case. showOpenFilePicker()
is async
though, and it returns the file that was picked. So if we want the generic method to work like showOpenFilePicker()
, it should also be async
and return whatever was picked.
I was given an action item to see what click()
does today to guide this discussion. It turns out interop here is a bit messy. Test page: https://boom-bath.glitch.me/pickers.html . Results:
Element | Firefox (desktop) | Firefox (mobile) | Chrome (desktop) | Chrome (mobile) | Safari (desktop) | Safari (mobile) |
---|---|---|---|---|---|---|
<input type="date"> |
* | * | ❗ | ❗ | * | |
<input type="month"> |
* | ❗ | * | |||
<input type="week"> |
* | ❗ | ||||
<input type="time"> |
* | ❗ | * | |||
<input type="datetime-local"> |
* | ❗ | ❗ | * | ||
<input type="color"> |
❗ | ❗ | ❗ | ❗ | ❗ | * |
<input type="file"> |
❗ | ❗ | ❗ | ❗ | ❗ | ❗ |
<select> |
* | * | ||||
<select multiple> |
* | * |
❗ means the picker does open, on both programmatic click()
and when the user clicks on the <label>
's text.
* means the picker does not open via programmatic click()
, but it does open by the user click on the <label>
's text.
Blank means neither clicking on the label nor programmatic click()
will open the picker.
E.g. on mobile Chrome, the user clicking on the label text for <input type="date">
will open the picker, but the user clicking on the label text for <select>
will not open the picker. And on desktop Chrome, the user clicking on the label only opens the picker for <input type="file">
and <input type="color">
.
None of the elements in "Not very likely to have a picker, but could conceivably", besides sometimes besides <select multiple>
, ever show pickers, so I omit them from above.
Thankfully nobody showed pickers on focus()
.
I can't think of anything unifying these. E.g. you might think Chrome's approach is "display fullscreen pickers, don't display anchored pickers", but <select>
on mobile is a fullscreen picker and not displayed, whereas <input type="color">
on desktop is an achored picker and is displayed.
Here's my proposal:
Standardize on Firefox/Chrome desktop's click()
behavior as the minimal interoperable subset. That is, for legacy reasons, click()
shows the picker on color and file, on both desktop and mobile, but it does nothing in all other cases.
Introduce showPicker()
which is supposed to show the picker whenever it exists. Namely,
Pick one behavior for the user user clicking on a label. That behavior should either be the same as click()
or the same as showPicker()
, but I'm not sure which. We should debate what folks feel a better user experience/more compat risky/etc.
After showPicker()
has been available for some time, hopefully Chrome mobile and Safari can align on the above minimal behavior for click()
.
We could also contemplate not special-casing <input type="color">
, as I suspect fewer people are relying on it showing the picker than <input type="file">
, but probably that's not worth the risk.
Thank you @domenic for the thorough investigation.
Here are my results on Safari Mobile. Feel free to edit your post earlier.
Element | Safari (mobile) |
---|---|
<input type="date"> |
|
<input type="month"> |
|
<input type="week"> |
|
<input type="time"> |
|
<input type="datetime-local"> |
|
<input type="color"> |
|
<input type="file"> |
❗ |
<select> |
Thanks @beaufortfrancois! You inspired me to borrow my girlfriend's iPhone and do some of my own testing on the <label>
issue. I've updated the above with full results, and also split out Firefox desktop/mobile since they are sufficiently different on the <label>
issue as well.
New test page with no user activation: https://boom-bath.glitch.me/pickers-2.html
Results:
<input type="color">
with no user activation, at (0, 0) coordinates. Seems like a bug.Conclusion: we can definitely impose a user-activation restriction on both the activation behavior and the new showPicker()
method.
New test page where the pickers are in a cross-origin iframe: https://creative-abrupt-bladder.glitch.me/
Results: on desktop Firefox and desktop Chrome, at least, there is no difference in behavior from the first-party case. I.e. you can open file and color pickers with a user-activation click.
Conclusion: it would be a web compat lift to lock down cross-origin iframe color and file pickers. So although that's a good idea, I think we should pursue it as a separate issue, since I suspect it'd cause a lot of web developer pain (e.g. third-party file picker widgets).
We could make the new showPicker()
API be locked down even if click()
is not. Since for non-color/file inputs, it is presenting a new capability. But I think we should still allow showPicker()
to work in cross-origin iframes for color and file, as otherwise people will just have to use click()
more often. We can work on locking down both at once in the future.
I like the idea of restricting the new capability where it makes sense to do so.
@domenic Is there anything I can do to help moving this forward?
@beaufortfrancois I'll work on the spec soon, but a few things could help from the implementation side:
Work on a prototype for showPicker()
:
(0,0)
) for things like color or date, like click()
does currently.Work on a flag that aligns mobile Chrome's behavior for click()
with desktop Chrome's (i.e., it only works for color and file). Shipping this will be difficult and probably something we'll need to delay until we have showPicker()
shipped and evangelized, but it's worth doing at some point.
Fix click()
in desktop Chrome on color inputs to not open a picker at (0,0)
when called without user activation; instead it should do nothing (like all other calls to click()
without user activation).
- On desktop the picker should open at a sensible location (not
(0,0)
) for things like color or date, likeclick()
does currently.
If the HTML input element is already in the DOM, it makes sense to open where the element is. However if the element is not in the DOM already, (0,0)
is where it opens by default. Do you want to change that behavior?
Interesting! Let me test what all browsers do in that case.
- Work on a prototype for
showPicker()
:
Here's the WIP Chromium CL for the new showPicker()
method: https://chromium-review.googlesource.com/c/chromium/src/+/3056920
In the process of prototyping @beaufortfrancois pointed out that <select>
uses HTMLSelectElement
and not HTMLInputElement
. So there's a question as to whether we should define showPicker()
for both of these, or just HTMLInputElement
.
Although IMO treating <select>
and <input>
as on equal footing is nice theoretically, and I suspect web developers probably want the ability to open select popups as well, my instinct is to put off work on showPicker()
for select for now pending more developer feedback and successfully landing it for HTMLInputElement
:
<input type=date>
etc., click()
on select does not open the picker in any browser today, so select.showPicker()
would be a new capability.Happy to discuss more here or in the triage call. In particular it'd be interesting to hear peoples thoughts between: do select.showPicker()
at the same time as input.showPicker()
, do select.showPicker()
shortly after input.showPicker()
once we have a successful spec/implementation for the former, do select.showPicker()
only after gathering web dev sentiment to ensure it's useful, or never do select.showPicker()
.
Interesting! Let me test what all browsers do in that case.
Here are my results:
Click() on the element outside of the DOM | Safari (desktop) | Firefox (desktop) | Chrome (desktop) | Safari (mobile) | Firefox (mobile) | Chrome (mobile) |
---|---|---|---|---|---|---|
<input type="color"> |
- | Opens at the bottom left corner of the screen | Opens at top left of the page | - | Opens modal dialog | Opens modal dialog |
<input type="file"> |
Opens modal dialog at the center of the page | Opens modal dialog at the center of the page | Opens modal dialog at the center of the page | Opens small popup dialog where user clicked | Opens bottom modal dialog | Open bottom modal dialog |
Thanks. I guess those results made me realize it's kind of device- and situation-dependent. So probably the spec will not actually say anything about the location of the picker, or if it does it'll say something vague like "associated with the control, if the control is being rendered".
FYI The showPicker()
method is now available in Chrome Canary 🐣 so you can try it and file feedback.
<button>Show Date Picker</button>
<script>
const button = document.querySelector("button");
button.addEventListener("click", () => {
try {
const inputDate = document.createElement("input");
inputDate.type = "date";
// Show programmatically the browser date picker.
inputDate.showPicker();
// Get date entered by user.
inputDate.addEventListener("change", event => {
console.log(`Got ${event.target.value} date`);
});
} catch (error) {
// Use custom library as a fallback...
}
});
</script>
See https://twitter.com/quicksave2k/status/1457650699832004609
Do we expect all use cases to rely on manual closing of the picker? If not, we could consider adding closePicker
as well.
Thanks for the feedback @mathiasbynens!
The browser closes automatically the picker as soon as this one loses focus (when user clicks outside for instance).
I'm not sure then how a closePicker()
would be used. Did you have something specific in mind?
I could e.g. imagine a scenario with multiple <input>
s, some of which triggering a browser-native picker, others triggering a custom picker implementation, through interaction with some other DOM element. It seems worthwhile to allow custom and native picker UIs to co-exist, with any native ones getting closed as soon as a custom one opens, regardless of what triggers the opening. It sounds like this is already handled for the common case where the user has to click somewhere outside the native picker to trigger the other one, and maybe that’s good enough!
To be clear, I’m not proposing / advocating for closePicker
— I just wanted to make sure its exclusion was not an oversight but an intentional choice. 👍
I've posted https://github.com/whatwg/html/pull/7319 with a spec PR. Review appreciated!
Reposting a comment from blink-dev: https://groups.google.com/a/chromium.org/g/blink-dev/c/fEebe5uXQ1I/m/NWvUs_QEAgAJ
tl;dr - given the EyeDropper API proposal, maybe there's a chance to align on method names that open a picker / UI widget? Was open
considered instead of showPicker
?
We haven't had much discussion about the naming, so thanks for starting it.
Personally, I don't feel strongly about the name. But some background:
The showPicker()
name is chosen to align with window.showOpenFilePicker()
. I'll also note there's some unresolved feedback on the EyeDropper
issue tracker asking if maybe it should become window.showColorPicker()
: https://github.com/WICG/eyedropper-api/issues/18
I do think fileInput.open()
and dateInput.open()
are a bit less clear than fileInput.showPicker()
and dateInput.showPicker()
, but not by much.
Curious to hear what others think.
open() sounds a bit odd for a method on an input element. It isn't immediately clear to the reader what it would do. showPicker() is quite obvious.
(and since EyeDropper API is just a proposal, it could be changed to have showPicker?)
I guess it could go the other way, yeah - I also don't have strong feelings on naming, but consistency would be nice since both of these are new.
On a file input I could see people thinking .open()
opens the file.
For an "empty" <input type=file>
, there's no file to open. I guess I wouldn't expect any different behavior with a non-empty files
/value
.
I don't feel strongly either about the naming of this method and I agree some consistency would be great as well for web developers.
FYI I've left a comment at https://github.com/WICG/eyedropper-api/issues/18#issuecomment-964866716 to let EyeDropper folks know about this issue.
Developers have also been asking for the ability to open suggestions for <input list="…">
with <datalist>
and this API could also work for it:
That's a great point. I forgot to test those. IMO showPicker()
should definitely open those pickers; I'll see if we can update the spec to be more explicit about that in some way.
I have a WIP Chromium CL at https://chromium-review.googlesource.com/c/chromium/src/+/3284804 to open those pickers. Good catch @mnoorenberghe!
@mnoorenberghe https://chromiumdash.appspot.com/commit/92e5fe8556d41ba34766129574df624ea2413ffa has landed. Give https://show-picker.glitch.me/ a try in Chrome Canary 98 98.0.4726.0. You'll need to enable the experimental web platform features flag for this.
FYI I've just sent an intent to ship at blink-dev: https://groups.google.com/a/chromium.org/g/blink-dev/c/YfnM0ubs53k
@domenic @beaufortfrancois Any chance to help with clarifying the question at https://bugs.webkit.org/show_bug.cgi?id=237192#c19? This WebKit patch is an import of the Chromium showpicker() CL. Thanks.
Is it correct that when called on an HTMLInputElement of a type that has no picker, that showPicker should check cross-frame and user gesture status, throw exceptions if either of those applies, but then if neither applies, silently do nothing?
As you can see below, in Chromium showPicker
will throw security error if type is not file
nor color
. However it will check user gesture status for all types. See https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/html/forms/html_input_element.cc;l=2218;drc=72575413b1662ce93e9137f99303d0d5a3942f0f
void HTMLInputElement::showPicker(ExceptionState& exception_state) {
LocalFrame* frame = GetDocument().GetFrame();
if (type() != input_type_names::kFile && type() != input_type_names::kColor &&
frame) {
const SecurityOrigin* security_origin =
frame->GetSecurityContext()->GetSecurityOrigin();
const SecurityOrigin* top_security_origin =
frame->Tree().Top().GetSecurityContext()->GetSecurityOrigin();
if (!security_origin->IsSameOriginWith(top_security_origin)) {
exception_state.ThrowSecurityError(
"HTMLInputElement::showPicker() called from cross-origin iframe.");
return;
}
}
if (!LocalFrame::HasTransientUserActivation(frame)) {
exception_state.ThrowDOMException(
DOMExceptionCode::kNotAllowedError,
"HTMLInputElement::showPicker() requires a user gesture.");
return;
}
input_type_view_->OpenPopupView();
}
As you can see below, in Chromium
showPicker
will throw security error if type is notfile
norcolor
. However it will check user gesture status for all types.
Thanks @beaufortfrancois for your prompt response. Yes, this is what we have in WebKit imported code as well. What we are trying to clarify here is, we check on cross-frame and user gesture status and throw exceptions if either of those applies. What is neither applies, silently do nothing?
As per https://github.com/whatwg/html/issues/6909#issuecomment-956747809, it mentioned that "It should not consume user activation.". Does it mean that silently doing nothing is intentional?
That is my understanding according to https://html.spec.whatwg.org/multipage/input.html#dom-input-showpicker
The showPicker() method steps are:
- If this's relevant settings object's origin is not same origin with this's relevant settings object's top-level origin, and this's type attribute is not in the File Upload state or Color state, then throw a "SecurityError" DOMException.
- If this's relevant global object does not have transient activation, then throw a "NotAllowedError" DOMException.
- Show the picker, if applicable, for this.
Let's wait on @domenic answer as well.
Yes, that is correct.
3. Show the picker, if applicable, for this.
Thanks both. Just to confirm - If not applicable, do nothing?
Yes, if you read the algorithm for "show the picker, if applicable", step 4 says
Otherwise, the user agent should show any relevant user interface for selecting a value for element, in the way it normally would when the user interacts with the control. (If no such UI applies to element, then this step does nothing.)
Yes, if you read the algorithm for "show the picker, if applicable", step 4 says
Otherwise, the user agent should show any relevant user interface for selecting a value for element, in the way it normally would when the user interacts with the control. (If no such UI applies to element, then this step does nothing.)
Perfect. Thanks very much!
Background:
Developers have been asking for years for a way to programmatically open a browser date picker. See https://www.google.com/search?q=programmatically+open+date+picker+site:stackoverflow.com Because of that, they had to rely on custom widget libraries and CSS hacks for specific browsers.
Date pickers in Chrome Desktop, Chrome Mobile, Safari Desktop, Safari Mobile, and Firefox Desktop (July 2021).
Proposal
A new
showPicker()
method to theHTMLInputElement
interface would show a browser picker (if supported) for<input type="date">
,<input type="month">
,<input type="week">
,<input type="datetime-local">
, and<input type="time">
HTML elements . This method is handy, easy to use, and friendly to discover.As it's already possible to listen to
change
events to know when the HTML element value changes, I believe it's OK to make this method synchronous.Example usage
Feature detection
Open questions
Alternative considered
Adding a brand new
DatePicker
object that could be used with HTML elements or in standalone mode seems overkill.According to https://github.com/whatwg/html/issues/3232#issuecomment-345279014, it seems like a synthetic
click()
should not trigger a browser date picker.Resources