elm / html

Use HTML in Elm!
https://package.elm-lang.org/packages/elm/html/latest/
BSD 3-Clause "New" or "Revised" License
395 stars 99 forks source link

Autofocus attribute doesn't work reliably #186

Open davetapley opened 5 years ago

davetapley commented 5 years ago

SSCCE on Ellie:

What I expect: The input is focussed any time it it appears on screen. What happens: The input is focussed on page load, but not after 'Hide input' then 'Show input' are pressed in succession.

Seen on MacOS Chrome Version 71.0.3578.98 (Official Build) (64-bit).

Elm 0.19.

davetapley commented 5 years ago

I presume it's due to this:

autofocus is defined to work reliably only on page load. It is not really suited for situations where you are swapping, or opening, or unhiding DOM elements such as in a single-page application framework. You are likely to have to resort to handling the autofocusing yourself.

If that's the case them I think Elm should either manage the autofocus in

situations where you are swapping, or opening, or unhiding DOM elements

..., or it should not provide autofocus in HTML.Attributes.

davetapley commented 5 years ago

I don't know if it's due to some shadow DOM magic, but I just tried this JS workaround and it doesn't work either, leaving me with no way to get an input to autofocus? 😱

Array.from(document.getElementsByTagName("input")).find(function(i) { return i.autofocus }).focus()
davetapley commented 5 years ago

As mentioned here there is a solution using Dom.focus as shown here.

I'm going to make a PR to update the docs to at least call that out (although I still think it'd be nice if the autofocus attribute took care of it.

ChristophP commented 5 years ago

The HTML spec defines the behavior that autofocus will set the focus only on page load. I think it would be strange if Elm deviated from that behavior. It wouldn't hurt to be added to the docs I guess, although everything in the Html module just works how HTML works in general.

davetapley commented 5 years ago

Thanks for the link @ChristophP.

I didn't know this:

The autofocus content attribute allows the author to indicate that a control is to be focused [...] as soon as the dialog within which it finds itself is shown

I don't see a dialog in Html, but using a dialog and adding/removing open certainly seems more appealing than having to use events (namely Dom.focus).

davetapley commented 5 years ago

I tried to implement ⬆️ here using:

node "dialog" [property "open" (bool model.inputVisible)] 
            [ input [autofocus True] []]

It works insomuch as the dialog (and input) appear and disappear, but the autofocus still doesn't work. Maybe some shadow DOM shenanigans? 😞

davetapley commented 5 years ago

I also tried ⬆️ here using attribute instead:

node "dialog" (if model.inputVisible then [attribute "open" ""] else [])
            [ input [autofocus True] []]

Same behavior 😞

ChristophP commented 5 years ago

I am guessing it could be related to two things.

  1. Some timing issue: Maybe when the page loads the input isn't quite painted yet, so autofocus has no effect, because any autofocus that gets drawn after page load doesn't do anything.
  2. Ellie runs your code in an iframe. Maybe your autofocus isn't the only one on the page, or there are some scripts which "steal" away the focus from your element. Even in a situation with iframes (where there's multiple windows on the page), you can still only have one focused element to my knowledge. Otherwise, how would the browser know where to put the characters when you type.

I would try to debug it by running it on a page that you control, not inside ellie.

SimonAlling commented 1 year ago

I also tried arrow_up here using attribute instead:

node "dialog" (if model.inputVisible then [attribute "open" ""] else [])
            [ input [autofocus True] []]

Same behavior disappointed

Can confirm that this doesn't work, even in a plain web app (i.e. no Ellie, <iframe> etc). :crying_cat_face:

If I run document.querySelector("dialog").show() in the console, then the input is focused, but if I do document.querySelector("dialog").setAttribute("open", ""), then the input isn't focused (but the dialog is shown).