Currently I can scroll when click and drag on the margin space between the AriaTabs. Once I click on the AriaTab, it’ll register as a click. OnMouseDown and onClick won’t be detected when I click on AriaTab. Wrapping AriaTab inside div breaks the entire component.
Are there any way to add scroll functionality on the tabs without scrollbar?
import { Tabs, TabList, Tab as AriaTab, TabPanel } from 'react-aria-components';
const Tab: React.FC<TabProps> = ({ tabs }) => {
const tabsRef = useRef<HTMLDivElement>(null);
const [ isMouseDown, setIsMouseDown ] = useState(false);
const [ startX, setStartX ] = useState(0);
const [ scrollLeft, setScrollLeft ] = useState(0);
const handleMouseDown = (e: React.MouseEvent<HTMLDivElement>) => {
console.log('handleMouseDown registered');
if (tabsRef.current) {
setIsMouseDown(true);
setStartX(e.pageX - tabsRef.current.offsetLeft);
setScrollLeft(tabsRef.current.scrollLeft);
}
};
const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>)=> {
if(!isMouseDown) return;
e.preventDefault();
if (tabsRef.current) {
const x = e.pageX - tabsRef.current.offsetLeft;
const walk = (x-startX)*2;
tabsRef.current.scrollLeft = scrollLeft-walk;
}
}
const handleMouseMoveCapture = ()=> {
console.log('handleMouseMoveCapture');
}
const handleMouseUp = ()=> {
setIsMouseDown(false);
}
const handleMouseLeave = ()=> {
setIsMouseDown(false);
}
const handleTabClick = (e: React.MouseEvent<HTMLDivElement>) => {
const tabElement = e.target as HTMLElement;
console.log('handleTabClick')
if (tabElement.closest(`.${styles['react-aria-Tab']}`)) {
console.log(`Tab ${tabElement.innerText} clicked`);
}
};
return (
<Tabs className={styles['react-aria-Tabs']}>
<div className={styles['scrolling-container']}
ref={tabsRef}
onMouseDown={handleMouseDown}
onMouseLeave={handleMouseLeave}
onMouseUp={handleMouseUp}
onMouseMove={handleMouseMove}
onMouseMoveCapture={handleMouseMoveCapture}
onClick={handleTabClick}
>
<TabList className={styles['react-aria-TabList']}>
{tabs.map(tab => (
<AriaTab key={tab.id} id={tab.id} className={styles['react-aria-Tab']}>
{tab.icon && <span className={styles['react-aria-TabIcon']}>{tab.icon}</span>}
{tab.label}
</AriaTab>
))}
</TabList>
</div>
{tabs.map(tab => (
<TabPanel key={tab.id} id={tab.id} className={styles['react-aria-TabPanel']}>
{tab.content}
</TabPanel>
))}
</Tabs>
);
};
2
Answers
Add scroll to tabs:
Scroll work when drag mouse. No scrollbar need.
To achieve it, you need to carefully handle mouse events while ensuring they don’t interfere with the default click events on the AriaTab components.
The key here is to differentiate between a drag event for scrolling and a click event on a tab. Below is the modified code implementing these suggestions.
Make sure your CSS includes styles for the scrolling container, tabs, and other relevant classes
How it works:
Mouse Down
: When the mouse is pressed down, we store the initial position and scroll offset.Mouse Move
: If the mouse is moved while pressed down, we calculate the new scroll position and set isDragging to true to indicate that a drag operation is in progress.Mouse Up and Leave
: When the mouse button is released or leaves the container, we reset the dragging state.Tab Click
: We check if a drag was in progress (isDragging). If so, we prevent the click action, otherwise, the click event on the tab is registered.