Nukem's Possible Manifestation

    react-horizontal-scrolling-menu
    TypeScript icon, indicating that this package has built-in type declarations

    2.7.0 • Public • Published

    React horizontal scrolling menu

    example

    npm Tests codebeat badge Codacy Badge Commitizen friendly npm bundle size (minified + gzip) Donate

    Proud corner

    performance-dashboard-on-aws | React status code

    Examples

    Demo

    Basic example

    Hidden scrollbar and arrows on bottom

    Select item

    Drag by mouse

    Click and select multiple items

    Scroll by 1 item

    Center item

    Dynamically add items when last is visible

    apiRef - controling component outside

    Add item and scroll to it

    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 = () =>
      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.

    Example

    You can clone repository and run demo project.

    git clone https://github.com/asmyshlyaev177/react-horizontal-scrolling-menu
    yarn install
    yarn run demo

    Helpers and api

    Children of main ScrollMenu component 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
    onWheel (VisibilityContext, event) => void
    onScroll (VisibilityContext, event) => void
    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

    VisibilityContext

    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
    visibleItemsWithoutSeparators ['item1', 'item2']
    initComplete boolean
    items ItemsMap class instance
    scrollContainer Ref
    visibleItems ['item1', 'item1-separator', 'item2']

    Transition/Animation

    Can use transitionDuration, transitionEase and transitionBehavior See [example]{https://codesandbox.io/s/custom-transition-animation-n2pyn}

    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 https://gist.github.com/gre/1650294#file-easing-js
        };
    }

    Other helpers

    slidingWindow

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

    slidingWindow(allItems, visibleItems)
    .prev()
    //.next()
    

    getItemsPos

    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

    apiRef

    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, Element.scrollIntoView for Safari and requestAnimationFrame or use polyfills.
    • Only modern browsers, no IE or smart toasters

    About

    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.

    Contributing

    Changelog

    Install

    npm i react-horizontal-scrolling-menu

    DownloadsWeekly Downloads

    28,817

    Version

    2.7.0

    License

    ISC

    Unpacked Size

    60.3 kB

    Total Files

    37

    Last publish

    Collaborators

    • asmyshlyaev177