npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@jsuites/menu

v4.0.0

Published

Lightweight responsive JavaScript navigation menu with collapsible folders and mobile support

Readme

JavaScript Navigation Menu - jSuites Menu Plugin

A lightweight, responsive JavaScript navigation menu component for building sidebar menus and documentation navigation. Features collapsible folders, automatic URL-based selection, smooth animations, and mobile-friendly design.

Key Features

  • Collapsible Folders: Expandable/collapsible sections with smooth animations
  • URL-Based Selection: Automatically highlights menu items based on current URL
  • Responsive Design: Transforms into a slide-out sidebar on mobile devices (<800px)
  • Smooth Animations: Slide-in/slide-out transitions for mobile navigation
  • Material Icons Support: Built-in support for Material Icons in folder headers
  • Scroll to Selected: Auto-scrolls to the currently selected menu item on load
  • Toggle Functionality: Show, hide, and toggle menu visibility programmatically
  • Event Callbacks: onload and onclick event handlers for custom logic
  • Lightweight: No dependencies, works standalone or with jSuites

Installation

NPM Installation

npm install @jsuites/menu

CDN Installation

<!-- jSuites Menu Plugin -->
<script src="https://cdn.jsdelivr.net/npm/@jsuites/menu/menu.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jsuites/menu/menu.min.css" />

Quick Start Example

Basic Navigation Menu

<!DOCTYPE html>
<html>
<head>
    <script src="https://cdn.jsdelivr.net/npm/@jsuites/menu/menu.min.js"></script>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jsuites/menu/menu.min.css" />
</head>
<body>
<div id="navigation">
    <nav>
        <h2 data-icon="home" class="folder">Getting Started</h2>
        <div>
            <ul>
                <li><a href="/docs/introduction">Introduction</a></li>
                <li><a href="/docs/installation">Installation</a></li>
                <li><a href="/docs/quick-start">Quick Start</a></li>
            </ul>
        </div>
    </nav>
    <nav>
        <h2 data-icon="code" class="folder">API Reference</h2>
        <div>
            <ul>
                <li><a href="/docs/methods">Methods</a></li>
                <li><a href="/docs/events">Events</a></li>
                <li><a href="/docs/options">Options</a></li>
            </ul>
        </div>
    </nav>
</div>

<script>
    const navigation = menu(document.getElementById('navigation'), {
        adjustOnLoad: true,
        onclick: function(instance, e) {
            console.log('Menu item clicked');
        }
    });
</script>
</body>
</html>

Using with LemonadeJS

import lemonade from 'lemonadejs';
import menu from '@jsuites/menu';

export default function Menu() {
    let self = this;

    self.data = self.data || [];

    self.createMenu = function(o) {
        self.instance = menu(o, {
            adjustOnLoad: true,
        });
    }

    self.toggle = function() {
        if (self.el.offsetWidth) {
            self.instance.hide();
        } else {
            self.instance.show();
        }
    }

    self.hide = function() {
        self.instance.hide();
    }

    self.show = function() {
        self.instance.show();
    }

    self.onload = function() {
        if (document.body.offsetWidth < 800) {
            self.el.style.display = 'none';
        }
    }

    // Template
    return render => render`<div :ready="self.createMenu" path="{{self.path}}" class="lm-p20">
        <img src="{{self.logo}}" class="jmenu-logo" />
        <div :loop="self.data">
            <nav data-id="{{self.id}}">
                <h2 data-icon="{{self.icon}}" class="folder">{{self.title}}</h2>
                <div>
                    <ul :loop="self.items">
                        <li><a href="{{self.href}}">{{self.title}}</a></li>
                    </ul>
                </div>
            </nav>
        </div>
    </div>`;
}

React Integration

import React, { useRef, useEffect } from 'react';
import menu from '@jsuites/menu';
import '@jsuites/menu/menu.css';

function NavigationMenu({ items }) {
    const menuRef = useRef(null);
    const containerRef = useRef(null);

    useEffect(() => {
        if (containerRef.current) {
            menuRef.current = menu(containerRef.current, {
                adjustOnLoad: true,
                onclick: (instance, e) => {
                    console.log('Navigation clicked');
                }
            });
        }
    }, []);

    const handleToggle = () => {
        menuRef.current?.toggle();
    };

    return (
        <>
            <button className="jmenu-icon" onClick={handleToggle}>Menu</button>
            <div ref={containerRef}>
                {items.map((section, index) => (
                    <nav key={index}>
                        <h2 data-icon={section.icon} className="folder">{section.title}</h2>
                        <div>
                            <ul>
                                {section.links.map((link, i) => (
                                    <li key={i}><a href={link.href}>{link.title}</a></li>
                                ))}
                            </ul>
                        </div>
                    </nav>
                ))}
            </div>
        </>
    );
}

export default NavigationMenu;

Vue Integration

