Description
Provide a general summary of the feature here
Right now useFocusManager
provides functions for focusing the next, previous, first, and last elements.
I would love to have four additional functions: findNext
, findPrevious
, findFirst
, and findLast
, which simply return the focusable element (or null
) and don't attempt to focus it.
🤔 Expected Behavior?
useFocusManager
provides findNext
, findPrevious
, findFirst
, and findLast
for finding focusable elements, without actually focusing them.
😯 Current Behavior
useFocusManager
only provides functions for focusing elements, not for checking presence/absence of focusable elements.
💁 Possible Solution
Lightly refactor createFocusManagerForScope
to extract and return findNext
, findPrevious
, findFirst
, and findLast
(See PR that closes this issue)
🔦 Context
Alert
My immediate use case is a custom alert/alertdialog component with the following logic:
- If the alert content does not contain a focusable element, it should disappear after 5 seconds (it's purely informative and static)
- If the alert content contains a focusable element, it should never automatically disappear (because it requires/enables user action)
I can imagine this UX being useful in any alert or alert-like component that wants to give the user extra time to take an action. It wouldn't be good UX to call focusManager.focusFirst
here, because assistive tech users should be allowed to ignore certain alertdialog
s and stay where they are in the page.
An alternate solution is to add a prop to my alert component that lets devs tell the component whether or not content contains a focusable element. But this is a tedious DX, and over time, it's virtually impossible to make sure the prop value stays correct and in sync with other code.
Tablist
In the past, I have also written and used a similar feature for a custom tablist component, specifically to meet this tablist ARIA Authoring Practice:
When the tab list contains the focus, moves focus to the next element in the page tab sequence outside the tablist, which is the tabpanel unless the first element containing meaningful content inside the tabpanel is focusable.
In other words, the tabindex
of the tab panel should be 0
if findFirst(...)
is unable to find a focusable element inside the panel.
In React, I would likely just use React Aria's tablist and not worry about these details, but for more custom implementations, the focusable finding feature could be useful.
💻 Examples
function CustomAlert() {
return (
<FocusScope>
<CustomAlertChild />
</FocusScope>
)
}
function CustomAlertChild() {
const focusManager = useFocusManager();
const [timeout, setTimeout] = useState<'never' | number>('never');
useLayoutEffect(() => {
setTimeout(
focusManager.findFirst()
? 'never'
: 5000
)
}, [focusManager])
// ...other alert logic
return (
<div>
...
</div>
)
}
🧢 Your Company/Team
Just me, independently
🕷 Tracking Issue
No response