html icon indicating copy to clipboard operation
html copied to clipboard

Autofocus attribute doesn't work reliably

Open davetapley opened this issue 5 years ago • 9 comments

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 avatar Feb 25 '19 23:02 davetapley

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 avatar Feb 25 '19 23:02 davetapley

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 avatar Feb 25 '19 23:02 davetapley

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.

davetapley avatar Feb 26 '19 21:02 davetapley

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.

ChristophP avatar Feb 27 '19 08:02 ChristophP

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 avatar Feb 27 '19 15:02 davetapley

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 avatar Feb 27 '19 16:02 davetapley

I also tried ⬆️ here using attribute instead:

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

Same behavior 😞

davetapley avatar Feb 27 '19 16:02 davetapley

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.

ChristophP avatar Mar 05 '19 02:03 ChristophP

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).

SimonAlling avatar Apr 02 '23 10:04 SimonAlling