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

hpvm-menu

v1.0.3

Published

Hyper Parametrizable Vanilla JS Menu, the best plugin for app off-canvas menus for your webapp.

Readme

HPVM-MENU

Hyper Parametrizable Vanilla Menu

Design to address long list of items (~180) and almost no dependecies. Hpvm-Menu is a First Class solution for webapps off-canvas menus with sliding submenus support. It is very small (~16Kb) and customizable through a wide range of options.

Online Demo

Need extra help? Have a look at the examples folder. Fill an issue if necessary.


Features

  • [x] 100% VanillaJS
  • [x] Flexbox based
  • [x] Theme support
  • [x] Off-Canvas sidebar
  • [x] Custom sort support
  • [x] Forced order support
  • [x] Custom item renderer
  • [x] Auto managed favorites
  • [x] Native support for external icons
  • [x] Support for search in extra tags
  • [x] Support for fuzzy search ( dep on fuse.js )
  • [x] Support for global search across multiple sidebars
  • [x] Support for nested lists using dropdrown and divide
  • [x] No external dependencies ( except Fontawesome )
  • [x] Modules can be used independently ( Iconbar, Sidebar, Overlay, Search )

Demo


Quick start

Install

This package can be installed with:

  • npm: npm install --save hpvm-menu

Or download the latest release.

CDN

Including Hpvm Menu

Script and Css tag

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/[email protected]/css/all.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/all.css">

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/all.min.js"></script>

Usage

Be sure to call the Hpvm once your menu element is available in the DOM.

HTML menu structure with all components

<div class="icon-bar container">
	<div class="icon-bar-top">
		<!-- <a class="tooltip" href="#"><i class="fa fa-bell fa-beat" style="--fa-beat-scale: 2.5;"></i><span class="tooltiptext">Alertas</span></a>  -->
	</div>
	<div class="icon-bar-bottom">
		<!-- <a class="tooltip icon-bar-item danger" href="#"><i class="fa fa-sign-out"></i><span class="tooltiptext">Sair</span></a> -->
	</div>
</div>

<div id="overlay">
	<i class="fa-solid fa-sync fa-spin fa-5x is-loaded" style="--fa-animation-duration: 5s;"></i>
</div>

<div class='wrapper' />

<div class='sidebar'>
	<div class='sidebar-widelogo'>
		<img src="https://via.placeholder.com/220x55/e0e0e0/000000/?text=LOGO+HERE" alt="Logo" />
	</div>
	<div id='sidebarTitle' class='sidebar-title'>
		Title Here
	</div>
	<div class='search'>
		<input class='searchInput' placeholder='Search for...' type="text"
			onkeyup="HpvMenu.sidebar.filterFn(this, 'menuItems')" />
		<button class='btn btn-outline-success' type='button'><i class='fas fa-search'></i></button>
	</div>
	<!-- For global search across all sidebars, use: -->
	<!-- <input onkeyup="HpvMenu.sidebar.filterFnGlobal(this, 'menuItems')" /> -->
	<ul id='menuItems' class='nav'>
	</ul>
	<div id='sideBarStatusText'>
		<p>No Item Available</p>
	</div>
</div>

<div id='content' class="content">
	Your content goes here
</div>

Vanilla JS

document.addEventListener('DOMContentLoaded', function() {

  	// iconbar entry
	HpvMenu.iconbar.registerEntry({
		'parentCls': 'icon-bar-top',
		'innerHtml': '<i class="fa fa-house-chimney-user"></i>',
		'tooltiptext': 'Central do Usuário',
		'onClick': function (event) {
			// mixin connects components
			HpvMenu.mixin.handleIconBarClick(event, 'home');
		}
	});

	// sidebar entry
	HpvMenu.sidebar.registerEntry({
		'id': 'home',
		'title': 'My Home Menu',
		'overlay': true,
		'sortItens': true,
		'search': {
			'enabled': true,
			'mode': 'fuzzy',
			'fields': ['title'],
			'global': false  // Set to true to include in global search
		},
		'itens': [
			{ 'type': 'entry', 'title': 'Item 1' },
			{ 'type': 'entry', 'title': 'Item 2' }
		],
		'onItemClick': function (event, entry, item) {
			console.log('Item is clicked: ', item);
		}
	});

});

Themes

Hpvm currently has 2 themes, the default and Dark. To use Dark theme simply import theme css after hpvm css file:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/themes/dark-grey.css">

Methods

The Hpvm API offers a couple of methods to control components isolated or as a group ( mixin ).

HpvMenu.iconbar.registerEntry(entry)

Register a new iconbar entry.

HpvMenu.iconbar.registerEntry({
	'parentCls': 'icon-bar-bottom',
	'classes': ['danger'],
	'innerHtml': '<i class="fa fa-sign-out"></i>',
	'tooltiptext': 'Exit',
	'onClick': function (event) {
		console.log('exit clicked');
	}
});

HpvMenu.iconbar.setActive(el)

Set programmatically an entry(el) of iconbar as active.

let iconbar = document.getElementsByClassName('icon-bar')[0];
let firstAnchor = iconbar.getElementsByTagName('a')[0];
HpvMenu.iconbar.setActive(firstAnchor);

HpvMenu.iconbar.removeLastActive()

Deactivate any active entry on iconbar.

HpvMenu.iconbar.removeLastActive();

HpvMenu.sidebar.registerEntry(entry)

Register a new sidebar entry.

