react-spectrum
react-spectrum copied to clipboard
Support customizing the tab order of an uncontained FocusScope
Closes #2421.
This PR implements the feature proposed in the linked issue by adding a new prop to FocusScope
named tabOrder
. tabOrder
can take on the following values:
-
'replace-trigger'
(default) -
'after-trigger'
-
RefObject<HTMLElement>
The string options 'replace-trigger'
and 'after-trigger'
values only function when restoreFocus
is enabled.
'replace-trigger'
captures the existing behavior of FocusScope
where tabbing backwards out of the scope moves focus to the element before the trigger, and tabbing forwards moves it to the node after.
'after-trigger'
behaves the same as 'replace-trigger'
but covers the frequent use case I encounter where I want the trigger element to remain as part of the tab order. Here, tabbing backwards moves focus to the trigger rather than the element before it.
Finally, passing a ref allows for full control over how focus moves out of the scope. This is useful when the scope has no trigger element or if its position in the virtual DOM is far away from the trigger's position.
✅ Pull Request Checklist:
- [x] Included link to corresponding React Spectrum GitHub Issue.
- [x] Added/updated unit tests and storybook for this change (for new code or code which already has tests).
- [x] Filled out test instructions.
- [ ] Updated documentation (if it already exists for this component).
- [x] Looked at the Accessibility Practices for this feature - Aria Practices
📝 Test Instructions:
🧢 Your Project:
@kherock You may also want to consider https://github.com/adobe/react-spectrum/pull/2445. It adds support for passing a RefObject<HTMLElement>
to the FocusScope
's restoreFocus
prop, which is similar to how you have implemented tabOrder
. It also addresses the use case where focus gets lost when the restore focus element has been removed from the DOM, as happens when a MenuItem is triggered to open a Dialog.