Nonprofit Pizza Maker

    TypeScript icon, indicating that this package has built-in type declarations

    3.2.3 • Public • Published

    React horizontal scrolling menu

    Stand With Ukraine


    npm Tests Codacy Badge Codacy Badge Commitizen friendly npm bundle size (minified + gzip) Donate with Bitcoin

    Proud corner

    performance-dashboard-on-aws | React status code



    Basic example

    Hidden scrollbar and arrows on bottom

    Select item

    Drag by mouse

    Click and select multiple items

    Scroll by 1 item

    Center items

    Dynamically add items when last is visible

    apiRef - controling component outside

    Add item and scroll to it


    Loop scroll

    Custom transition/animation

    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 :)

    Quick start

    yarn add react-horizontal-scrolling-menu

    In project:

    import React from 'react';
    import { ScrollMenu, VisibilityContext } from 'react-horizontal-scrolling-menu';
    const getItems = () =>
        .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) =>
              ? currentSelected.filter((el) => el !== id)
              : currentSelected.concat(id)
      return (
        <ScrollMenu LeftArrow={LeftArrow} RightArrow={RightArrow}>
          {{ id }) => (
              itemId={id} // NOTE: itemId is required for track items
    function LeftArrow() {
      const { isFirstItemVisible, scrollPrev } =
      return (
        <Arrow disabled={isFirstItemVisible} onClick={() => scrollPrev()}>
    function RightArrow() {
      const { isLastItemVisible, scrollNext } = React.useContext(VisibilityContext);
      return (
        <Arrow disabled={isLastItemVisible} onClick={() => scrollNext()}>
    function Card({ onClick, selected, title, itemId }) {
      const visibility = React.useContext(VisibilityContext);
      return (
          onClick={() => onClick(visibility)}
            width: '160px',
          <div className="card">
            <div>visible: {JSON.stringify(!!visibility.isItemVisible(itemId))}</div>
            <div>selected: {JSON.stringify(!!selected)}</div>
              height: '200px',
    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.

    git clone
    yarn install
    yarn run demo

    Helpers and api

    Children of main ScrollMenu component(arrows, fotter, items) can use VisibilityContext to access state and callbacks. Function callbacks also pass context, eg onWheel, onScroll etc.

    Properties and callbacks

    Prop Signature
    LeftArrow React component for left arrow
    RightArrow React component for right arrow
    Header React component Header
    Footer React component Footer
    onWheel (VisibilityContext, event) => void
    onScroll (VisibilityContext, event) => void, will fire before scroll
    onInit (VisibilityContext) => void
    apiRef React.RefObject
    onUpdate (VisibilityContext) => void
    onMouseDown (VisibilityContext) => (React.MouseEventHandler) => void
    onMouseUp (VisibilityContext) => (React.MouseEventHandler) => void
    onMouseMove (VisibilityContext) => (React.MouseEventHandler) => void
    itemClassName ClassName of Item
    separatorClassName ClassName of Item's separator
    scrollContainerClassName ClassName of scrollContainer
    transitionDuration Duration of transitions in ms, default 500
    transitionBehavior 'smooth' |'auto' | customFunction
    transitionEase Ease function, eg t => t*(2-t)
    wrapperClassName ClassName of the outer-most div
    RTL Enable Right to left direction
    noPolyfill Don't use polyfill for scroll, no transitions


    Prop Signature
    getItemById itemId => IOItem | undefined
    getItemElementById itemId => DOM Element | null
    getItemByIndex index => IOItem | undefined
    getItemElementByIndex index => DOM Element | null
    getNextItem () => IOItem | undefined)
    getPrevItem () => IOItem | undefined
    initComplete boolean
    isFirstItemVisible boolean
    isItemVisible itemId => boolean
    isLastItem boolean
    isLastItemVisible boolean
    scrollNext (behavior, inline, block, ScrollOptions) => void
    scrollPrev (behavior, inline, block, ScrollOptions) => void
    scrollToItem (item, behavior, inline, block, ScrollOptions) => void
    initComplete boolean
    items ItemsMap class instance
    scrollContainer Ref
    visibleElements ['item1', 'item2']
    visibleElementsWithSeparators ['item1', 'item1-separator', 'item2']
    visibleItemsWithoutSeparators (deprecated, use visibleElements) ['item1', 'item2']
    visibleItems (deprecated, use visibleElementsWithSeparators) ['item1', 'item1-separator', 'item2']


    NOTE: won't work with RTL prop

    Can use transitionDuration, transitionEase and transitionBehavior See example

    ScrollOptions for scrollToItem, scrollPrev, scrollNext

    Will override transition* options passed to ScrollMenu

      // target,
      behavior, // 'smooth', 'auto' or custom function
        // inline,
        // block,
          duration: number, // number in milliseconds
          ease: (t) => t, // ease function, more

    Other helpers


    Can get previous or next visible group of items with slidingWindow(allItems: string[], visibleItems: string[]) helper, e.g

    slidingWindow(allItems, visibleItems)


    Can get first, center and last items, e.g.

    const prevGroup = slidingWindow(allItems, visibleItems).prev()
    const { first, center: centerItem, last } = getItemsPos(prevGroup)
    // and scroll to center item of previous group of items
    scrollToItem(getItemById(centerItem, 'smooth', 'center'))

    Check out examples


    Can pass Ref object to Menu, current value will assigned as VisibilityContext. But visibleItems and some other values can be staled, so better use it only for firing functions like scrollToItem.

    For scrolling use apiRef.scrollToItem(apiRef.getItemElementById) instead of apiRef.scrollToItem(apiRef.getItemById).

    Can get item outside of context via apiRef.getItemElementById(id) or directly via document.querySelector(`[data-key='${itemId}']`). See apiRef example and Add item and scroll to it

    Browser support

    • Browser must support IntersectionObserver API 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.




    npm i react-horizontal-scrolling-menu

    DownloadsWeekly Downloads






    Unpacked Size

    79 kB

    Total Files


    Last publish


    • asmyshlyaev177