Giter VIP home page Giter VIP logo

cdes / react-headless-nested-menu Goto Github PK

View Code? Open in Web Editor NEW
9.0 2.0 3.0 387 KB

A useful headless component (hook) that gives you all the functions you need to create a multi-level menu using your own components!

Home Page: https://cdes.github.io/react-headless-nested-menu/

License: MIT License

TypeScript 100.00%
typescript hooks menu nested-menus multi-level-menu headless-components headless-ui

react-headless-nested-menu's Introduction

React Headless Nested Menu Logo

React Headless Nested Menu

A useful headless component (hook) that gives you all the functions you need to create a multi-level menu using your own components!

Features

  • Only functionality, no need to fight with CSS classes and overrides to customize your menu.
  • Created in TypeScript, so you get types out of the box.
  • Fully configurable behavior (open on click or hover).

React Headless Nested Menu Logo

Installation

yarn add react-headless-nested-menu

Usage

You can import the generated bundle to use the whole library generated by this starter:

import React from "react";
import { useNestedMenu } from "react-headless-nested-menu";

function App() {
  const {
    getToggleButtonProps,
    getMenuProps,
    getItemProps,
    getOpenTriggerProps,
    getCloseTriggerProps,
    getMenuOffsetStyles,
    isOpen,
    isSubMenuOpen,
    toggleMenu
  } = useNestedMenu({
    items
  });

  const [item, setItem] = useState<MenuItem>();

  // your custom function to render items
  const renderItem = (item: MenuItem) => (
    <div
      {...getItemProps(item)}
      className="relative my-1 first:mt-0 last:mb-0"
      {...getOpenTriggerProps("onPointerEnter", item)}
      onClick={(event) => {
        event.stopPropagation();
        setItem(item);
        toggleMenu();
      }}
    >
      <div
        className={classnames(
          "flex flex-row justify-between items-center rounded-lg flex-1 h-8 flex items-center px-2",
          {
            "text-gray-600 hover:text-gray-800 hover:bg-gray-200": !isSubMenuOpen(
              item
            ),
            "text-gray-800 bg-gray-200": isSubMenuOpen(item)
          }
        )}
      >
        {item.label}
        {item.subMenu && <Chevron />}
      </div>

      {/* Only show submenu when there's a submenu & it's open */}
      {item.subMenu && isSubMenuOpen(item) && renderMenu(item.subMenu, item)}
    </div>
  );

  // your custom function to render menus (root menu & sub-menus)
  const renderMenu = (items: Items, parentItem?: MenuItem) => (
    <div
      {...getMenuProps(parentItem)}
      style={{
        position: "absolute",
        ...getMenuOffsetStyles(parentItem)
      }}
      className={classnames(
        "bg-white p-2 shadow-lg rounded-lg select-none border border-gray-100 relative z-10",
        {
          "ms-2": typeof parentItem === "undefined", //for root menu
          "-mt-3": typeof parentItem !== "undefined" //for submenus only
        }
      )}
      {...getCloseTriggerProps("onPointerLeave", parentItem)}
    >
      <div>{items.map((item) => renderItem(item))}</div>

      {/* add hit area */}
      {parentItem && (
        <div
          style={{
            position: "absolute",
            top: -8,
            bottom: -8,
            left: -8,
            right: -8,
            zIndex: -1
          }}
        ></div>
      )}
    </div>
  );

  return (
    <div className="w-64 p-4 rounded-lg flex flex-col ms-4 mt-4">
      <button
        className="text-gray-600 border-2 border-gray-600 rounded-lg h-10 focus:outline-none"
        {...getToggleButtonProps()}
      >
        {item ? item.label : "Open Menu"}
      </button>
      {isOpen && renderMenu(items)}
    </div>
  );
}

const rootElement = document.getElementById("root");
React.render(<App />, rootElement);

To do

  • Improve documentation.
  • Add more example.
  • Add tests.
  • Use popper for positioning menus.

Examples

Credits

react-headless-nested-menu's People

Contributors

cdes avatar samio avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

react-headless-nested-menu's Issues

React@>18

this is a pretty awesome hook but when I use it, I just get Invalid hook call, most likely due to the Hooks API changing between react 16 and 18!
any chance of updating this to work with the latest version of React? pretty please ☺️

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.