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

meno-interactions

v0.1.0

Published

Attribute-driven JavaScript interactions for Meno and static no-code web projects.

Readme

Meno Interactions

Attribute-driven JavaScript interactions for Meno projects and static no-code sites.

Meno already supports component JavaScript with vanilla DOM code scoped to the component root, and it supports interactive styles through state classes such as .is-open or .is-scrolled. This package gives no-code builders a reusable script they can add once, then control behavior with custom attributes in the Meno Attributes panel.

Install

npm install meno-interactions

Or use the browser files from dist/ in a Meno project:

{
  "meta": {
    "libraries": {
      "js": [{ "url": "/libraries/meno-interactions.umd.js", "mode": "defer" }],
      "css": [{ "url": "/libraries/meno-interactions.css" }]
    }
  }
}

CDN Setup

After this package is published to npm, you can load it from a CDN with one CSS file and one deferred script.

Option 1: jsDelivr

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/meno-interactions/dist/meno-interactions.css">
<script defer src="https://cdn.jsdelivr.net/npm/meno-interactions/dist/meno-interactions.umd.js"></script>

Option 2: unpkg

<link rel="stylesheet" href="https://unpkg.com/meno-interactions/dist/meno-interactions.css">
<script defer src="https://unpkg.com/meno-interactions/dist/meno-interactions.umd.js"></script>

Option 3: Version-pin the CDN

Pinning a version prevents future package updates from changing an already-launched site.

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/meno-interactions.css">
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/meno-interactions.umd.js"></script>

Add CDN Files in Meno

In Meno, add the CDN URLs as page or project libraries. If editing JSON directly, put them in meta.libraries:

{
  "meta": {
    "libraries": {
      "css": [
        { "url": "https://cdn.jsdelivr.net/npm/[email protected]/dist/meno-interactions.css" }
      ],
      "js": [
        { "url": "https://cdn.jsdelivr.net/npm/[email protected]/dist/meno-interactions.umd.js", "mode": "defer" }
      ]
    }
  }
}

The script auto-initializes on page load. You do not need to write JavaScript for normal use.

Self-hosted CDN-style Setup

If you do not want third-party CDN URLs, copy these files into your Meno project's /libraries/ folder:

  • dist/meno-interactions.umd.js
  • dist/meno-interactions.css

Then load them like this:

{
  "meta": {
    "libraries": {
      "css": [{ "url": "/libraries/meno-interactions.css" }],
      "js": [{ "url": "/libraries/meno-interactions.umd.js", "mode": "defer" }]
    }
  }
}

Quick Use

Add attributes in Meno's Attributes panel. For example, an accordion only needs a wrapper and trigger attributes:

<div data-meno-accordion data-meno-single="true">
  <button data-meno-accordion-trigger>Question</button>
  <div>Answer</div>
</div>

In Meno JSON, the same idea is represented through attributes:

{
  "type": "node",
  "tag": "div",
  "attributes": { "data-meno-accordion": "", "data-meno-single": "true" },
  "children": [
    {
      "type": "node",
      "tag": "button",
      "attributes": { "data-meno-accordion-trigger": "" },
      "children": "Question"
    },
    { "type": "node", "tag": "div", "children": "Answer" }
  ]
}

Attribute Reference and Examples

Disclosure / Simple Toggle

Use this for one button that opens or closes one nearby panel.

<button data-meno-toggle data-meno-target="#details">Show details</button>
<div id="details" hidden>
  Extra content goes here.
</div>

Attributes:

  • data-meno-toggle: marks the clickable trigger.
  • data-meno-target="#details": optional selector for the panel. If omitted, the next sibling is used.

State classes and attributes:

  • The panel receives .is-open when open.
  • The trigger receives aria-expanded="true" or aria-expanded="false".
  • The panel hidden attribute is toggled.

Accordion

Use this for FAQ rows or any stacked expandable content.

