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

@nera-static/plugin-page-navigation

v2.4.1

Published

A plugin for Nera static site generator to create sibling page navigation within directories. Perfect for section-based navigation and multi-page document structures.

Readme

@nera-static/plugin-page-navigation

Test npm version

A plugin for the Nera static site generator that creates navigation between sibling pages or allows custom definitions via frontmatter. Lightweight, flexible, and easy to integrate in any layout.

✨ Features

  • Automatically adds navigation based on sibling pages
  • Supports custom navigation overrides via frontmatter
  • Optional sorting using the position frontmatter field
  • Configurable class for highlighting the current page
  • Includes a ready-to-use Pug template with multiple layout options
  • Works with Nera v4.1.0+

🚀 Installation

Install the plugin in your Nera project:

npm install @nera-static/plugin-page-navigation

Nera will automatically detect the plugin and apply the navigation metadata during the build process.

⚙️ Configuration

Create an optional configuration file to override the active class name:

# config/page-navigation.yaml
active_page_nav_class: 'page-nav__link--active'

This class is applied to the current page's link in the generated navigation, alongside page-nav__link.

The value shown is the default, used when no config file is present — so the file is genuinely optional. Set it only to use a different class name.

🧩 Usage

Automatic sibling navigation

By default, pages in the same directory are grouped as siblings. Each link's text is the sibling page's title — a page without one produces an empty link, so title is effectively required.

---
title: Page A
position: 1
---

position is optional and controls the sort order:

  • pages that declare a position come first, ordered by it;
  • pages without one follow, ordered by their href;
  • position: 0 is a real value, not "absent".

Two cases produce no navigation at all, silently, and both are deliberate:

  • Pages at the site root. A page directly in pages/ has no meaningful set of siblings — it would link to every top-level page — so automatic navigation is skipped for it. A custom page_navigation (below) still works there.
  • A directory holding a single page, which would only link to itself.

Custom navigation via frontmatter

You can override the default navigation for a page by defining page_navigation. One entry is enough — unlike automatic navigation, an explicit list is never suppressed:

---
title: Page with custom nav
page_navigation:
  - href: /index.html
    name: Home
  - href: /contact.html
    name: Contact
    current: true
---

Custom entries are passed to the template exactly as written. Nothing is computed for them, so if you want the active class on one of them, set current: true yourself, as above.

Entries must be mappings. An entry that is not one — most commonly an empty list item, which YAML parses as null — is skipped with a warning rather than breaking the render. A page_navigation that is not a list at all (a string, a mapping) is ignored entirely, and the page falls back to no navigation.

Navigation metadata

Every page receives meta.pageNav, always with both keys and always with elements as an array — empty when there is nothing to render:

meta.pageNav = {
  activeClass: 'page-nav__link--active',
  elements: [
    {
      name: 'Page Title',      // the sibling page's `title`
      href: '/path/to/page.html',
      current: true,           // is this the page being rendered?
      position: 0              // index in the sorted list, 0-based
    },
  ]
}

position here is the emitted 0-based index in the finished list, which is not the same thing as the position you write in frontmatter — that one is an arbitrary sort key. For a custom page_navigation, elements holds your entries verbatim, so neither current nor position is present unless you wrote them.

Pages generated by other plugins

Some plugins create pages rather than just annotating them — for example @nera-static/plugin-tags, whose tag overview pages are built while it runs. Plugins execute in the order start: → alphabetical → end:, so by default this plugin runs before plugin-tags and those pages do not exist yet when it does. They end up with no meta.pageNav at all — not an empty one, no key.

Run this plugin last. In your project's config/plugin-order.yaml:

plugin-order:
    - end:
          - plugin-page-navigation

Every page then gets navigation, generated ones included: each tag overview page is a sibling of the others in /tags/, so it receives a nav across all of them with the current tag highlighted, exactly like any other directory. This is safe — the plugin reads only generator-produced fields (href, dirname, title, position) and writes only meta.pageNav, which nothing but your templates consumes, so its position in the order cannot disturb another plugin.

This requires Nera v4.2.0+, where config/plugin-order.yaml is read. On 4.1.x the file is ignored and generated pages simply have no navigation.

Guard your markup either way. Ordering closes the gap for the plugins you have today; add another page-generating plugin later and it reopens. A missing meta.pageNav is undefined, so reading .elements off it throws and the whole build fails, not just that page. The shipped template already guards. If you write your own:

