Click and select multiple items
Previous version V1
This is a horizontal scrolling menu component for React. Menu component has adaptive width, just set width for parent container. Items width will be determined from CSS styles.
For navigation, you can use scrollbar, native touch scroll, mouse wheel or drag by mouse.
Component provide context with visible items and helpers.
Possible set default position on initialization.
⭐ if you like the project :)
yarn add react-horizontal-scrolling-menu
In project:
import React from "react";
import { ScrollMenu, VisibilityContext } from "react-horizontal-scrolling-menu";
const getItems = () =>
Array(20)
.fill(0)
.map((_, ind) => ({ id: `element-${ind}` }));
function App() {
const [items, setItems] = React.useState(getItems);
const [selected, setSelected] = React.useState([]);
const [position, setPosition] = React.useState(0);
const isItemSelected = (id) => !!selected.find((el) => el === id);
const handleClick = (id) => ({ getItemById, scrollToItem }) => {
const itemSelected = isItemSelected(id)
setSelected((currentSelected) =>
itemSelected
? currentSelected.filter((el) => el !== id)
: currentSelected.concat(id)
);
}
return (
<ScrollMenu
LeftArrow={LeftArrow}
RightArrow={RightArrow}
>
{items.map(({ id }) => (
<Card
itemId={id} // NOTE: itemId is required for track items
title={id}
key={id}
onClick={handleClick(id)}
selected={isItemSelected(id)}
/>)
)}
</ScrollMenu>
);
}
function LeftArrow() {
const { isFirstItemVisible, scrollPrev } = React.useContext(VisibilityContext)
return (
<Arrow disabled={isFirstItemVisible} onClick={() => scrollPrev()}>
Left
</Arrow>
);
}
function RightArrow() {
const { isLastItemVisible, scrollNext } = React.useContext(VisibilityContext)
return (
<Arrow disabled={isLastItemVisible} onClick={() => scrollNext()}>
Right
</Arrow>
);
}
function Card({
onClick,
selected,
title,
itemId
}) {
const visibility = React.useContext(VisibilityContext)
return (
<div
onClick={() => onClick(visibility)}
style={{
width: "160px",
}}
tabIndex={0}
>
<div className="card">
<div>{title}</div>
<div>visible: {JSON.stringify(!!visibility.isItemVisible(itemId))}</div>
<div>selected: {JSON.stringify(!!selected)}</div>
</div>
<div
style={{
height: "200px",
}}
/>
</div>
);
}
export default App;
Check out Example in example-nextjs
folder for info how to implement more features like mouse drag or disable body scroll.
You can clone repository and run demo project from example-nextjs folder.
git clone https://github.com/asmyshlyaev177/react-horizontal-scrolling-menu
yarn install
yarn run demo
Children of main ScrollMenu component can use VisibilityContext to access state and callbacks.
Function callbacks also pass context, eg onWheel
, onScroll
etc.
Prop | Signature |
---|---|
LeftArrow | React component for left arrow |
RightArrow | React component for right arrow |
onWheel | (VisibilityContext, event) => void |
onScroll | (VisibilityContext, event) => void |
onInit | (VisibilityContext) => void |
onMouseDown | (VisibilityContext) => (React.MouseEventHandler) => void |
onMouseUp | (VisibilityContext) => (React.MouseEventHandler) => void |
onMouseMove | (VisibilityContext) => (React.MouseEventHandler) => void |
Prop | Signature |
---|---|
getItemById | itemId => IOItem | undefined |
getItemByIndex | index => IOItem | undefined |
getNextItem | () => IOItem | undefined) |
getPrevItem | () => IOItem | undefined |
initComplete | boolean |
isFirstItemVisible | boolean |
isItemVisible | itemId => boolean |
isLastItem | boolean |
isLastItemVisible | boolean |
scrollNext | (behavior, inline, block) => void |
scrollPrev | (behavior, inline, block) => void |
scrollToItem | (item, behavior, inline, block) => void |
visibleItemsWithoutSeparators | ['item1', 'item2'] |
initComplete | boolean |
items | ItemsMap class instance |
scrollContainer | Ref |
visibleItems | ['item1', 'item1-separator', 'item2'] |
- Browser must support IntersectionObserver API, Element.scrollIntoView and requestAnimationFrame or use polyfills.
- Only modern browsers, no IE or smart toasters
My first npm project. Sorry for my english.
Any contribution and correction appreciated. Just fork repo, commit and make PR, don't forget about tests.