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

@openpicker/sdk

v0.2.5

Published

Open-source CSS element picker — SDK for invoking the openpicker browser extension.

Readme

@openpicker/sdk

SDK for invoking the OpenPicker browser extension to pick a CSS selector on any page. Website: openpicker.dev · Docs: docs.openpicker.dev · Live demo: demo.openpicker.dev

npm install @openpicker/sdk
import { createOpenpicker, OpenpickerError } from "@openpicker/sdk"

const op = createOpenpicker({ appName: "My App" })

if (await op.isAvailable()) {
  // `url` is required: the extension opens it in a tab, the user picks there,
  // and the selector is routed back here.
  const { selector, matchCount, element } = await op.pick({
    url: "https://app.example.com",
    screenshot: "element", // optional: "none" | "element" | "viewport"
  })
  console.log(selector, matchCount, element)
} else {
  // Prompt the user to install the OpenPicker extension.
}

Constrain the selector

Pass per-dimension rules into a pick (id / class / attribute / tag, each with an allow and an ignore regex), lock the picker UI so the user can't loosen them, and/or require a unique match:

const { selector } = await op.pick({
  url: "https://app.example.com",
  selector: {
    attr: { allow: "^data-step$" }, // only the data-step attribute
    id: { enabled: false },
    class: { enabled: false },
    tag: { enabled: false },
  },
  lockSelectorSettings: true, // rule settings shown read-only
  lockSelectorEdit: true, // selector field read-only
  requireUniqueMatch: true, // confirm only when exactly one element matches
})

SDK rules compose with the user's own saved rules — each layer can only narrow. Since the user can still hand-edit the selector unless you set lockSelectorEdit, validate the result against your config with matchesSelectorConfig:

import { matchesSelectorConfig } from "@openpicker/sdk"

const config = { attr: { allow: "^data-step$" }, tag: { enabled: false } }
const { selector } = await op.pick({ url, selector: config })
if (!matchesSelectorConfig(selector, config)) {
  // doesn't meet your requirement — ask the user to pick again
}

The picker won't return a selector that violates the active rules — it offers a conforming one or none. See Configuring selectors for the full model.

Restrict which element can be picked

selector shapes how a selector is built; mustMatch controls which element can be picked. Pass a CSS selector and only matching elements are selectable (hovering a descendant snaps to the nearest matching ancestor; non-matching elements aren't selectable):

op.pick({ url, mustMatch: "input, textarea, select, [contenteditable]" })

The two axes are independent and compose — e.g. "only inputs, identified by id":

op.pick({
  url,
  mustMatch: "input, textarea, select, [contenteditable]",
  selector: { class: { enabled: false }, attr: { enabled: false }, tag: { enabled: false } },
})

An invalid mustMatch rejects the pick with invalid_params.

More

See the protocol spec for the wire format, and the main README for the full API.