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

spin-comp

v0.1.0

Published

Zero-config component scaffolder. Spin up React/Preact/Solid component folders (.tsx, styles, tests, stories, barrel) in seconds with interactive prompts.

Readme

spin-comp

Zero-config component scaffolder. Spin up a complete component folder — source, styles, tests, a Storybook story, and a barrel export — in about 5 seconds instead of 3 minutes of tedious copy-paste.

npx spin-comp Button
src/components/Button/
├── Button.tsx
├── Button.module.css
├── Button.test.tsx
├── Button.stories.tsx   # optional
└── index.ts

No config required to start. When you do want to lock in your team's conventions, drop a .spincomprc.json and every future run is a single keystroke.


Why

Creating a new UI component usually means: make a folder, make a .tsx file, make a .css file, make a .test.tsx file, then paste the same boilerplate into all of them and rename things. spin-comp turns that ritual into one command with a few quick prompts.

  • Fast — full folder in seconds, interactive or fully flag-driven.
  • Flexible — React, Preact, or Solid · TS or JS · CSS Modules, SCSS, styled-components, Tailwind, or none · Vitest or Jest.
  • Consistent — a config file / presets keep every component in your codebase identical in shape.
  • Extensible — override any generated file with your own .tmpl templates.
  • Scriptable — a typed programmatic API for your own tooling.

Install

Run ad-hoc with npx (nothing to install):

npx spin-comp Button

Or add it to a project:

npm install --save-dev spin-comp

Requires Node.js >= 18.

Usage

Interactive (default)

npx spin-comp Button

You'll be asked a handful of questions (kind, framework, language, styling, tests, story, export style, barrel, directory). Values from your config file are pre-selected, so you can blast through with Enter.

Non-interactive

Pass --yes to skip all prompts and use your config + flags + defaults. Great for scripts and muscle memory:

npx spin-comp Button --yes --style css-module --story
npx spin-comp useToggle --yes --kind hook --js
npx spin-comp Theme --yes --kind context

Nested paths

The name accepts a path. Everything before the last segment becomes a sub-directory:

npx spin-comp forms/inputs/TextField --yes
# -> src/components/forms/inputs/TextField/TextField.tsx

Preview without writing

npx spin-comp Button --yes --dry-run

What it generates

| Kind | Files | Default directory | | ----------- | ----------------------------------------------------------- | ----------------- | | component | Name.tsx, styles, Name.test.tsx, Name.stories.tsx, index.ts | src/components | | hook | useName.ts, useName.test.ts, index.ts | src/hooks | | context | Name.tsx (provider + useName hook), test, index.ts | src/context |

Example component (--framework react --style css-module):

import type { ReactNode } from 'react';
import styles from './Button.module.css';

export interface ButtonProps {
  children?: ReactNode;
  className?: string;
}

export function Button({ children, className }: ButtonProps) {
  return <div className={[styles.button, className].filter(Boolean).join(' ')}>{children}</div>;
}

CLI options

Usage: spin-comp [name] [options]
       spin-comp init

Arguments:
  name                       Component/hook/context name (supports nested paths)

Options:
  -k, --kind <kind>          component | hook | context
  -f, --framework <name>     react | preact | solid
  -l, --language <language>  ts | js
      --ts / --js            Shorthand for --language
  -s, --style <style>        css-module | css | scss-module | scss |
                             styled-components | tailwind | none
  -t, --test <runner>        vitest | jest | none
      --testing-library      Include Testing Library assertions
      --no-testing-library   Skip them
      --story / --no-story   Generate a Storybook story
      --barrel / --no-barrel Generate an index barrel file
  -e, --export <style>       named | default
  -d, --dir <path>           Base directory for generated files
      --flat / --no-flat     Write into the directory without a named subfolder
      --props-interface      Generate a typed props interface (TS)
      --no-props-interface   Skip it
      --preset <name>        Use a named preset from your config
      --templates <dir>      Directory of custom .tmpl overrides
      --force                Overwrite files that already exist
      --dry-run              Show what would be generated without writing
  -y, --yes                  Skip interactive prompts
      --cwd <dir>            Working directory
  -v, --version              Print version
  -h, --help                 Show help

Configuration

Run spin-comp init to drop a starter config, or create one by hand. Config is discovered by walking up from the current directory, so a single file at the repo root covers the whole project. Supported locations (first match wins):

  • .spincomprc / .spincomprc.json
  • spin-comp.config.json
  • .config/spin-comp.json
  • a spinComp key inside package.json
{
  "framework": "react",
  "language": "ts",
  "style": "css-module",
  "test": "vitest",
  "testingLibrary": true,
  "story": false,
  "barrel": true,
  "exportStyle": "named",
  "directory": "src/components",
  "presets": {
    "ui": { "directory": "src/components/ui", "story": true },
    "page": { "directory": "src/pages", "style": "css-module" }
  }
}

Select a preset at run time:

npx spin-comp Modal --preset ui --yes

Precedence (lowest to highest): built-in defaults → config file → selected preset → CLI flags → interactive answers.

Custom templates

Point --templates <dir> (or templatesDir in config) at a folder of .tmpl files to override any generated file. Recognized names: component.tmpl, hook.tmpl, context.tmpl, style.tmpl, test.tmpl, story.tmpl, barrel.tmpl.

Placeholders are substituted with {{ ... }}:

| Placeholder | Example (user-card) | | ------------------ | --------------------- | | {{name}} | UserCard | | {{camelName}} | userCard | | {{kebabName}} | user-card | | {{constantName}} | USER_CARD | | {{ext}} | tsx | | {{styleFileName}}| UserCard.module.css | | {{framework}} | react |

templates/component.tmpl
---
import styles from './{{styleFileName}}';

export function {{name}}() {
  return <div className={styles.{{camelName}}} />;
}

Programmatic API

import { scaffold, planScaffoldFor } from 'spin-comp/api';

// Write files to disk
await scaffold('Button', {
  framework: 'react',
  style: 'css-module',
  story: true,
  cwd: process.cwd(),
});

// Or just plan (no writes) — useful in tests
const { files } = await planScaffoldFor('Button', { style: 'none' });
files.forEach((f) => console.log(f.relativePath));

scaffold(name, options) and planScaffoldFor(name, options) accept every config field plus cwd, force, dryRun, templatesDir, preset, and loadConfigFile.

Development

npm install
npm run build       # compile TypeScript to dist/
npm test            # run the vitest suite
npm run typecheck   # type-check without emitting

License

MIT © phemymii