react-spectrum
react-spectrum copied to clipboard
Virtualizer does not scroll items into view within the browser viewport
๐ Bug Report
When the bounds of a virtualized collection extend beyond the browser viewport, and setting focus to an item within the collection that is out of view, the browser will not scroll the focused item into view.
๐ค Expected Behavior
An item receiving focus in a virtualized collection should not only scroll the item into view within the collection, but it should scroll the item into view within the browser as well.
๐ฏ Current Behavior
- Open https://reactspectrum.blob.core.windows.net/reactspectrum/0661785f30971bdbcbd291282b26836cf272c3f8/storybook/iframe.html?id=listbox--async-loading&viewMode=story
- Reduce the inner height of the browser window to be less than the height of the ListBox within the story, ~200px should be good.
- Tab to set keyboard focus to the first Item within the ListBox.
- Use ArrowDown to scroll until you focus an Item within the ListBox that is outside of the browser viewport.
- Notice that the browser does not automatically scroll the
document.bodyto bring the focused Item into view.
๐ Possible Solution
Add the following to useVirtualizer method in @react-aria/virtualizer/src/Virtualizer.tsx:
// Define an IntersectionObserver to evaluate whether the browser should scroll the element receiving focus into view.
let intersectionObserver = useMemo(() => {
const intersectionObserverOptions:IntersectionObserverInit = {
root: undefined,
rootMargin: '0px',
threshold: 1
};
const scrollIntoViewOptions:ScrollIntoViewOptions = {
behavior: 'auto',
block: 'nearest',
inline: 'nearest'
};
const intersectionObserverCallback = (entries:Array<IntersectionObserverEntry>, observer:IntersectionObserver) => {
entries.forEach(entry => {
if (!entry.isIntersecting) {
entry.target.scrollIntoView(scrollIntoViewOptions);
}
observer.unobserve(entry.target);
});
};
return new IntersectionObserver(intersectionObserverCallback, intersectionObserverOptions);
}, []);
Then at the end of the onFocus method, add the following after updating isFocusWithin.current:
// Evaluate whether the browser should scroll to bring element receiving focus into view.
if (isFocusWithin.current) {
intersectionObserver.observe(e.target);
}
๐ฆ Context
This bug was reported by a team using a static TableView that noticed when the TableView was larger than the browser viewport, focusing a row would not cause the browser to scroll it into view.
๐ป Code Sample
๐ Your Environment
| Software | Version(s) |
|---|---|
| react-spectrum | @react-aria/[email protected] |
| Browser | Chrome Version 97.0.4692.71 (Official Build) (x86_64) |
| Operating System | macOS Version 12.1 (21C52) |
๐งข Your Company/Team
Adobe/Accessibility Adobe/Admin_Console
๐ท Tracking Issue (optional)
Jira issue A11Y-5009 and TRON-8092