React horizontal scrolling menu

This is horizontal scrolling menu component for React. Menu component has adaptive width, just set width for parent container. Items width will be determinated from css styles. Note: don't set margin for item wrapper, use padding instead. Can use margin for item element those you pass as props.

For navigation you can use arrows, mouse wheel or just drag items.

Component return items position, selected item and click event from callbacks.

Possible set default position and selected item on initialization.

Add star if you like project :)

Quick start

npm install --save react-horizontal-scrolling-menu

In project:

import React, { Component } from 'react';
import ScrollMenu from 'react-horizontal-scrolling-menu';
import './App.css';

// list of items
const list = [
  { name: 'item1' },
  { name: 'item2' },
  { name: 'item3' },
  { name: 'item4' },
  { name: 'item5' },
  { name: 'item6' },
  { name: 'item7' },
  { name: 'item8' },
  { name: 'item9' }
];

// One item component
// selected prop will be passed
const MenuItem = ({ text, selected }) => {
  return (
    <div
      className="menu-item"
    >
      {text}
    </div>
  );
};

// All items component
// Important! add unique key
export const Menu = (list) => list.map(el => {
  const { name } = el;

  return (
    <MenuItem
      text={name}
      key={name}
    />
  );
});


const Arrow = ({ text, className }) => {
  return (
    <div
      className={className}
    >{text}</div>
  );
};


const ArrowLeft = Arrow({ text: '<', className: 'arrow-prev' });
const ArrowRight = Arrow({ text: '>', className: 'arrow-next' });

class App extends Component {
  state = {
    selected: 0
  };
  
  onSelect = key => {
    this.setState({ selected: key });
  }

  
  render() {
    const { selected } = this.state;
    // Create menu from items
    const menu = Menu(list, selected);

    return (
      <div className="App">
        <ScrollMenu
          data={menu}
          arrowLeft={ArrowLeft}
          arrowRight={ArrowRight}
          selected={selected}
          onSelect={this.onSelect}
        />
      </div>
    );
  }
}

In App.css

.menu-item {
  padding: 0 40px;
  margin: 5px 10px;
  user-select: none;
  cursor: pointer;
  border: none;
}
.menu-item-wrapper.active {
  border: 1px blue solid;
}
.menu-item.active {
  border: 1px green solid;
}

.scroll-menu-arrow {
  padding: 20px;
  cursor: pointer;
}

Example

You can clone repository and run demo project from examples folder.

git clone https://github.com/asmyshlyaev177/react-horizontal-scrolling-menu
cd react-horizontal-scrolling-menu/examples
npm install
npm run start

Properties and callbacks

Props Type Description Required Default Value
data Array of react components Menu items, if empy render null (note, component must have unique key!) true []
wheel Boolean Scroll with mouse wheel false true
arrowLeft React component React component for left arrow false null
arrowRight React component React component for right arrow, don't pass it for disable arrow false null
transition Float number How long animation last, 0 for disable false 0.4
alignCenter Boolean Try to align items by center false true
selected String or Number Initial selected item false 0
translate Number Initial offset false 0
dragging Boolean Allow drag items by mouse(and touch) false true
clickWhenDrag Boolean After drag end select item under cursor( if any) false false
onSelect Function Callback when item selected, return item key false null
onUpdate Function Callback when menu position changed, return { translate: 0 } false null
menuClass String Class for component false 'horizontal-menu'
arrowClass String Class for arrow false 'scroll-menu-arrow'
wrapperClass String Class for wrapper in component false 'menu-wrapper'
innerWrapperClass String Class for inner wrapper false 'menu-wrapper--inner'
itemClass String Class for item wrapper false 'menu-item-wrapper'
itemClassActive String Class for active item wrapper false 'active'
menuStyle Object Styles for item wrapper false {display: 'flex', alignItems: 'center', userSelect: 'none'}
wrapperStyle Object Class for active item wrapper false {overflow: 'hidden', userSelect: 'none'}

Gotcha

For now component will use for menu items props passed first time, further props as data will be ignored.

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.

GitHub