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

@zentauri-ui/zentauri-components

v1.4.51

Published

React + Tailwind UI kit with ESM/CJS builds, per-entry exports, and a zentauri-components / zentauri-ui CLI to vendor UI or hook source into your app

Readme

@zentauri-ui/zentauri-components

A React UI kit for building product interfaces with Tailwind CSS. Components are implemented in TypeScript, ship with declaration files, and are bundled as ESM and CommonJS for broad bundler compatibility.

Overview

The library targets React 18+ apps that use Tailwind CSS v4 (or an equivalent setup where Tailwind can scan this package via @source). Styling uses utility classes; class-variance-authority powers variant APIs (size, appearance, and similar props), with clsx and tailwind-merge for predictable className composition. Framer Motion backs motion where a feature ships animated variants, and react-icons is used for iconography where applicable.

Published artifacts live under dist/. Imports use per-entry subpaths: @zentauri-ui/zentauri-components/ui/<area> for static UI, @zentauri-ui/zentauri-components/ui/<area>/animated where a motion bundle exists, and @zentauri-ui/zentauri-components/hooks/<entry> for React hooks (and shared helpers under hooks/utils). Base UI entries do not re-export animated components; motion lives on its own entry so optional framer-motion usage stays tree-shakeable and chunk-friendly. Each entry resolves to its own ESM (.mjs), CJS (.js), and types (.d.ts) so bundlers pull only what you import. Most apps rely on Tailwind scanning the package sources (see installation); a separate CSS import is not required for that setup.

Package exports

| Subpath | Description | | ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | | @zentauri-ui/zentauri-components/ui/<name> | Single UI area: static primitives, compound parts, variants, and types. Does not include Framer Motion–based animated exports. | | @zentauri-ui/zentauri-components/ui/<name>/animated | Motion entry for that area when published: animated components, motion presets, and related types (depends on framer-motion). | | @zentauri-ui/zentauri-components/hooks/<entry> | One hook module or utils (cn, clampPage, range from src/lib/utils.ts). Entries match files under src/hooks/ (see React hooks). |

The UI <name> segment matches the folder under src/ui/ (for example accordion, select, empty-state, buttons for Button, inputs for Input). The hooks <entry> is the file stem (for example useMediaQuery, usePagination) or utils.

Only a subset of UI areas publish a /animated entry (see Components). Some motion entries also re-export non-motion pieces from the same feature so you can import one motion subpath for a whole flow; others pair a base ui/<name> import with a small set of *Animated exports from ui/<name>/animated—use the animated/index.ts for that area as the source of truth.