<div data-meno-accordion data-meno-single="true">
  <button data-meno-accordion-trigger>What is included?</button>
  <div hidden>Everything needed for the starter setup.</div>

  <button data-meno-accordion-trigger>Can I open many rows?</button>
  <div hidden>Set data-meno-single="false" on the wrapper.</div>
</div>

Attributes:

  • data-meno-accordion: marks the accordion wrapper.
  • data-meno-accordion-trigger: marks each clickable row header.
  • data-meno-single="true": only one panel can be open at a time.
  • data-meno-single="false": multiple panels can stay open.

Panel rule:

  • Each trigger controls its next sibling unless the trigger has aria-controls="panel-id".

Tabs

Use this for switching between multiple panels.

<div data-meno-tabs data-meno-initial-tab="overview">
  <div role="tablist">
    <button data-meno-tab="overview">Overview</button>
    <button data-meno-tab="specs">Specs</button>
    <button data-meno-tab="faq">FAQ</button>
  </div>

  <section data-meno-tab-panel="overview">Overview content.</section>
  <section data-meno-tab-panel="specs">Specs content.</section>
  <section data-meno-tab-panel="faq">FAQ content.</section>
</div>

Attributes:

  • data-meno-tabs: marks the tab set wrapper.
  • data-meno-tab="id": marks a tab button.
  • data-meno-tab-panel="id": marks the matching panel.
  • data-meno-initial-tab="id": optional initial tab. If omitted, the first tab is selected.

State:

  • Active tab and panel receive .is-active.
  • Inactive panels receive hidden.
  • Buttons receive aria-selected.

Dropdown

Use this for nav menus or compact option panels.

<nav>
  <button data-meno-dropdown="services">Services</button>
  <div data-meno-dropdown-panel="services">
    <a href="/design">Design</a>
    <a href="/development">Development</a>
  </div>
</nav>

Attributes:

  • data-meno-dropdown="services": trigger key.
  • data-meno-dropdown-panel="services": matching panel key.

State:

  • The panel receives .is-open.
  • The trigger receives aria-expanded.
  • Clicking outside the root closes open dropdowns.

Modal

Use this for centered overlays, signup prompts, video popups, and confirmations.

<button data-meno-open-modal="signup">Open signup</button>

<div data-meno-modal="signup" data-meno-backdrop-close="true">
  <div data-meno-modal-panel>
    <button data-meno-close aria-label="Close">Close</button>
    <h2>Join the list</h2>
    <p>Modal content goes here.</p>
  </div>
</div>

Attributes:

  • data-meno-open-modal="signup": opens a modal with the same key.
  • data-meno-modal="signup": modal wrapper.
  • data-meno-close: closes the nearest modal.
  • data-meno-backdrop-close="true": clicking the backdrop closes the modal.
  • data-meno-backdrop-close="false": disables backdrop close.

State:

  • The modal receives .is-open.
  • The modal hidden attribute is toggled.
  • Body scrolling is locked while a modal is open.
  • Escape closes open modals.

Drawer / Mobile Nav

Use this for side panels, mobile menus, filter panels, or cart drawers.

<button data-meno-open-drawer="menu">Menu</button>

<aside data-meno-drawer="menu">
  <button data-meno-close aria-label="Close menu">Close</button>
  <a href="/">Home</a>
  <a href="/about">About</a>
</aside>

Attributes:

  • data-meno-open-drawer="menu": opens a drawer with the same key.
  • data-meno-drawer="menu": drawer wrapper.
  • data-meno-close: closes the drawer.

Meno agent compatibility:

  • data-action="toggle-mobile-nav" is also treated as a drawer opener.
  • data-action="open-drawer" is also supported.

State:

  • The drawer receives .is-open.
  • The drawer hidden attribute is toggled.
  • Body scrolling is locked while a drawer is open.
  • Escape closes open drawers.

Carousel

Use this for horizontally scrolling cards, logos, images, or testimonials.

