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

thrifty-ui

v0.2.0

Published

A Radix + Tailwind React UI foundation built around usePanelChrome (one panel, four hosts) — primitives, a slidable-column shell, a theming picker, and a Claude Code authoring stack.

Readme

thrifty-ui

A Radix + Tailwind React UI foundation, not a comprehensive component catalog. It hands you the parts that are tedious to stand up yourself — an accessible primitive layer, a slidable-column shell, live theming — built around one sharp idea (usePanelChrome), plus a Claude Code authoring stack so you can grow it into your own kit instead of starting from a blank page.

It's deliberately small. The point isn't breadth; it's a clean base you extend.

  • MIT, React 19, Tailwind v4.
  • Ships as source (TypeScript/TSX) — your bundler + Tailwind compile it, so utility classes and theme tokens resolve in your app with no extra step.

Status: 0.1.0, first release. Expect a focused surface, not a kitchen sink.

The idea: one panel, four hosts

The headline primitive is usePanelChrome. A panel declares its header/footer as content only — it doesn't know or care where it's mounted. The hook does the rest:

  • If the host supplies onHeader/onFooter (a column, a sheet, a dialog, a drawer), the panel's chrome is hoisted into that host's slot.
  • If no host callback is present, the same chrome renders inline in a matching bordered slot, so the panel is self-contained in a bare body.

So the same panel renders correctly in a desktop column, a mobile bottom sheet, a dialog, or a drawer — no useIsMobile branching, no media queries, no per-host variants inside the panel. Desktop/mobile portability falls out of the primitive for free.

import { usePanelChrome } from "thrifty-ui"

function MyPanel({ onHeader, onFooter }) {
  const header = useMemo(() => <h2>Title</h2>, [])
  const footer = useMemo(() => <button>Action</button>, [])
  // Pass MEMOIZED nodes so the hoist only re-pushes on real changes.
  const { header: h, footer: f } = usePanelChrome({ onHeader, header, onFooter, footer })
  return (
    <div className="flex flex-col h-full">
      {h}
      <div className="flex-1 overflow-auto">…body…</div>
      {f}
    </div>
  )
}

What's in it

  • The chrome primitiveusePanelChrome.
  • The shellSlidableColumn (draggable, off-edge-hideable columns), ColumnToolBar, Sheet, Drawer, Popup, SlidingPanels.
  • ThemingThemeScope / useThemeRoot (scoped or :root CSS-variable theming), a ColorPanel picker (with Undo + copy-CSS), StylePanel, TypographyPanel, EffectsPanel, themeToCss, a DEFAULT_THEME and a generateTheme helper.
  • Radix wrappers — Dialog, Popover, Select, Combobox, Menus, Tabs, Form, Toolbar, and more (accessibility inherited from Radix).
  • HooksuseAudioPlayer (+ FFT subscribeFrequency), useAnchoredZoom, useMouseParallax, useSwipeDismiss, useRovingTabindex, and others.
  • A showcase panelMusicPlayerPanel, which exercises the chrome primitive in both modes (its transport hoists to a footer slot, or falls back inline) over the audio singleton + theme-coupled visualizer.

Feeding the MusicPlayer

MusicPlayerPanel is controlled and presentational. Pass playlists in through panelData{ playlists: [{ id, name, tracks: [{ id, title, url }] }] } — and turn on editing with presence-driven callbacks: each affordance renders only when its handler is supplied.

  • onCreatePlaylist / onRenamePlaylist / onDeletePlaylist / onReorderPlaylists
  • onAddTrack (opens a file picker) / onRemoveTrack / onReorderTracks

Omit them all for a read-only player. The host owns the playlist state and its persistence; the panel renders that data and reports edits back through the callbacks.

Install

npm i thrifty-ui
# peers:
npm i react react-dom

Requires Tailwind v4. Import the kit's base styles once, and make sure Tailwind scans the package source so its utilities are generated:

/* your app's CSS entry */
@import "tailwindcss";
@import "thrifty-ui/styles.css";
@source "../node_modules/thrifty-ui";
import { ThemeScope, DEFAULT_THEME, MusicPlayerPanel } from "thrifty-ui"

export function App() {
  return (
    <ThemeScope theme={DEFAULT_THEME}>
      <MusicPlayerPanel />
    </ThemeScope>
  )
}

For top-level theming that also reaches Radix portals (sheets, dialogs, popovers), use useThemeRoot(theme, mode) instead of ThemeScope.

The Claude Code authoring stack

thrifty-ui ships a .claude/ stack — rules that teach an agent the kit's contracts (the usePanelChrome host-claims-or-falls-back model, panelData typing, the public API surface) plus a panel-from-template skill — so if you build with Claude Code, the agent scaffolds new panels correctly against the primitive. It's the fastest way to extend the foundation into your kit; if you don't use Claude Code it's inert and harmless.

Over Radix Themes + Tailwind alone

Radix gives you accessible primitives; Tailwind gives you styling. thrifty-ui adds the layer between them that you'd otherwise hand-roll: the host-agnostic panel-chrome contract, a draggable column shell, CSS-variable theming with a live picker and copy-to-CSS, and the agent stack to author against it.

License

MIT © Clifford James Heenan