Search code examples
cssreactjstwitter-bootstrapreactstrapmegamenu

Issue in displaying submenu on hover


I am making a reactjs application with reactstrap where I have made a dropdown which consists of sub menus inside it.

I am trying to achieve the result of making the submenus display on hover over the dropdown and if there is n numbers of dropdown then the submenus related with the hover item needs to be displayed.

Code tried:

<Dropdown
  className="d-inline-block"
  onMouseOver={this.onMouseEnter}
  onMouseLeave={this.onMouseLeave}
  isOpen={this.state.dropdownOpen}
  toggle={this.toggle}
>
  <DropdownToggle caret>Dropdown1</DropdownToggle>
  <DropdownMenu>
    <DropdownItem header>Submenu 1</DropdownItem>
    <DropdownItem>Submenu 1.1</DropdownItem>
  </DropdownMenu>
  &nbsp;&nbsp;&nbsp;
  <DropdownToggle caret>Dropdown2</DropdownToggle>
  <DropdownMenu>
    <DropdownItem header>Submenu 2</DropdownItem>
    <DropdownItem>Submenu 2.1</DropdownItem>
    <DropdownItem>Submenu 2.2</DropdownItem>
  </DropdownMenu>
  &nbsp;&nbsp;&nbsp;
  <br />
  <br />
  <DropdownToggle caret>Dropdown3</DropdownToggle>
  <DropdownMenu>
    <DropdownItem header>Submenu 3</DropdownItem>
    <DropdownItem>Submenu 3.1</DropdownItem>
    <DropdownItem>Submenu 3.2</DropdownItem>
    <DropdownItem>Submenu 3.3</DropdownItem>
  </DropdownMenu>
</Dropdown>

Click here for working demo

Expected Result: http://supply.com/

In the above given link you could able to see the horizontal menu which on hover will display their respective submenu and I am in the need to achieve the same behaviour.


Solution

    1. You need to separate those menus and put in a single <Dropdown> component.
    2. And you need to set an event handler for each of them.
    3. You may use Array.prototype.map to simplify setting handlers.
    import React from "react";
    import {
      Dropdown,
      DropdownToggle,
      DropdownMenu,
      DropdownItem
    } from "reactstrap";
    
    export default class Example extends React.Component {
      constructor(props) {
        super(props);
    
        this.onMouseEnter = this.onMouseEnter.bind(this);
        this.onMouseLeave = this.onMouseLeave.bind(this);
        this.state = {
          dropdownOpen: -1
        };
        this.toggle = this.toggle.bind(this);
    
        this.menus = [
          {
            title: "Bathroom",
            submenus: [{ title: "Toilets" }, { title: "Toilet seats" }]
          },
          {
            title: "Kitchen",
            submenus: [{ title: "Farmhouse Sinks" }, { title: "Cast Iron Sinks" }]
          }
        ];
      }
    
      onMouseEnter(current) {
        this.setState({ dropdownOpen: current });
      }
    
      onMouseLeave() {
        this.setState({ dropdownOpen: -1 });
      }
    
      toggle() {}
    
      render() {
        return (
          <div>
            {this.menus.map((menu, i) => (
              <Dropdown
                className="d-inline-block"
                onMouseOver={e => this.onMouseEnter(i)}
                onMouseLeave={this.onMouseLeave}
                isOpen={this.state.dropdownOpen === i}
                toggle={this.toggle}
              >
                <DropdownToggle caret>{menu.title}</DropdownToggle>
                <DropdownMenu>
                  {menu.submenus.map((submenu, i) => (
                    <DropdownItem header>{submenu.title}</DropdownItem>
                  ))}
                </DropdownMenu>
              </Dropdown>
            ))}
          </div>
        );
      }
    }
    

    stackblitz: https://stackblitz.com/edit/reactstrap-v6-qsffjj