<div data-meno-carousel>
  <button data-meno-carousel-prev aria-label="Previous">Previous</button>

  <div data-meno-carousel-track>
    <article data-meno-carousel-item>Slide 1</article>
    <article data-meno-carousel-item>Slide 2</article>
    <article data-meno-carousel-item>Slide 3</article>
  </div>

  <button data-meno-carousel-next aria-label="Next">Next</button>
</div>

Attributes:

  • data-meno-carousel: marks the carousel wrapper.
  • data-meno-carousel-track: marks the scrollable track.
  • data-meno-carousel-item: optional item marker for scroll snapping styles.
  • data-meno-carousel-prev: previous button.
  • data-meno-carousel-next: next button.

Meno agent compatibility:

  • data-el="carousel-track" is also supported.
  • data-action="carousel-prev" and data-action="carousel-next" are also supported.

Behavior:

  • Prev/next scroll by one item width.
  • The CSS file adds smooth horizontal scroll and scroll snapping.

Sticky Header

Use this to add a class after the visitor scrolls.

<header data-meno-sticky data-meno-sticky-threshold="16">
  Site header
</header>

Attributes:

  • data-meno-sticky: watches scroll position.
  • data-meno-sticky-threshold="16": optional pixel threshold. Default is 8.

Meno agent compatibility:

  • data-el="site-header" is also treated as sticky.

State:

  • The header receives .is-scrolled after the threshold.

Smooth Scroll

Use this for in-page anchor navigation.

<nav data-meno-smooth-scroll>
  <a href="#features">Features</a>
  <a href="#pricing">Pricing</a>
</nav>

<section id="features">Features content</section>
<section id="pricing">Pricing content</section>

Attributes:

  • data-meno-smooth-scroll: put this on a wrapper containing anchor links, or directly on an anchor.

Behavior:

  • Links starting with # scroll smoothly to matching element IDs.
  • The URL hash is updated without a full jump.

Copy to Clipboard

Use this for copying codes, links, email addresses, or snippets.

<code id="coupon">SAVE20</code>
<button data-meno-copy="#coupon" data-meno-copied-label="Copied!">Copy code</button>

You can also copy a literal value without a source element:

<button data-meno-copy data-meno-copy-text="[email protected]">Copy email</button>

Attributes:

  • data-meno-copy="#coupon": selector or ID of the source element.
  • data-meno-copy-text="value": fallback literal text to copy.
  • data-meno-copied-label="Copied!": temporary success label.
  • data-meno-copy-timeout="1500": how long the success label stays, in milliseconds.

Meno agent compatibility:

  • data-action="copy" and data-copy-target="coupon" are also supported.

Form State

Use this for simple no-backend validation and success state.

<form data-meno-form data-meno-success="Thanks, we received it.">
  <label>
    Email
    <input name="email" type="email" required data-meno-error="Email is required">
  </label>

  <button type="submit">Submit</button>
  <p data-meno-form-status></p>
</form>

Attributes:

  • data-meno-form: marks a form for handling.
  • data-meno-form-status: element where error/success text appears.
  • data-meno-success="message": success message.
  • data-meno-reset-on-submit="true": reset form after success. Default is true.
  • data-meno-reset-on-submit="false": keep form values after success.
  • data-meno-error="message": field-level required error message.

Behavior:

  • The package prevents default submission.
  • Required fields are checked.
  • A meno:form-submit event is dispatched with { data }.
  • No network call is made. Wire your own backend by listening for meno:form-submit.

Lightbox

Use this for image gallery zoom.

<a href="/images/photo-large.webp" data-meno-open-lightbox data-meno-lightbox-alt="Project photo">
  <img src="/images/photo-thumb.webp" alt="Project photo">
</a>

<div data-meno-lightbox hidden>
  <button data-meno-close aria-label="Close">Close</button>
  <img src="" alt="">
</div>

Attributes:

  • data-meno-open-lightbox: opens the lightbox.
  • data-meno-open-lightbox="/images/photo-large.webp": optional explicit image URL.
  • data-meno-lightbox-alt="Text": alt text for the opened image.
  • data-meno-lightbox: lightbox wrapper.
  • data-meno-close: close button.