<template>
    <div>
        <button class="jmenu-icon" @click="toggle">Menu</button>
        <div ref="menuContainer">
            <nav v-for="(section, index) in sections" :key="index">
                <h2 :data-icon="section.icon" class="folder">{{ section.title }}</h2>
                <div>
                    <ul>
                        <li v-for="(link, i) in section.links" :key="i">
                            <a :href="link.href">{{ link.title }}</a>
                        </li>
                    </ul>
                </div>
            </nav>
        </div>
    </div>
</template>

<script>
import menu from '@jsuites/menu';
import '@jsuites/menu/menu.css';

export default {
    props: ['sections'],
    data() {
        return {
            menuInstance: null
        };
    },
    mounted() {
        this.menuInstance = menu(this.$refs.menuContainer, {
            adjustOnLoad: true
        });
    },
    methods: {
        toggle() {
            this.menuInstance?.toggle();
        }
    }
};
</script>

Usage Examples

Documentation Sidebar

const docsSidebar = menu(document.getElementById('sidebar'), {
    adjustOnLoad: true,
    onclick: function(instance, e) {
        // Track navigation analytics
        analytics.track('docs_navigation', {
            path: e.target.href
        });
    }
});

// Update selection when using client-side routing
window.addEventListener('popstate', () => {
    docsSidebar.update(true); // true = scroll to selected item
});

Mobile Navigation with Toggle Button

<button class="jmenu-icon" onclick="navigation.toggle()">
    <span class="material-icons">menu</span>
</button>

<div id="mobile-nav">
    <img src="/logo.png" class="jmenu-logo" />
    <nav>
        <h2 class="folder">Products</h2>
        <div>
            <ul>
                <li><a href="/products/software">Software</a></li>
                <li><a href="/products/services">Services</a></li>
            </ul>
        </div>
    </nav>
</div>

<script>
    const navigation = menu(document.getElementById('mobile-nav'));
</script>

Nested Menu Structure

<div id="nested-menu">
    <nav>
        <h2 data-icon="folder" class="folder">Components</h2>
        <div>
            <h3>Form Elements</h3>
            <ul>
                <li><a href="/components/input">Input</a></li>
                <li><a href="/components/select">Select</a></li>
                <li><a href="/components/checkbox">Checkbox</a></li>
            </ul>
            <h3>Layout</h3>
            <ul>
                <li><a href="/components/grid">Grid</a></li>
                <li><a href="/components/container">Container</a></li>
            </ul>
        </div>
    </nav>
</div>

<script>
    menu(document.getElementById('nested-menu'));
</script>

API Reference

Options

| Property | Type | Default | Description | |----------------|----------|---------|--------------------------------------------------------| | adjustOnLoad | boolean | true | Auto-scroll to selected item when menu loads | | onclick | function | null | Callback fired when a menu link is clicked | | onload | function | null | Callback fired when the menu finishes initializing |

Methods

show()

Display the menu (with slide animation on mobile).

menuInstance.show();

hide()

Hide the menu (with slide animation on mobile).

menuInstance.hide();

toggle()

Toggle menu visibility.

menuInstance.toggle();

update(adjustScroll)

Update the selected state based on the current URL path.

// Update selection without scrolling
menuInstance.update();

// Update selection and scroll to selected item
menuInstance.update(true);

Parameters:

  • adjustScroll (boolean): If true, scrolls the menu to show the selected item

select(element, event)

Programmatically select a menu item.

const link = document.querySelector('.jmenu a[href="/docs/intro"]');
menuInstance.select(link, event);

Parameters:

  • element (HTMLElement): The anchor element to select
  • event (Event): The original event object

HTML Structure

The menu expects this HTML structure:

<div id="menu">
    <!-- Optional logo for mobile view -->
    <img src="/logo.png" class="jmenu-logo" />

    <nav>
        <!-- Collapsible folder header -->
        <h2 data-icon="icon_name" class="folder">Section Title</h2>
        <div>
            <!-- Optional subsection heading -->
            <h3>Subsection</h3>
            <ul>
                <li><a href="/path">Link Text</a></li>
            </ul>
        </div>
    </nav>
</div>

CSS Classes

| Class | Description | |----------------|--------------------------------------------------| | .jmenu | Main menu container (added automatically) | | .jmenu-logo | Logo image, visible only on mobile | | .jmenu-icon | Menu toggle button (hamburger icon) | | .folder | Collapsible section header | | .selected | Applied to active folder and list item |

CSS Custom Properties

| Property | Description | |-----------------------|---------------------------------------| | --main-color | Accent color for selected item border | | --main-color-light | Background color for selected item |

Responsive Behavior

The menu automatically adapts for different screen sizes:

  • Desktop (>800px): Static sidebar, folders expand/collapse in place
  • Mobile (<800px):
    • Full-height slide-out panel with fixed positioning
    • Logo becomes visible
    • Close button appears in top-right corner
    • Clicking a link automatically closes the menu

Related Projects

  • LemonadeJS - Reactive micro JavaScript library
  • Jspreadsheet - JavaScript data grid and spreadsheet component
  • jSuites - JavaScript plugins and web components collection
  • CalendarJS - JavaScript calendar, schedule, and date picker components

License

MIT License

Support & Community

Contributing

Contributions are welcome! Please feel free to submit pull requests or open issues.