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

@arraypress/pagefind-modal-astro

v1.0.0

Published

Astro search modal — headless replacement for Pagefind's built-in UI. Native <dialog>, grouped results, ⌘K, keyboard nav, focus restoration.

Downloads

65

Readme

@arraypress/pagefind-modal-astro

Astro search modal — a headless replacement for Pagefind's built-in <pagefind-modal> Component UI. Native <dialog>, grouped results, keyboard navigation, ⌘K shortcut, focus restoration.

Install

npm install @arraypress/pagefind-modal-astro

Plus run Pagefind as a postbuild step so the search index exists in production:

{
  "scripts": {
    "build": "astro build && pagefind --site dist"
  }
}

Use

---
import { PagefindModal } from '@arraypress/pagefind-modal-astro';
---
<PagefindModal />

<!-- Anywhere on the page — any element with [data-search-open] opens it. -->
<button data-search-open aria-label="Search">
  <svg>…</svg>
</button>

Open with the button, ⌘K (macOS) / Ctrl+K (Windows/Linux), or programmatically via the native <dialog> API:

document.getElementById('pf-search-modal').showModal();

Dev mode

Pagefind's JS bundle only exists in production builds (dist/pagefind/pagefind.js). The modal lazy-loads it on first search — in dev mode the load fails gracefully and the modal shows the unavailable hint. Build the site to test search end-to-end.

Pagefind meta

The modal reads these meta keys per result. Set them on your source pages via data-pagefind-meta="key:value":

| Meta key | Rendered as | |------------|-----------------------------------| | title | Result headline | | image | Thumbnail (falls back to monogram)| | category | Chip above the title | | price | Chip above the title | | artist | "by …" subline | | summary | Excerpt (preferred over Pagefind's auto-excerpt) |

Anything not set is silently omitted.

Section grouping

Results group by URL prefix. The default rules:

import { DEFAULT_SECTIONS } from '@arraypress/pagefind-modal-astro';

DEFAULT_SECTIONS;
// [
//   { prefix: '/products/', key: 'products', label: 'Products', order: 1 },
//   { prefix: '/blog/',     key: 'posts',    label: 'Posts',    order: 2 },
//   { prefix: '/news',      key: 'news',     label: 'News',     order: 3 },
//   { prefix: '',           key: 'pages',    label: 'Pages',    order: 9 },
// ]

Override for your routes:

<PagefindModal sections={[
  { prefix: '/docs/',    key: 'docs',    label: 'Documentation', order: 1 },
  { prefix: '/guides/',  key: 'guides',  label: 'Guides',        order: 2 },
  { prefix: '',          key: 'pages',   label: 'Other',         order: 9 },
]} />

Rules try in array order; the first matching prefix wins. The last entry with prefix: '' catches everything else.

i18n

All structural strings are configurable:

<PagefindModal strings={{
  ariaLabel:   'Recherche',
  placeholder: 'Chercher…',
  idleHint:    'Tapez pour rechercher.',
  noResults:   'Aucun résultat.',
  closeLabel:  'Fermer la recherche',
  navHint:     'Naviguer',
  openHint:    'Ouvrir',
  closeHint:   'Fermer',
}} />

Keyboard shortcuts

| Key | Action | |----------------|-----------------------------------| | ⌘K / Ctrl+K | Toggle the modal | | Esc | Close (native <dialog>) | | ↑ / ↓ | Navigate results | | Enter | Open the selected result |

Focus is restored to the trigger element on close.

Props

| Prop | Default | Description | |-----------------|--------------------------|---------------------------------------------------| | id | 'pf-search-modal' | Dialog DOM id. | | pagefindPath | '/pagefind/pagefind.js'| Override if you serve Pagefind from a sub-path. | | sections | DEFAULT_SECTIONS | URL-prefix grouping rules. | | strings | English | i18n overrides. | | maxResults | 12 | How many top hits to hydrate per query. | | excerptLength | 25 | Pagefind excerptLength option (words). | | debounceMs | 120 | Debounce on input → search. | | class | — | Extra classes on the <dialog>. |

Styling

The component ships no styles. Hook against these class names in your stylesheet:

.pf-modal                — <dialog>
.pf-modal__panel
.pf-modal__head, __icon, __input, __kbd, __close
.pf-modal__results, __hint
.pf-modal__foot
.pf-group, .pf-group__heading
.pf-result, .pf-result__thumb (with --placeholder), __body
.pf-result__meta, __chip, __price
.pf-result__title, __artist, __excerpt, __url
.pf-result[aria-selected="true"]   /* keyboard/hover selection */
body.pf-search-open                /* added while modal is open */

License

MIT