HpvMenu.sidebar.registerEntry({
	'id': 'dashboard',
	'title': 'Dashboard',
	'overlay': true,
	'sortItens': true,
	'search': true,
	'itens': [],
	'onItemClick': function (event, entry, item) {
		console.log("Item clicked: ", item);
	}
});

HpvMenu.sidebar.show(id)

Show sidebar with rendered content from an registered entry.

HpvMenu.sidebar.show('dashboard');

HpvMenu.sidebar.close()

Close sidebar if openned.

HpvMenu.sidebar.close();

HpvMenu.overlay.show( isIconBarVisible, isSidebarVisible )

Show overlay above user content, parameters help calculate the initial position.

HpvMenu.overlay.show(true, false);

HpvMenu.overlay.hide()

Hide overlay if active.

HpvMenu.overlay.hide();

HpvMenu.overlay.showLoading( isIconBarVisible, isSidebarVisible )

Show overlay above user content with an spinning icon. Parameters help calculate the initial position.

HpvMenu.overlay.showLoading(true, false);

HpvMenu.overlay.hideLoading()

Hide overlay and spinning if active.

HpvMenu.overlay.hide();

HpvMenu.mixin.closeSideBar()

Closes sidebar, hides overlay and remove iconbar active entries.

HpvMenu.mixin.closeSideBar();

HpvMenu.mixin.handleIconBarClick( event, id )

Set iconbar entry as active, opens sidebar and display the overlay. Can be used on while registering iconbar entry with 'onClick' event handler.

HpvMenu.iconbar.registerEntry({
	'parentCls': 'icon-bar-top',
	'innerHtml': '<i class="fa fa-star"></i>',
	'tooltiptext': 'Bookmarks',
	'onClick': function (event) {
		HpvMenu.mixin.handleIconBarClick(event, 'bookmarks');
	}
});

HpvMenu.mixin.setIconBarActive( el )

Wrapper around iconbar.setIconBarActive, closing the sidebar if users click on an open entry.

let iconbar = document.getElementsByClassName('icon-bar')[0];
let firstAnchor = iconbar.getElementsByTagName('a')[0];
HpvMenu.mixin.setIconBarActive( firstAnchor );

Global Search

HPVM-Menu now supports global search functionality that allows searching across multiple sidebars simultaneously.

Enabling Global Search

To enable global search for a sidebar, set global: true in the search configuration:

HpvMenu.sidebar.registerEntry({
	'id': 'my_sidebar',
	'title': 'My Sidebar',
	'search': {
		'enabled': true,
		'global': true,  // Enable global search
		'mode': 'fuzzy',
		'fields': ['title', 'tags']
	},
	'itens': [
		// ... your items
	]
});

Using Smart Search (Recommended)

Use the smart search function that automatically chooses between local and global search based on each sidebar's configuration:

<!-- Smart search (automatically chooses local or global based on sidebar config) -->
<input onkeyup="HpvMenu.sidebar.filterFnSmart(this, 'menuItems')" />

<!-- Smart fuzzy search -->
<input onkeyup="HpvMenu.sidebar.filterFnFuzzySmart(this, 'menuItems')" />

Using Global Search Directly

If you want to force global search for all sidebars:

<!-- Global search (searches across all sidebars) -->
<input onkeyup="HpvMenu.sidebar.filterFnGlobal(this, 'menuItems')" />

<!-- Global fuzzy search -->
<input onkeyup="HpvMenu.sidebar.filterFnFuzzyGlobal(this, 'menuItems')" />

Using Local Search Only

For local search within the current sidebar only:

<!-- Standard search (searches only current sidebar) -->
<input onkeyup="HpvMenu.sidebar.filterFn(this, 'menuItems')" />

<!-- Local fuzzy search -->
<input onkeyup="HpvMenu.sidebar.filterFnFuzzy(this, 'menuItems')" />

Smart Search Behavior

The smart search functions (filterFnSmart and filterFnFuzzySmart) automatically choose the appropriate search method based on each sidebar's configuration:

  • If search.global=true: Uses global search (searches across all sidebars with global search enabled)
  • If search.global=false or not set: Uses local search (searches only within the current sidebar)

This provides the best of both worlds:

  • Global-enabled sidebars participate in cross-sidebar search
  • Local-only sidebars maintain their independent search functionality

Global Search Features

  • Cross-sidebar search: Results include items from all sidebars with search.global=true
  • Grouped results: Results are organized by sidebar with clear labels
  • Smart navigation: Click any result to automatically switch to that sidebar
  • Path information: Shows hierarchical path for nested items
  • Highlight on selection: Selected items are highlighted when navigated to
  • No results message: Shows "Nenhum item encontrado." when no matches are found

Local Search Features

  • Current sidebar only: Searches only within the active sidebar
  • Fast and focused: Optimized for searching within a specific context
  • Preserves sidebar state: Doesn't interfere with other sidebars
  • No results message: Shows "Nenhum item encontrado." when no matches are found

Example

See the Global Search Example for a complete implementation.

TODO

  • [ ] Responsive layout ( Missing mobile yet )
  • [ ] Customize scrollbar
  • [ ] Expansive iconbar as dropdown item
  • [ ] Stick section label on scroll

Learn more ( In Progress )

  • [Tutorial]
  • [Options]
  • [Add-ons]
  • [API]

Licence

The Hpvm-Menu code is licensed under the Apache-2.0 licence.

Similar projects: