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

@helga-agency/faceted-search

v1.2.0

Published

Web components for client-side faceted filtering and full-text search over server-rendered content.

Downloads

1,168

Readme

Faceted Search

Web components for client-side faceted filtering and full-text search over server-rendered content.

All filtering, searching and facet counting happens in the browser — no server round-trips needed. The components read data attributes from existing DOM elements, build internal indexes (powered by itemsjs and MiniSearch), and update visibility in place.

Five custom elements work together through an orchestrator pattern:

  1. <faceted-search> — orchestrator that wires everything together
  2. <faceted-search-input> — wraps a text input for full-text search
  3. <faceted-search-filter-values> — wraps checkbox or radio inputs for facet filtering
  4. <faceted-search-result-reader> — reads item data from the DOM
  5. <faceted-search-result-updater> — shows/hides/reorders result items

Example

<faceted-search data-fuzzy-search data-order-by-relevance>

    <faceted-search-input data-live-search data-debounce="200" data-propagate-to-url>
        <input type="text" placeholder="Search…" />
    </faceted-search-input>

    <faceted-search-filter-values
        data-filter-name="color"
        data-item-selector=".filter-item"
        data-item-value-selector="[data-value]"
        data-item-id-selector="[data-id]"
        data-leads-to-empty-result-class="is-empty"
        data-item-amount-selector=".count"
        data-propagate-to-url
    >
        <div class="filter-item" data-id="col-red" data-value="red">
            <label><input type="checkbox" /> Red <span class="count">0</span></label>
        </div>
        <div class="filter-item" data-id="col-blue" data-value="blue">
            <label><input type="checkbox" /> Blue <span class="count">0</span></label>
        </div>
    </faceted-search-filter-values>

    <faceted-search-result-updater
        data-item-selector=".result-item"
        data-item-id-selector="[data-id]"
        data-empty-results-selector=".empty-message"
        data-results-selector=".results"
    >
        <p class="empty-message" hidden>No results found.</p>
        <div class="results">
            <faceted-search-result-reader
                data-item-selector=".result-item"
                data-item-id-selector="[data-id]"
                data-filter-properties='[{"fieldIDSelector": "[data-color]", "filterName": "color"}]'
                data-search-properties='[{"fieldIDSelector": "[data-name]", "boost": 2}, {"fieldIDSelector": "[data-description]"}]'
            >
                <div class="result-item" data-id="1" data-color="red" data-name="Red Shoe">Red Shoe</div>
                <div class="result-item" data-id="2" data-color="blue" data-name="Blue Hat">Blue Hat</div>
            </faceted-search-result-reader>
        </div>
    </faceted-search-result-updater>

</faceted-search>

Components

<faceted-search>

Orchestrator element. Wraps all other components. Manages child registration, creates the internal model, delegates updates, and restores state from the URL hash.

Attributes

  • data-fuzzy-search (boolean, optional): Enables fuzzy matching for full-text search.
  • data-order-by-relevance (boolean, optional): Orders results by search relevance when a search term is active. When the search term is cleared, DOM order is restored.

<faceted-search-input>

Wraps a single <input> element for full-text search.

Attributes

  • data-live-search (boolean, optional): Emits search events on every keystroke (debounced). Without this attribute, search is triggered only on Enter.
  • data-debounce (number, optional): Debounce delay in milliseconds for live search. Defaults to 0.
  • data-propagate-to-url (boolean, optional): Persists the search term in the URL hash.

Structure

Must contain exactly one <input> element.

<faceted-search-filter-values>

Wraps a group of filter value items. Each item contains a checkbox or radio input. The input type is detected automatically: radio inputs enable single-select behavior, checkboxes allow multi-select.

Attributes

  • data-filter-name (string, required): Unique name for this filter group. Must match a filterName in data-filter-properties on the result reader.
  • data-item-selector (string, required): CSS selector matching each filter item element.
  • data-item-value-selector (string, required): Attribute selector (e.g. [data-value]) to read the filter value from each item.
  • data-item-id-selector (string, required): Attribute selector to read a unique ID from each item.
  • data-leads-to-empty-result-class (string, optional): CSS class applied to items whose expected result count is zero.
  • data-item-amount-selector (string, optional): CSS selector for the element whose text content is updated with the expected result count.
  • data-propagate-to-url (boolean, optional): Persists selected values in the URL hash.

Structure

Each item matching data-item-selector must contain an <input type="checkbox"> or <input type="radio">. All radios in a group should share the same name attribute.

<faceted-search-result-reader>

Reads item data from the DOM. Extracts filter field values and search field values from data attributes on each result item.

Attributes

  • data-item-selector (string, required): CSS selector matching each result item.
  • data-item-id-selector (string, required): Attribute selector for the unique item ID.
  • data-filter-properties (JSON string, required): Array of objects mapping DOM attributes to filter names. Each entry has:
    • fieldIDSelector: attribute selector (e.g. [data-color])
    • filterName: name matching a data-filter-name on a filter-values component
  • data-search-properties (JSON string, required): Array of objects specifying which attributes to index for full-text search. Each entry has:
    • fieldIDSelector: attribute selector (e.g. [data-name])
    • boost (number, optional): score multiplier for this field — see MiniSearch docs for details

Structure

Must contain the result item elements that match data-item-selector.

<faceted-search-result-updater>

Receives ordered visible IDs from the orchestrator and updates the DOM: shows/hides items, reorders them to match relevance order, and toggles an empty-state message.

Attributes

  • data-item-selector (string, required): CSS selector matching each result item.
  • data-item-id-selector (string, required): Attribute selector for the unique item ID.
  • data-empty-results-selector (string, optional): CSS selector for the "no results" message element. Hidden when results exist, shown when empty.
  • data-results-selector (string, optional): CSS selector for the results wrapper element. Hidden when no results, shown when results exist.

Structure

Must wrap the result reader and contain the empty-state element (if configured). The result reader must be nested inside the element matching data-results-selector.

Development

To test the components locally in a browser, use Vite to serve the source files (it resolves bare module imports from node_modules automatically). From the root dir:

npx vite packages/FacetedSearch/src

Then open http://localhost:5173/FacetedSearchTest.html.