if meta.pageNav && meta.pageNav.elements.length
  nav.page-nav
    each item in meta.pageNav.elements
      a.page-nav__link(href=item.href, class=item.current ? meta.pageNav.activeClass : '') #{ item.name }

🛠️ Template Publishing

Use the default template provided by the plugin:

npx nera-page-navigation

This copies the template and the mixins it depends on:

views/vendor/plugin-page-navigation/
├── page-navigation.pug
└── helper/
    ├── mixins.pug
    └── setup.pug

Publishing skips when the destination directory already exists, so re-running never discards your edits. Note that the check is on the directory, not on each file: once it exists, nothing is copied into it — a template you deleted is not restored, and the command still exits 0.

To overwrite with the packaged versions:

npx nera-page-navigation --force

Upgrading the plugin? --force is what actually delivers a template change. Publishing skips a directory that already exists, so a site that published before an upgrade keeps its old copies and the new markup simply never appears. Upgrading without it is safe — it just does nothing. --force overwrites every file in that directory and discards local edits, so diff your published copies first if you have customised them.

This matters for anyone who published before v2.2.0: the template shipped up to v2.1.0 could not compile at all, and only --force replaces it.

Then include it in your layout:

include ../vendor/plugin-page-navigation/page-navigation

The path is relative to the including file, so from a layout in views/layouts/ this resolves to views/vendor/…. A bare views/vendor/… would resolve to views/layouts/views/vendor/… and fail.

Available navigation styles

  • +simpleNav – Basic horizontal navigation
  • +pipeSeparated – Pipe-separated links
  • +linkList – List-based navigation

Uncomment the layout option that suits your needs inside the template file.

🎨 Styling

The plugin uses BEM CSS methodology:

.page-nav { }
.page-nav__item { }
.page-nav__link { }
.page-nav__link--active { }
.page-nav--list { }
.page-nav--pipe-separated { }

Customize or override these classes in your CSS.

These class names are a public contract. You style them from your own stylesheet, so renaming one is a breaking change and ships as a major version.

📊 Generated Output

The plugin injects navigation metadata into each page's meta object; the markup comes from whichever mixin the template calls. For two pages with the second one current, the shipped mixins produce:

+simpleNav:

<nav class="page-nav">
    <a class="page-nav__link" href="/index.html">Home</a>
    <a class="page-nav__link page-nav__link--active" href="/about.html">About</a>
</nav>

+pipeSeparated:

<nav class="page-nav page-nav--pipe-separated">
    <a class="page-nav__link" href="/index.html">Home</a>&nbsp;|&nbsp;
    <a class="page-nav__link page-nav__link--active" href="/about.html">About</a>
</nav>

+linkList:

<ul class="page-nav page-nav--list">
    <li class="page-nav__item">
        <a class="page-nav__link" href="/index.html">Home</a>
    </li>
    <li class="page-nav__item">
        <a class="page-nav__link page-nav__link--active" href="/about.html">About</a>
    </li>
</ul>

When meta.pageNav.elements is empty, the template renders nothing at all.

🧪 Development

npm install
npx vitest run
npm run lint

npm test runs Vitest in watch mode and does not exit — use npx vitest run for a single pass.

Tests cover:

  • Sibling detection and ordering
  • Custom override behavior
  • Template rendering
  • Active class logic

🤝 Contributing

Issues and pull requests are welcome. See the Nera contributing guide for plugin development, the hook contract, and local setup.

For this repo specifically:

  • npx vitest run and npm run lint must pass (npm test is watch mode).
  • Bump the version and update CHANGELOG.md in the same commit as the change.
  • Template markup and BEM class names are a public contract — users style them from their own CSS, so changing one is a major bump.
  • Releases publish from CI on a pushed v* tag. Never run npm publish.

🧑‍💻 Author

Michael Becker
https://github.com/seebaermichi

🔗 Links

🧩 Compatibility

  • Nera: v4.1.0+ — a baseline rather than a requirement; this plugin uses no generator feature above the 4.x line, and the layout-relative include above needs no pug basedir. The recommended config/plugin-order.yaml entry needs v4.2.0+, where that file is read; on 4.1.x it is ignored and pages generated by other plugins get no navigation
  • Node.js: >= 20.0.0 (matches engines.node)
  • Plugin Utils: ^1.2.0
  • Plugin API: Uses getMetaData() for injecting navigation metadata

📦 License

MIT