Package Name Check

Reads an npm or pip install command package by package and flags typosquats, wrong import names and packages that don't exist yet.

StopsHelps catch a typosquatted package before install

Installation

pnpm dlx shadcn@latest add https://bollard-ui.vercel.app/r/package-name-check.json

The files land in your project. They're yours to edit.

Usage

package-name-check-usage.tsx
import { PackageNameCheck, type PackageInfo } from "@/components/ui/package-name-check"

return <PackageNameCheck defaultValue="npm install loadsh crossenv react@^19 express-session-redis-store" lookup={lookup} now={Date.UTC(2026, 9, 14)} />

What it catches

  • Lookalikes of popular packages, including capital I for l
  • Import names used as install names (sklearn, cv2, bs4, PIL)
  • Node or Python built-ins installed from the registry (fs, crypto, json)
  • Names npm or PyPI can't publish
  • Names that don't exist (AI-hallucinated) or appeared days ago, through your lookup

Props

PackageNameCheck props
PropTypeDefault
value

Controlled text: an install command, a requirements.txt or names one per line.

string—
defaultValue

Initial text when uncontrolled.

string""
onValueChange

Called with the text on every edit or fix.

(value: string) => void—
ecosystem

Registry for bare names. A command (npm i, pip install, uv add…) overrides it.

Ecosystem—
defaultEcosystem

Initial registry when uncontrolled.

Ecosystem"npm"
onEcosystemChange

Called when the user switches registry.

(ecosystem: Ecosystem) => void—
popular

Popular names to compare against per registry. Defaults to a curated list.

Partial<Record<Ecosystem, string[]>>—
lookup

Optional registry lookup (existence, downloads, first publish date). Rejections are caught.

(name: string, ecosystem: Ecosystem, signal: AbortSignal) => Promise<PackageInfo | null>—
now

Clock for "published N days ago", in ms. Defaults to the time the component mounted.

number—
onVerdictsChange

Called with every package's verdict whenever they change.

(verdicts: PackageVerdict[]) => void—
label

Visible label; shorthand for `messages.label`.

string—
messages

Every visible string. `{name}`, `{suggestion}`, `{ecosystem}` and the other placeholders are filled in.

Partial<PackageNameCheckMessages>—

* required. Also accepts the native props of <textarea> (className, aria-*, data-*…), passed through to it.

Accessibility

  • Visible label; ecosystem picker is a labelled radiogroup
  • Textarea is described by the status (role=status)
  • Focus returns to a nearby control after a fix

Only what the source does. Test with your own screen reader and content before shipping.

Limitations

This is a UX guard rail. Enforce on the server: Pin dependencies with a lockfile and scan installs in CI; a client check is advisory.

  • The popular-package list is a curated sample; pass your own
  • Existence and age checks need your registry lookup
  • Doesn't scan package code or check maintainers

Rules

Rules last verified:

Informational. Confirmed npm's 214-character and no-uppercase rules and PyPI's normalization of runs of . - _ to a single -. The incident examples were not re-verified. Copied components don't update themselves, so re-check after rule changes (see updating a component).

What it stops

Helps catch a typosquatted package before install

Also known as

npm install · pip install · requirements.txt · package.json · typosquatting · supply chain · slopsquatting · dependency check

Field type

Dependencies

Pairs well with