Animated components (ui/<name>/animated)

  • Why a separate subpath: animated modules import framer-motion. Keeping them on …/ui/<name>/animated avoids pulling motion into pages that only use the static …/ui/<name> entry and keeps server/client boundaries predictable in app routers.
  • When to install framer-motion: add it when your app imports any @zentauri-ui/zentauri-components/ui/*/animated path (see Optional: animations and icons under installation).

Published motion entries (same <name> as the base UI folder):

accordion, alert, avatar, badge, buttons, card, divider, drawer, empty-state, inputs, modal, progress, skeleton, spinner, table, tabs, toast, toggle, tooltip

Spinner: only the motion entry is built—import from @zentauri-ui/zentauri-components/ui/spinner/animated (there is no separate ui/spinner static bundle).

Requirements

  • React and React DOM >= 18 (peer dependencies)
  • A Tailwind pipeline that can scan this package (see Step 3 below)

Components

Import static primitives from @zentauri-ui/zentauri-components/ui/<subpath> when the Base column lists a path. When the Animated column lists a path, motion components and preset helpers come from @zentauri-ui/zentauri-components/ui/<subpath>/animated (they are not exported from the base entry). Spinner has no static bundle—use only the animated subpath.

| Area | Base subpath …/ui/… | Animated subpath …/ui/…/animated | | -------------- | --------------------- | ------------------------------------ | | Accordion | accordion | accordion/animated | | Alert | alert | alert/animated | | Avatar | avatar | avatar/animated | | Badge | badge | badge/animated | | Breadcrumb | breadcrumb | — | | Button | buttons | buttons/animated | | Card | card | card/animated | | Divider | divider | divider/animated | | Drawer | drawer | drawer/animated | | Dropdown | dropdown | — | | Empty state | empty-state | empty-state/animated | | File upload | file-upload | — | | Input | inputs | inputs/animated | | Modal | modal | modal/animated | | Pagination | pagination | — | | Progress | progress | progress/animated | | Search | search | - | | Select | select | — | | Skeleton | skeleton | skeleton/animated | | Slider | slider | — | | Spinner | — | spinner/animated | | Stepper | stepper | — | | Table | table | table/animated | | Tabs | tabs | tabs/animated | | Toast | toast | toast/animated | | Toggle | toggle | toggle/animated | | Tooltip | tooltip | tooltip/animated |

React hooks

Hooks live in src/hooks/. Each hook is a separate published entry under @zentauri-ui/zentauri-components/hooks/<name> (same pattern as UI areas). Types are exported where the implementation defines them (for example UseDisclosureResult, PaginationPageItem). For class-name merging and pagination helpers used alongside hooks, import from @zentauri-ui/zentauri-components/hooks/utils.

| Hook / module | Subpath …/hooks/… | Notes (selected exports) | | -------------------------- | ----------------------------- | -------------------------- | | useBodyScrollLock | useBodyScrollLock | Locks document scroll while open | | useClickOutside | useClickOutside | ClickOutsideEventType, UseClickOutsideParams | | useClipboard | useClipboard | UseClipboardResult | | useControllableState | useControllableState | UseControllableStateParams | | useDebouncedValue | useDebouncedValue | Debounced state from a value | | useDisclosure | useDisclosure | UseDisclosureParams, UseDisclosureResult | | useDocumentTitle | useDocumentTitle | UseDocumentTitleParams | | useFocusManagement | useFocusManagement | Focus trap / focus moves for overlays | | useHover | useHover | Pointer hover state | | useInView | useInView | UseInViewParams | | useIntersectionObserver | useIntersectionObserver | UseIntersectionObserverParams | | useIsomorphicLayoutEffect| useIsomorphicLayoutEffect | useLayoutEffect safe for SSR | | useIsMounted | useIsMounted | Ref / flag after mount | | useLocalStorage | useLocalStorage | UseLocalStorageResult | | useMediaQuery | useMediaQuery | Match CSS media queries | | useNetworkStatus | useNetworkStatus | Online / offline | | usePageVisibility | usePageVisibility | Document visibility API | | usePagination | usePagination | buildPaginationItems, BuildPaginationItemsParams, PaginationPageItem | | usePrefersColorScheme | usePrefersColorScheme | ColorSchemePreference | | usePrefersReducedMotion | usePrefersReducedMotion | prefers-reduced-motion | | useResizeObserver | useResizeObserver | ElementSize | | useSessionStorage | useSessionStorage | UseSessionStorageResult | | useThrottledCallback | useThrottledCallback | Throttled callback ref | | useToggle | useToggle | Boolean toggle state | | useWindowSize | useWindowSize | WindowSize | | cn, clampPage, range | utils | Shared helpers from src/lib/utils.ts |

Hook import example

import { useDisclosure } from "@zentauri-ui/zentauri-components/hooks/useDisclosure";
import { useMediaQuery } from "@zentauri-ui/zentauri-components/hooks/useMediaQuery";
import {
  buildPaginationItems,
  usePagination,
} from "@zentauri-ui/zentauri-components/hooks/usePagination";
import { cn } from "@zentauri-ui/zentauri-components/hooks/utils";

Some UI packages re-export the hook that belongs to that component (for example usePagination from @zentauri-ui/zentauri-components/ui/pagination). Prefer hooks/<name> when you only need the hook without the UI primitives.

Installation

Getting started — Add the package, install peer dependencies so primitives resolve correctly, point Tailwind at the library sources, then import from ui/<name> (static), ui/<name>/animated (motion, when published), and/or hooks/<entry> subpaths.

Step 1 — Install the package

Choose your package manager.

npm install @zentauri-ui/zentauri-components
pnpm install @zentauri-ui/zentauri-components
yarn add @zentauri-ui/zentauri-components

Step 2 — Install peer dependencies

The library expects react, react-dom, class-variance-authority, clsx, and tailwind-merge in your app. Install them alongside the components package.

npm install react react-dom class-variance-authority clsx tailwind-merge
pnpm add react react-dom class-variance-authority clsx tailwind-merge
yarn add react react-dom class-variance-authority clsx tailwind-merge

Optional: animations and icons

Add framer-motion when you import any @zentauri-ui/zentauri-components/ui/<name>/animated entry (including Spinner, which is only published under ui/spinner/animated). Add react-icons when using icon sets from that package.

npm install framer-motion react-icons
pnpm add framer-motion react-icons
yarn add framer-motion react-icons

Published dist/ files import these packages; they are not vendored inside @zentauri-ui/zentauri-components. Static ui/<name> bundles do not depend on framer-motion; only ui/<name>/animated entries do. Your app installs peers via dependencies where needed, and your bundler resolves them from node_modules.

Next.js: smaller route chunks

In Next.js 13+, enable optimizePackageImports so framer-motion and react-icons are resolved in a more tree-shakeable way:

// next.config.ts (example — API may be stable in your Next version)
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  experimental: {
    optimizePackageImports: ["framer-motion", "react-icons"],
  },
};

export default nextConfig;

Step 3 — Include library paths in globals.css

Add an @source entry so Tailwind scans class names inside @zentauri-ui/zentauri-components. The path is relative to this CSS file—adjust ../ if your file lives elsewhere.

@import "tailwindcss";
@source "../node_modules/@zentauri-ui/zentauri-components";

Step 4 — Import and use components and hooks

Use one subpath per UI area (static and animated are separate entries: ui/<name> vs ui/<name>/animated) and one subpath per hook module so the bundler resolves only the entries you use.

Imports (single UI area)

import {
  Accordion,
  AccordionContent,
  AccordionItem,
  AccordionTrigger,
} from "@zentauri-ui/zentauri-components/ui/accordion";

Imports (multiple UI areas)

import { Button } from "@zentauri-ui/zentauri-components/ui/buttons";
import {
  Select,
  SelectTrigger,
  SelectValue,
  SelectContent,
  SelectItem,
} from "@zentauri-ui/zentauri-components/ui/select";

Imports (hooks alongside UI)

import { useDisclosure } from "@zentauri-ui/zentauri-components/hooks/useDisclosure";
import { Button } from "@zentauri-ui/zentauri-components/ui/buttons";

Imports (animated / Framer Motion)

Use the /animated subpath for motion components and preset helpers. You can import static and motion entries from the same feature in one file when you compose them (names and re-exports differ per area).

import { Button } from "@zentauri-ui/zentauri-components/ui/buttons";
import { ButtonAnimated } from "@zentauri-ui/zentauri-components/ui/buttons/animated";

import { Spinner } from "@zentauri-ui/zentauri-components/ui/spinner/animated";

Usage

<div className="rounded-3xl border border-white/10 bg-white/5 p-5 shadow-2xl shadow-slate-950/40 backdrop-blur-xl">
  <Accordion
    type="single"
    defaultValue="item-1"
    appearance="separated"
    size="md"
  >
    <AccordionItem value="item-1">
      <AccordionTrigger>Shipping</AccordionTrigger>
      <AccordionContent>
        <p className="text-sm text-slate-300">
          Standard delivery in 3-5 business days. Express options at checkout.
        </p>
      </AccordionContent>
    </AccordionItem>
    <AccordionItem value="item-2">
      <AccordionTrigger>Returns</AccordionTrigger>
      <AccordionContent>
        <p className="text-sm text-slate-300">
          Free returns within 30 days of delivery in original condition.
        </p>
      </AccordionContent>
    </AccordionItem>
  </Accordion>
</div>

CLI — copy component source into your app

The package ships a small Node CLI (zentauri-components and zentauri-ui point to the same cli/index.mjs) that copies selected folders from this package’s src/ui and src/hooks into your repository—similar to shadcn/ui. You keep the files, control paths via components.json, and imports are rewritten to your path aliases (@/components/ui, @/hooks, @/lib/utils, and so on).

Which UI folders are valid for add is driven by cli/registry.json: a generated manifest listing every addable directory name (matching src/ui/<name>) plus optional nameAliases so the CLI accepts friendly tokens (for example buttonbuttons).

Commands

Call the published binary by name after the package (recommended so npx does not treat the first word as a shell command):

npx @zentauri-ui/zentauri-components init
npx @zentauri-ui/zentauri-components add buttons inputs
npx @zentauri-ui/zentauri-components -h

Hooks only (copy src/hooks/<name> into your app, plus sibling hook dependencies such as useMediaQuery when needed):

npx @zentauri-ui/zentauri-components add hook useWindowSize
npx @zentauri-ui/zentauri-components add hook useToggle useDebouncedValue

The zentauri-ui binary is the same entry as zentauri-components. If npx still mis-resolves, pin the package:

npx --yes --package=@zentauri-ui/zentauri-components zentauri-components init
npx --yes --package=@zentauri-ui/zentauri-components zentauri-components add button

From a monorepo checkout you can run the script by path instead of npx:

node node_modules/@zentauri-ui/zentauri-components/cli/index.mjs init
node node_modules/@zentauri-ui/zentauri-components/cli/index.mjs add accordion
node node_modules/@zentauri-ui/zentauri-components/cli/index.mjs add hook useWindowSize

| Command | What it does | | ------- | -------------- | | init | Writes components.json in the current working directory (or --cwd) with default aliases and resolvedPaths. Refuses to overwrite an existing file. | | add <names...> | Walks up from --cwd (default .) to find components.json, then copies each resolved UI folder under src/ui, pulls in hooks those files depend on (including transitive hook imports), and creates lib/utils at resolvedPaths.utils from the package template if it is missing. | | add hook <names...> | Same config lookup; copies only hook folders listed under registry.hooks (from hooksEntryNames in tsup.config.ts), including transitive sibling-hook imports. Does not copy UI unless a hook’s imports require you to add a component separately (for example usePagination imports types from ui/pagination). |

Global flags: -h / --help, -v / --version, --cwd <dir> (relative to process.cwd()).

components.json (created by init)

Defaults look like this; edit resolvedPaths and aliases so they match your app’s tsconfig / bundler paths.

{
  "aliases": {
    "ui": "@/components/ui",
    "utils": "@/lib/utils",
    "hooks": "@/hooks"
  },
  "resolvedPaths": {
    "ui": "src/components/ui",
    "utils": "src/lib/utils.ts",
    "hooks": "src/hooks"
  }
}

Registry (cli/registry.json)

  • components: sorted list of folder names under src/ui/ that add may copy. The file is generated; the canonical build list lives in tsup.config.ts as uiComponentNames, and the generator always ensures spinner is included so the CLI stays aligned with the animated-only spinner bundle.
  • hooks: sorted list of folder names under src/hooks/ that add hook may copy; generated from hooksEntryNames in tsup.config.ts (same entries as published …/hooks/<name> subpaths).
  • nameAliases: optional map from a CLI token to a real folder name. Today: buttonbuttons, inputinputs (matching common singular names while folders stay plural).

Example: these are equivalent when nameAliases is configured:

zentauri-components add button
zentauri-components add buttons

After add, imports inside copied .ts/.tsx files are rewritten using your aliases; test files (*.test.*, *.spec.*) from the package are not copied.

When to use the CLI vs npm imports

| Approach | Best when | | -------- | ----------- | | npm + package exports (earlier sections) | You want versioned dependencies, smallest app-owned surface, and tree-shaken dist/ entries. | | init / add | You want vendored source under your repo (customize primitives, match shadcn-style workflows, or lock file-level behavior). |

Tailwind still needs to see the classes your copied files use—point @source at those paths (for example your src/components/ui) rather than only at node_modules/@zentauri-ui/zentauri-components if you no longer rely on scanning the published package.

Checkout the components:

https://zentauri-ui.vercel.app/

Development

From this package directory in the monorepo:

  • pnpm build (or npm run build) — production bundle via tsup (Rollup treeshake + scripts/prepend-use-client.mjs via onSuccess so each UI entry under dist/ui/, including dist/ui/<name>/animated.*, starts with "use client" where needed)
  • pnpm devtsup watch mode (same onSuccess hook after each rebuild)
  • pnpm test / pnpm test:watchVitest and Testing Library unit tests // covered 300+ test cases in total
  • pnpm run generate:registry — runs scripts/generate-registry.mjs, which reads uiComponentNames and hooksEntryNames from tsup.config.ts, merges in spinner, applies fixed nameAliases, and writes cli/registry.json (components + hooks). Run this after adding or renaming UI areas or hook entries so the CLI stays in sync (the script prints counts).
  • prepack — invokes generate:registry automatically before npm pack / publish so the published tarball always ships an up-to-date registry alongside cli/index.mjs.

Github Release log

https://github.com/ShubhamTiwari909/zentauri-ui/releases

NOTE:

This package is in initial phase of development and you might see some minor or major breaking changes in the future. If you want to contribute to this project, email me at @[email protected] or ping me on linkeded https://www.linkedin.com/in/shubham-tiwari-b7544b193/

License

MIT