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

@ehsaneha/react-primitive-tab

v1.0.1

Published

A headless, type-safe, and hook-based tab primitive for React with full control over state management using react-observable-store.

Downloads

6

Readme

@ehsaneha/react‑primitive‑tab

A headless, zero‑dependency tab primitive for React. It ships only logic—no markup, no styling—so you can render exactly the HTML you want and theme it however you like. Under the hood it leverages react-observable-store for rock‑solid, hook‑friendly state management.

npm i @ehsaneha/react-primitive-tab

Quick look

import React from "react";
import { Tab, TabContent, useTabTrigger } from "@ehsaneha/react-primitive-tab";

export default function ProfileTabs() {
  return (
    <Tab initIndex="posts">
      <TabList />
      <TabPanels />
    </Tab>
  );
}

function TabList() {
  const tabs = [
    { id: "posts", label: "Posts" },
    { id: "likes", label: "Likes" },
    { id: "about", label: "About" },
  ];

  return (
    <div className="flex gap-2 border-b">
      {tabs.map((t) => (
        <Trigger key={t.id} index={t.id} label={t.label} />
      ))}
    </div>
  );
}

function Trigger({ index, label }: { index: string; label: string }) {
  const [selected, select] = useTabTrigger({ index });

  return (
    <button
      className={selected ? "border-b-2 font-medium" : "opacity-60"}
      onClick={select}
    >
      {label}
    </button>
  );
}

function TabPanels() {
  return (
    <>
      <TabContent index="posts">/* … */</TabContent>
      <TabContent index="likes">/* … */</TabContent>
      <TabContent index="about">/* … */</TabContent>
    </>
  );
}
  1. <Tab initIndex> creates an internal store that keeps the active tab’s index.
  2. All children rendered inside <Tab> gain access to that store through React context.
  3. useTabTrigger({ index }) returns [isSelected, activate] for toggling any UI element.
  4. <TabContent index> shows its children only when the given index is active.

API

| Export | Description | | ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | | Tab<S> | Context provider. initIndex (S) – initial tab key/value. | | useTabTrigger<S>( { index } ) | Hook → [isSelected: boolean, activate: () ⇒ void]. Call inside any descendant of Tab to build a trigger (button, link, etc.). | | TabContent<S> | Renders children when its index matches the active one. | | useTabContext() | Low‑level access to the raw context ({ indexStore }). Use only if you need custom behaviour. | | useTab | Internal helper that creates the store; exposed for advanced composition. |

Generic type S The index can be anything that’s comparable via ===—string, number, enum, union, etc.


Styling & accessibility

Because the library is headless you have full control:

  • Render button, a, li > button, or any custom component.
  • Add ARIA roles (role="tablist", role="tab", aria-selected, etc.) as you see fit.
  • Apply your design‑system classes (Tailwind, CSS‑in‑JS, CSS Modules, …).

TypeScript support

Everything is typed end‑to‑end. Pass a union literal to initIndex and enjoy autocompletion & type‑safe triggers/contents.

type Section = "overview" | "settings" | "billing";

<Tab<Section> initIndex="overview"> … </Tab>;

Why another tab library?

  • Headless first – no hard‑coded markup or styles.
  • Tiny – few lines of code, tree‑shake friendly.
  • Composable – built with hooks, not render props.
  • Framework agnostic index – use strings, numbers, enums, whatever.
  • Powered by observable stores – avoids prop drilling and re‑renders only when needed.

Installation

# npm
npm install @ehsaneha/react-primitive-tab

# pnpm
pnpm add @ehsaneha/react-primitive-tab

# yarn
yarn add @ehsaneha/react-primitive-tab

Peer dependency: React ≥ 16.8 (hooks).


License

This package is licensed under the MIT License. See LICENSE for more information.


Feel free to modify or contribute to this package!