State:

  • The lightbox receives .is-open.
  • The lightbox hidden attribute is toggled.

Generic Class Toggle

Use this when you only need to add, remove, or toggle a class.

<button data-meno-class-toggle="is-highlighted" data-meno-target="#card">
  Toggle highlight
</button>

<article id="card">Card content</article>

Attributes:

  • data-meno-class-toggle="class-name": toggles a class.
  • data-meno-class-add="class-name": adds a class.
  • data-meno-class-remove="class-name": removes a class.
  • data-meno-target="#selector": optional target. If omitted, the clicked element is used.

Examples:

<button data-meno-class-add="is-open" data-meno-target="#panel">Open</button>
<button data-meno-class-remove="is-open" data-meno-target="#panel">Close</button>
<div id="panel">Panel</div>

Custom Event Dispatch

Use this to let no-code controls trigger custom JavaScript elsewhere.

<button data-meno-dispatch="pricing:select">Choose plan</button>

<script>
  document.addEventListener('pricing:select', function (event) {
    console.log('Selected from', event.detail.source);
  });
</script>

Attributes:

  • data-meno-dispatch="event-name": dispatches a bubbling custom event from the clicked element.

MenoFilter

MenoFilter is built into Meno and already works with attributes such as data-meno-filter, data-meno-list, data-meno-search, data-meno-sort, and data-meno-page. This package does not replace it; it complements it for UI interactions outside filtering.

Common MenoFilter attributes:

<div data-meno-filter="posts" data-meno-url-sync="true" data-meno-per-page="6">
  <input data-meno-search data-meno-search-fields="title,excerpt" placeholder="Search">

  <button data-meno-filter-field="category" data-meno-filter-value="Design">Design</button>
  <button data-meno-clear>Clear</button>

  <div data-meno-list>
    <article data-category="Design" data-title="Example post">Example post</article>
  </div>

  <p><span data-meno-count="results"></span> results</p>
  <div data-meno-empty>No results found.</div>
</div>

Interactive Styles Pattern

Use the package to toggle state classes, then style those states in Meno interactiveStyles or component CSS.

{
  "interactiveStyles": [
    {
      "name": "Open panel",
      "prefix": "",
      "postfix": ".is-open",
      "style": { "base": { "display": "block", "opacity": "1" } }
    }
  ]
}

For child targets, put the interactive style on the target node and use a parent selector:

{
  "prefix": "[data-el='dropdown']:hover ",
  "postfix": "",
  "style": { "base": { "opacity": "1", "visibility": "visible" } }
}

Meno Agent Compatibility

The script recognizes Meno agent conventions as aliases:

| Agent convention | Package behavior | | --- | --- | | data-action="toggle-accordion" | Accordion trigger | | data-action="select-tab" | Tab trigger | | data-el="tab-panel" | Tab panel | | data-action="toggle-dropdown" | Dropdown trigger | | data-el="dropdown-panel" | Dropdown panel | | data-action="open-modal" | Modal trigger | | data-action="close-modal" | Modal close | | data-action="open-drawer" | Drawer trigger | | data-action="close-drawer" | Drawer close | | data-action="toggle-mobile-nav" | Drawer/mobile nav trigger | | data-el="carousel-track" | Carousel track | | data-action="carousel-prev" | Carousel previous | | data-action="carousel-next" | Carousel next | | data-el="site-header" | Sticky header | | data-action="copy" | Copy trigger | | data-copy-target="id" | Copy source | | data-el="form-status" | Form status element |

JavaScript API

import { init, destroy, register } from 'meno-interactions';

const app = init({ root: document });
app.refresh();
destroy();

register('my-interaction', function (root) {
  const button = root.querySelector('[data-my-button]');
  if (!button) return [];
  const handler = function () {
    console.log('Clicked');
  };
  button.addEventListener('click', handler);
  return [function () { button.removeEventListener('click', handler); }];
});

The browser build exposes window.MenoInteractions:

<script>
  window.MenoInteractions.init();
</script>

Build

npm run build
npm test