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

@monoid-dev/use-search

v0.1.1

Published

React hook with sanitized and parsed search string.

Readme

Type-checked query string

use-search is a simple library that helps your deal with all the shit with the query string on the url-bar. Handle search like you React.useState, with validation against arbitrary input!

Install

yarn add @monoid-dev/use-search

Usage

import React from 'react';
import ReactDOM from 'react-dom';

import * as t from 'io-ts'; // For more information about io-ts, please click https://gcanti.github.io/io-ts/

import useSearch, { SearchConfigProvider } from '@monoid-dev/use-search';

export const Page = () => {
  const {
    search, // The parsed { id: string | undefined } object
    updateSearch, // The method to update the object
  } = useSearch(t.type({
    id: t.union([t.undefined,  t.string]),  // Define your query type here
  }));

  return (
    <>
      {JSON.stringify(search)}

      <button
        onClick={() => updateSearch({ id: String(parseInt(search?.id ?? '0') + 1) })}
      >
        Update Search
      </button>
    </>
  );
};

ReactDOM.render((
  <SearchConfigProvider>
    <Page />
  </SearchConfigProvider>
), document.body);

APIs

  • useSearch

    function useSearch<T>(type: t.Type<T>, config?: UseSearchConfig)

    Parameters:

    • type The io-ts type of the parsed search.
    • config The local configuration for the search, shallowly merged with the current UseSearchConfig in the context.

    Return Type:

    • search: T | undefined The parsed and validated search string. Returns undefined when there's an error.
    • setSearch: T Reset the search string, navigating to the new href.
    • updateSearch: Partial<T> Partially update the search string, navigating to the new href.
  • UseSearchConfig

interface UseSearchConfig {
  parse?: (q: string) => unknown; // The method to parse the search string, by default using `query-string` with `{ arrayFormat: 'bracket-separator' }`.
  stringify?: (v: Record<string, unknown>) => string; // The method to stringify the search string from your object, by default using `query-string` with `{ arrayFormat: 'bracket-separator' }`.
  errorPolicy?: 'throw' | 'return'; // If 'throw', throws an error when an error happens. Warning: will cause a white screen when ErrorBoundary is not set up.
  useRouter?: () => Router; // The function that returns a Router object. It is called once per rendering thus safe to pass a React hook here. By default uses the native window.location methods. See API Router.
  omitValue?: (value: unknown) => void; // When to omit value in the query string. By default we omit `undefiend`, `null` and empty or all-whitespace strings.
}
  • Router
interface Router {
  pathname: string; // The current pathname, e.g. the `/search` https://www.google.com.hk/search?q=ErrorBoundary
  search: string; // The current search
  navigate: (link: string) => void; // The method to redirect to new page
}

Recipes:

  • For nextjs

    import { useRouter as useNextRouter } from 'next/router';
    
    // Wrap your tree with global configuration
    const useRouter = () => {
      const router = useNextRouter();
    
      return {
        get pathname() {
          return router.pathname;
        },
        get search() {
          return router.asPath.split('?')[1] ?? '';
        },
        navigate(link: string) {
          router.push(link);
        },
      };
    };
    
    // In _app.tsx
    function MyApp({ Component, pageProps }: any) {
      return (
        <SearchConfigProvider
          config={{
            useRouter,
          }}
        >
          <Component {...pageProps} />
        </SearchConfigProvider>
      );
    }
    
    export default MyApp;

    Note that, per NextJS document, router, does not include query information if the page is static. So you'll need the page to be serverside-generated or you'll face an inconsistency in the rehydration step! Or, you can leverage useEffect for static pages.

  • For react-router-dom

    TBD