Middle
How to implement keyboard navigation (up/down arrows) in a virtualized list using @tanstack/virtual?
sobes.tech AI
Answer from AI
To implement keyboard navigation (up/down arrows) in a virtualized list using @tanstack/virtual, you need to manage the currently highlighted index and scroll the list to the desired item when this index changes.
Main steps:
- Store the index of the currently highlighted item in the state.
- Handle keyboard events (keydown) on the list container.
- When pressing the down arrow, increase the index; when pressing the up arrow, decrease it, with boundary checks.
- Use the
scrollToIndexmethod from the @tanstack/virtual API to scroll the list to the highlighted item.
Example in React:
import React, { useState, useRef, useEffect } from 'react';
import { useVirtual } from '@tanstack/react-virtual';
function VirtualList({ items }) {
const parentRef = useRef(null);
const [highlightedIndex, setHighlightedIndex] = useState(0);
const rowVirtualizer = useVirtual({
size: items.length,
parentRef,
estimateSize: () => 35,
overscan: 5,
});
useEffect(() => {
rowVirtualizer.scrollToIndex(highlightedIndex);
}, [highlightedIndex, rowVirtualizer]);
const onKeyDown = (e) => {
if (e.key === 'ArrowDown') {
e.preventDefault();
setHighlightedIndex(i => Math.min(i + 1, items.length - 1));
} else if (e.key === 'ArrowUp') {
e.preventDefault();
setHighlightedIndex(i => Math.max(i - 1, 0));
}
};
return (
<div
ref={parentRef}
tabIndex={0}
onKeyDown={onKeyDown}
style={{ height: `300px`, overflow: 'auto', outline: 'none' }}
>
<div
style={{
height: `${rowVirtualizer.totalSize}px`,
position: 'relative',
}}
>
{rowVirtualizer.virtualItems.map(virtualRow => {
const isSelected = virtualRow.index === highlightedIndex;
return (
<div
key={virtualRow.index}
ref={virtualRow.measureRef}
style={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: `${virtualRow.size}px`,
transform: `translateY(${virtualRow.start}px)`,
backgroundColor: isSelected ? '#bde4ff' : 'transparent',
padding: '8px',
boxSizing: 'border-box',
}}
>
{items[virtualRow.index]}
</div>
);
})}
</div>
</div>
);
}
In this example, pressing the arrow keys updates the highlighted index, and the list scrolls to it, providing convenient keyboard navigation.