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

@overdoser/react-toolkit

v0.5.0

Published

A modern, themeable React component library with SCSS modules.

Readme

@overdoser/react-toolkit

A modern, themeable React component library with SCSS modules.

Installation

npm install @overdoser/react-toolkit

Setup

Import the stylesheet in your app entry point:

import '@overdoser/react-toolkit/theme.css';

Theming

Override --crk-* CSS custom properties to customize the theme:

:root {
  --crk-color-primary: #3b82f6;
  --crk-color-danger: #ef4444;
  --crk-font-family: 'Inter', sans-serif;
}

For per-element tweaks, every component accepts className and a classes prop (internal class names are hashed — never target them directly).

theme.css vs theme.layered.css

The package ships two stylesheets with identical content — same rules, same hashed class names, same --crk-* tokens. The only difference is that theme.layered.css wraps everything in a CSS cascade layer:

@layer crk {
  /* ...the entire stylesheet... */
}

That wrapper changes how your overrides compete with the toolkit's styles. Import exactly one of the two (never both).

The problem with plain theme.css. The overrides you pass via className / classes.* are plain CSS classes, so they tie with the toolkit's own class on specificity — the winner is decided by stylesheet source order, which your bundler controls. In many setups the toolkit CSS is injected after your app CSS, so your overrides silently lose.

What the layer fixes. A core rule of cascade layers: any unlayered style beats any layered style, regardless of specificity or import order. Since theme.layered.css puts the whole toolkit in the crk layer, your own (unlayered) rules — including every className / classes.* override — always win, deterministically:

import '@overdoser/react-toolkit/theme.layered.css'; // instead of theme.css

(If you import CSS from a .css entry instead of JS, the equivalent is @import '@overdoser/react-toolkit/theme.css' layer(crk); as the first line.)

| | theme.css | theme.layered.css | | --- | --- | --- | | Override wins by | specificity, then import order (bundler-dependent) | always (unlayered beats layered) | | --crk-* token theming | ✅ | ✅ (identical) | | Affected by a global CSS reset | only via normal specificity/order | ⚠️ an unlayered reset also beats the toolkit's base styles |

The one caveat. Because layered styles lose to all unlayered styles, an aggressive global reset (e.g. button { font: inherit }) would also override the toolkit's base styles under theme.layered.css. If you ship a heavy reset, put it in its own earlier layer so the order is explicit:

@layer reset, crk;

Rule of thumb: if you heavily customize component internals via classes / className, use theme.layered.css. Otherwise theme.css is fine. Theme-token (--crk-*) overrides work the same in both.

Components

| Component | Description | | --- | --- | | Button | Variants: primary, secondary, danger, ghost. Multiple sizes. Loading states with dots, shimmer, and border animations. | | Link | Styled link with variants and external link support (inline new-tab icon, toggleable). | | Typography | Renders h1-h6, p, span, label. Supports weight, color, align, and truncate. | | List / ListItem | Ordered and unordered lists with configurable spacing. | | Table | Sortable columns, multi-sort with Ctrl+click, pagination, and server-side sort support. | | Dropdown | Menu dropdown with chevron indicator. Also works as a selectable form input with options, value, and onChange. | | Popover | Positioned popover anchored to a trigger element, with viewport-aware auto-flip. | | Modal | Portal-based modal with Header, Body, and Footer compound components. Includes focus trap and escape/backdrop close. | | Draggable | Free-move container for any content. Optional Draggable.Handle, axis lock, viewport/parent bounds, keyboard moves. | | Toast | Imperative notifications: ToastProvider renders, standalone toast() (or useToast()) triggers. Variants, positions, auto-dismiss with hover-pause. | | Tabs | Accessible tabs (Tabs.List / Tabs.Tab / Tabs.Panel). Line/solid/pill variants, vertical, keyboard nav. | | Alert | Inline status message (info/success/warning/danger) with optional title, icon, and dismiss. | | Badge | Small status pill. Variants, soft/solid/outline appearance, sizes, optional status dot. | | Spinner | Indeterminate loading spinner; inherits currentColor. | | Skeleton | Loading placeholder — text (multi-line), circle, or rect; pulse/wave animation. | | Drawer | Off-canvas panel sliding from any edge. Header/Body/Footer, focus trap, Escape/backdrop close. | | Tooltip | Lightweight hover/focus label with open delay and viewport-aware flipping. | | Avatar | Image with initials/icon fallback, sizes, circle/square, presence dot. | | Divider | Horizontal/vertical separator, optional centered label. | | Breadcrumbs | Breadcrumb nav with auto separators and aria-current. | | Pagination | Windowed page nav with ellipses (1 … 6 7 8 9 10 … 99), prev/next/first/last. | | Slider | Single or dual-thumb range input; pointer + keyboard. | | NumberInput | Numeric field with steppers, min/max clamp, arrow-key step. | | Dropzone | File upload via drag-drop or click, with accept/maxSize validation. | | Timer | Countdown/stopwatch, digital or ring, attachable label, imperative controls. | | DatePicker | Date field with a pop-up calendar, keyboard nav, min/max and disabled days. | | Form / FormField | Form wrapper with react-hook-form integration. | | Input | Text input with sizes, error state, and prefix/suffix slots. | | Select | Native <select> with a custom arrow indicator. | | Checkbox | Checkbox with label and indeterminate state support; variant="switch" for a toggle switch. | | CheckboxGroup | Multi-value selection as a checkbox list or toggleable chips. | | Radio / RadioGroup | Context-based radio group. | | Textarea | Textarea with resize control. |

Hooks

| Hook | Description | | --- | --- | | useClickOutside | Detect clicks outside a ref element. | | useFocusTrap | Trap focus within a container. | | useKeyboard | Bind keyboard shortcuts. | | useTableSort | Manage table sort state (single and multi-column). |

Usage

Button

import { Button } from '@overdoser/react-toolkit';

<Button variant="primary" size="md" onClick={handleClick}>
  Save
</Button>

<Button variant="danger" loading loadingStyle="dots">
  Deleting...
</Button>

Form

import { Form, FormField, Input, Button } from '@overdoser/react-toolkit';
import { useForm } from 'react-hook-form';

function LoginForm() {
  const form = useForm();

  return (
    <Form form={form} onSubmit={(values) => console.log(values)}>
      <FormField name="email" label="Email">
        <Input />
      </FormField>
      <FormField name="password" label="Password">
        <Input type="password" />
      </FormField>
      <Button type="submit" variant="primary">Log in</Button>
    </Form>
  );
}

Toast

Mount ToastProvider once (it's the renderer), then fire notifications with the standalone toast() — no hook or context required:

import { ToastProvider, toast, Button } from '@overdoser/react-toolkit';

function App() {
  return (
    <ToastProvider position="top-right">
      <Button onClick={() => toast({ variant: 'success', title: 'Saved', description: 'All set.' })}>
        Save
      </Button>
    </ToastProvider>
  );
}

toast() is importable and callable from anywhere (event handlers, utilities, outside React). It returns an id and exposes toast.dismiss(id) / toast.dismissAll(). A useToast() hook returning the same { toast, dismiss, dismissAll } is also available if you prefer.

Peer Dependencies

  • react >= 18
  • react-dom >= 18
  • react-hook-form >= 7 (optional, needed for Form/FormField)

License

MIT