zthomas / react-horizontal-scrolling-menu

Horizontal scrolling menu component for React.

Home Page:https://www.npmjs.com/package/react-horizontal-scrolling-menu

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

React horizontal scrolling menu

example

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

Demo

Basic example

Select item

Click and select multiple items

Scroll by 1 item

Full Demo

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 from example-nextjs folder.

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
onMouseDown (VisibilityContext) => (React.MouseEventHandler) => void
onMouseUp (VisibilityContext) => (React.MouseEventHandler) => void
onMouseMove (VisibilityContext) => (React.MouseEventHandler) => void

VisibilityContext

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 support

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

About

Horizontal scrolling menu component for React.

https://www.npmjs.com/package/react-horizontal-scrolling-menu

License:MIT License


Languages

Language:TypeScript 74.2%Language:JavaScript 22.5%Language:CSS 3.3%Language:Shell 0.1%