-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Modal itself receiving focus rather than first tabbable element #54106
Comments
Pinging @ciampo for input from a components maintenance perspective and also @alexstine from a a11y and UX standpoint. |
This is one of those highly subjective accessibility topics which has a lot of requirements.
While I think it is okay to allow developers to manage focus differently, I don't think it should be a default to focus a control inside the modal. Thanks. |
Ok so this comes down to best practices and developer education (myself included). So in the specific example of #53735 we should focus the input as all the criteria are met. However in other examples this might not be desirable.
Actually I believe we need to update the |
@getdave Correct.
|
Some ideas for changes to the Pass an indexPass an index which represents which of the found tabble focusable elements within the Modal <Modal
{ ...otherProps }
focusOnMount={ 1 } // select the 2nd element
> Pass an functionDefine a function which is passed all the focusable nodes allowing you to select one: <Modal
{ ...otherProps }
focusOnMount={ ( focusableNodes ) => {
return focusableNodes[ 1 ];
} }
> |
Sorry, yes, my recommendation should have come with the caveats @alexstine provided here! I wonder whether, rather than try to fudge something into the <Modal { ... }>
<InputControl { ... } autoFocus />
<Button { ... }>Close Modal</Button>
</Modal> I tried it locally, and it seems to work. Initially at least – it messes with focus management when closing the dialog, but our energy might be better spent resolving that than reinventing this particular wheel. Just a thought. Autofocus.breaking.tab.flow.on.dialog.close.mov |
I think |
@getdave would the suggested In case it doesn't, and you'd be still interested in making changes to
What do you think? |
Thanks everyone. That's all really helpful.
What I'd like to avoid is people selecting non-tabbable/focusable elements. If we use the callback approach the callback would receive an array of tabbable elements meaning that the consumer would need to pick from a list that is pre-filtered for a11y compliance. If we allow access to entire DOM then it could lead to folks introducing a11y issues.
I seem to recall this property doesn't fit the React paradigm that well. I'm going to see if I can dig up some concrete rationale for that now and report back here. |
This article seems to suggest that autofocus may not always be unreliable. I found out that React actively manages the attribute to cover up some browser inconsistencies in how it's handled. It does this by calling In short most advice I could find seemed to point to actively managing via a |
I personally like the current In other words maybe |
Looking at this, it seems it will probably require moving the Close button outside of the element which receives the We could explore this route and leave existing APIs untouched though. What do you think @ciampo? |
I'm not sure that's feasible, since the element receiving the gutenberg/packages/components/src/modal/index.tsx Lines 223 to 227 in ebae2d5
I thought about moving the close button after the Modal's content (in terms of DOM order), but that would just partially resolve the problem, since any other tabbable element in the Modal's header would receive focus. Would that be an acceptable solution? Otherwise, I think that the cleanest way to improve this is to augment the |
I don't know much about how |
@andrewhayward That's probably an option. Please also see these other suggested routes for enhancing I believe it's essential that we only allow consumers of the API to select nodes that are tabbable and exposing overly flexible APIs can lead to problems. |
This would require verification, but as far as I know calling That being said, as an API consumer, while preventing the API from receiving non-focusable nodes is definitely a good thing to aim for, I'd also want to see that balanced against the complexity of the API itself. |
With respect I think it could. Let's say I'm "some developer" and I've had an a11y audit which says the modal must focus an element on mount. However, i'm not well versed in a11y so I use the API to attempt to place focus on a
I agree. Could you explain what part of the proposed callback API are feeling complex? How does that compare to an API which allows you to select any element? To be clear, I'm really grateful for you input. I'm genuinely curious to get wider perspectives. I'm not sure I have the right answer here so I'm keen to stress test my assumptions. Your help is appreciated 🙇 |
Agree with @getdave . Developers can and have tried to use focus on nodes that can't receive focus. It has to be checked. Might want to check some of the utility functions in wordpress/dom. For example, focus does not always mean tabbable so the functions are split. You can focus an element with |
@ciampo what is convoluted in allowing to select an index from the list of tabbable elements? It seems consistent with the way browsers treat this whole focus business. |
I think that something like <Modal
focusOnMount={ 4 }
{ ...props }
>
{ /* content */ }
</Modal> Can be really mysterious and difficult to comprehend to any developer. To know what element is being focused, you'd need to inspect the modal's content, know exactly what are the focusable elements, and try your luck. Finally, despite the fact that the Instead, I think that passing a { /* With a ref */ }
<Modal
focusOnMount={ buttonToFocusOnMountRef }
{ ...props }
>
{ /* content */ }
<button ref={ buttonToFocusOnMountRef }
</Modal>
{ /* With a callback */ }
<Modal
focusOnMount={ ( tabbables ) => {
// Literally any logic which returns either a focusable element, or undefined
return tabbables.filter( (t) => t.id === 'button-to-focus' )
} }
{ ...props }
>
{ /* content */ }
</Modal> |
Sorry, wasn't clear. I don't think that we should necessarily take Some Developer's word for what is or is not accessible. For example, if they provide a
I don't have any strong feelings on the matter – just seems easier and more React-y to stick a |
I think @ciampo 's explanation on preffered API is perfec and I support the callback approach since it gives a developer the chance to build more maintainable code.
This part seems unavoidable if we have an api that allows focus to be controlled from outside the modal itself. A test would take care of keeping this in check. |
Reopening for reconsideration.
The whatwg / html specification for the native |
As explained in #54590 (comment), this issue was about adding one additional choice for consumers of the component regarding focus handling on mount. The component's default behaviour is still to focus the Given the above, I think that we can close this issue. |
Yes, the default will always be to focus the opened dialog. This simply allows us to place focus if developers feel there is a need to change it. I disagree with the official spec if this is now considered invalid. It makes little sense to not focus an input for example if you already have |
Fixed by #54590 |
The standard
Modal
component defines a tabindex which forces it to be focused when mounted:gutenberg/packages/components/src/modal/index.tsx
Line 232 in 8e0fdca
As this is non-configurable it appears to be a deliberate decision but one that may be questionable from an a11y perspective as noted by @andrewhayward (see below).
Raising this Issue to discuss whether this attribute needs to be reconsidered or made configurable.
What is the rationale behind it and what arguments are there for/against removing it?
For what it's worth, from an accessibility perspective at least, it's actually strongly advised that focus is moved to a control within the dialog, rather than keeping focus on the dialog itself. In this case, where the sole purpose of the dialog is to update the text value, the text field would be a good candidate to automatically receive focus here.
Originally posted by @andrewhayward in #53735 (comment)
The text was updated successfully, but these errors were encountered: