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

@jiwambe/components

v0.6.6

Published

A production-ready, accessible React component library built with Tailwind CSS and a semantic token design system. Ships as ESM with full TypeScript support.

Readme

@jiwambe/components

A production-ready, accessible React component library built with Tailwind CSS and a semantic token design system. Ships as ESM with full TypeScript support.

Current release: 0.6.6. Release history and migration notes live in CHANGELOG.md.

Publishing (maintainers): pnpm publish runs prepublishOnly, which executes pnpm run test, pnpm run build, and pnpm audit. Resolve or accept any audit findings before the tarball is created. Releases via Changesets (pnpm run release) use the same hook when the package is published.

Installation

pnpm add @jiwambe/components

Peer Dependencies

Make sure you have the following installed in your project:

pnpm add react react-dom tailwindcss

Font Loading

The design system uses Instrument Sans and Inter fonts. Add them to your project (for example via Google Fonts):

<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
  href="https://fonts.googleapis.com/css2?family=Instrument+Sans:wght@400;500;600;700&family=Inter:wght@400;500;600&display=swap"
  rel="stylesheet"
/>

Setup

1. Install

pnpm add @jiwambe/components

Peer dependencies: react, react-dom, tailwindcss

2. Configure Tailwind

In your project's tailwind.config.ts, use the Jiwambe preset. The preset includes the plugin (which injects all design token CSS variables) and the safelist (which ensures all spacing utility classes survive purging).

import uiPreset from '@jiwambe/components/tailwind.preset';

export default {
  presets: [uiPreset],
  content: [
    './src/**/*.{js,ts,jsx,tsx,mdx}',
    // Recommended: prevents spacing classes from being purged
    './node_modules/@jiwambe/components/dist/**/*.js',
  ],
};

If you need to add your own plugins, extend the preset:

export default {
  presets: [uiPreset],
  plugins: [yourOtherPlugin],
  content: [...],
};

3. Usage

import { Box, Stack, Container, Grid } from '@jiwambe/components';

// Spacing tokens match the Jiwambe design token vocabulary:
<Container>
  <Stack spacing="space-4" mt="space-9" direction="column">
    <Box p="space-4">Fixed padding</Box>
    <Box px="fluid-4-9" py="space-6">Fluid horizontal padding</Box>
    <Box m="auto" px="fluid-4-9">Centered box</Box>
  </Stack>
</Container>

<Grid gap="space-4" p="space-2">
  <Box>Cell 1</Box>
  <Box>Cell 2</Box>
</Grid>

// Container gutters default to fluid-4-9 and can be overridden:
<Container />                         // fluid-4-9 gutters (default)
<Container px="space-9" />            // custom gutters
<Container disableGutters />          // no gutters

Spacing token reference

| Token | CSS variable | Resolved value | |---------------|---------------------------|-----------------------------------| | space-0 | var(--space-0) | 0rem | | space-0-25 | var(--space-0-25) | 0.0625rem | | space-1 | var(--space-1) | 0.25rem | | space-2 | var(--space-2) | 0.5rem | | space-3 | var(--space-3) | 0.75rem | | space-4 | var(--space-4) | 1rem | | space-5 | var(--space-5) | 1.25rem | | space-6 | var(--space-6) | 1.5rem | | space-8 | var(--space-8) | 2rem | | space-9 | var(--space-9) | 2.25rem | | space-12 | var(--space-12) | 3rem | | space-16 | var(--space-16) | 4rem | | space-18 | var(--space-18) | 4.5rem | | space-24 | var(--space-24) | 6rem | | space-30 | var(--space-30) | 7.5rem | | space-36 | var(--space-36) | 9rem | | space-48 | var(--space-48) | 12rem | | space-72 | var(--space-72) | 18rem | | space-list-indent | var(--space-list-indent) | 1.6875rem (27px) | | fluid-1-2 | var(--space-fluid-1-2) | clamp(0.25rem, 0.1706rem + 0.3968vw, 0.5rem) | | fluid-2-4 | var(--space-fluid-2-4) | clamp(0.5rem, 0.3413rem + 0.7937vw, 1rem) | | fluid-4-5 | var(--space-fluid-4-5) | clamp(1rem, 0.9206rem + 0.3968vw, 1.25rem) | | fluid-4-6 | var(--space-fluid-4-6) | clamp(1rem, 0.8413rem + 0.7937vw, 1.5rem) | | fluid-4-8 | var(--space-fluid-4-8) | clamp(1rem, 0.6825rem + 1.5873vw, 2rem) | | fluid-4-9 | var(--space-fluid-4-9) | clamp(1rem, 0.6032rem + 1.9841vw, 2.25rem) | | fluid-5-6 | var(--space-fluid-5-6) | clamp(1.25rem, 1.1706rem + 0.3968vw, 1.5rem) | | fluid-6-9 | var(--space-fluid-6-9) | clamp(1.5rem, 1.2619rem + 1.1905vw, 2.25rem) | | fluid-8-16 | var(--space-fluid-8-16) | clamp(2rem, 1.3651rem + 3.1746vw, 4rem) | | fluid-16-18 | var(--space-fluid-16-18) | clamp(4rem, 3.8413rem + 0.7937vw, 4.5rem) | | fluid-30-36 | var(--space-fluid-30-36) | clamp(7.5rem, 7.0238rem + 2.381vw, 9rem) | | fluid-48-72 | var(--space-fluid-48-72) | clamp(12rem, 10.0952rem + 9.5238vw, 18rem) |


Components

Typography

Renders text with design-system typographic styles.

<Typography variant="title-xl" as="h1">Big Headline</Typography>
<Typography variant="text-md">Body copy here.</Typography>
<Typography variant="form-label" as="label">Email</Typography>

Props:

| Prop | Type | Default | Description | | --- | --- | --- | --- | | variant | TypographyVariant | — | Required. One of title-sm, title-md, title-lg, title-xl, text-xs, text-xs-bold, text-sm, text-sm-bold, text-md, text-md-bold, text-xl, form-text, form-label, btn-small, btn-reg, link-md. | | as | string | "p" | HTML element to render (h1h6, p, span, label). | | className | string | — | Additional CSS classes. |

Button

Interactive button with four variants and three sizes.

<Button variant="primary">Submit</Button>
<Button variant="secondary" size="small">Cancel</Button>
<Button variant="ghost" disabled>Disabled</Button>

Props:

| Prop | Type | Default | Description | | --- | --- | --- | --- | | variant | "primary" \| "secondary" \| "inverse" \| "ghost" \| "destructive" | — | Required. Visual style. | | size | "small" \| "medium" \| "large" | "small" | Height, padding, and typography scale. | | disabled | boolean | false | Disables the button. |

Link

Anchor element with variant-based styling.

<Link variant="primary" href="/about">About Us</Link>
<Link variant="inverse" href="/contact">Contact</Link>

Props:

| Prop | Type | Default | Description | | --- | --- | --- | --- | | variant | "primary" \| "secondary" \| "tertiary" \| "inverse" | "primary" | Visual style. | | disabled | boolean | false | Prevents navigation and applies disabled styles. |

Accordion

Single-expansion accordion with keyboard navigation.

<Accordion
  items={[
    { title: 'FAQ 1', content: <p>Answer to FAQ 1</p> },
    { title: 'FAQ 2', content: <p>Answer to FAQ 2</p> },
    { title: 'FAQ 3', content: <p>Answer to FAQ 3</p>, disabled: true },
  ]}
  defaultOpenIndex={0}
/>

Props:

| Prop | Type | Default | Description | | --- | --- | --- | --- | | items | AccordionItem[] | — | Required. Array of { title, content, disabled? }. | | defaultOpenIndex | number | — | Initially open item index (uncontrolled). | | value | number | — | Open item index (controlled). | | onChange | (index: number) => void | — | Called when the open item changes (controlled). |

FAQ

FAQ section with heading, accordion of question/answer pairs, and optional footer link. Multiple items may be open at the same time (per-item toggle; controlled or uncontrolled) with full keyboard navigation. Layout and typography use design tokens aligned with Figma web · library FAQ (fluid section padding, --font-line-snug + FAQ letter-spacing on the heading, text-title-md / text-text-md / text-link-md, and space-* gaps at lg 940px per preset).

<FAQ
  heading="Questions"
  items={[
    { question: 'What is X?', answer: 'X is...' },
    { question: 'How do I Y?', answer: 'You can Y by...', disabled: true },
  ]}
  defaultOpenIndex={0}
  link={{ label: 'View all FAQs', href: '/faq' }}
  linkAs={NextLink}
/>

Props:

| Prop | Type | Default | Description | | --- | --- | --- | --- | | heading | string | "FAQ" | Section heading above the list. | | items | FAQItem[] | — | Required. Array of { question, answer, disabled? }. | | defaultOpenIndex | number \| number[] | [] | Index(es) open by default (uncontrolled); several may be set. | | value | number \| number[] | — | Open index(es) (controlled); several may be open. | | onChange | (indices: number[]) => void | — | Called when open indices change (controlled). | | link | { label: string; href: string } | — | Optional footer link (e.g. "View all FAQs"). | | linkAs | ElementType | "a" | Component for the footer link (e.g. next/link). |

Tab

Horizontal tabs with full ARIA support.

<Tab
  tabs={[
    { label: 'Overview', content: <p>Overview content</p> },
    { label: 'Details', content: <p>Detail content</p> },
    { label: 'Settings', content: <p>Settings content</p>, disabled: true },
  ]}
  defaultActiveIndex={0}
/>

Props:

| Prop | Type | Default | Description | | --- | --- | --- | --- | | tabs | TabItem[] | — | Required. Array of { label, content, disabled? }. | | defaultActiveIndex | number | 0 | Initially active tab (uncontrolled). | | activeIndex | number | — | Active tab index (controlled). | | onTabChange | (index: number) => void | — | Called when the active tab changes (controlled). |

List

Semantic list with correct ul/ol structure. For marker="disc" and marker="decimal" uses block layout and item margin (not flex/gap) so markers render reliably. Use indent and itemPadding="none" for legal/body-copy lists.

<List spacing="space-2">
  <List.Item size="sm">Item one</List.Item>
  <List.Item size="sm">Item two</List.Item>
</List>

<List marker="decimal" spacing="space-3">
  <List.Item size="md">Step one</List.Item>
  <List.Item size="md">Step two</List.Item>
</List>

{/* Legal/body-copy: 27px indent, no extra item padding */}
<List indent="space-list-indent" itemPadding="none" spacing="space-2">
  <List.Item size="md">First term.</List.Item>
  <List.Item size="md">Second term.</List.Item>
</List>

<List marker="none" spacing="space-1">
  <List.Item><Link href="/about">About</Link></List.Item>
</List>

Props:

| Prop | Type | Default | Description | | --- | --- | --- | --- | | marker | "disc" \| "decimal" \| "none" | "disc" | Marker style; decimal renders <ol>. | | spacing | SpacingToken | "space-2" | Vertical spacing between items (margin for disc/decimal, gap for none). | | indent | SpacingToken \| string | — | Left indent (e.g. "space-6", "space-list-indent" for 27px, or "27px"). | | itemPadding | "default" \| "none" | "default" | Item left padding; "none" for body-copy lists. |

Card

Card with optional image, title, description, and action. Aligned with Figma (web · library): media cards use secondary background, fluid padding/gaps, title-md/text-md typography, and 48px action button with rounded-rad-md.

<Card type="text-only" title="Title" description="Description." label="Action" onLabelClick={() => {}} />

<Card
  type="media-horizontal"
  imageSrc="/img.jpg"
  imageAlt="Product"
  title="Product"
  description="Description."
  label="View"
  labelHref="/product"
/>

<Card
  type="media-horizontal"
  imageSrc="/img.jpg"
  imageAlt="Product"
  message="Special Offer"
  title="Product"
  description="Description."
  label="Get started"
/>

Props: type (text-only | media-horizontal | media-vertical), imageSrc, imageAlt, message (overlay on image), title, description, label, onLabelClick, labelHref, linkAs.

Breadcrumb

Breadcrumb navigation with slash or chevron separator. Optional truncation for long paths (first … second-to-last / current).

<Breadcrumb
  items={[
    { label: 'Home', href: '/' },
    { label: 'Products', href: '/products' },
    { label: 'Detail' },
  ]}
/>

<Breadcrumb items={manyItems} truncate separator="slash" />

Props: items (array of { label, href? }), truncate, linkVariant, separator ("slash" | "chevron").

Grid

CSS Grid layout with responsive column counts.

<Grid>
  <div className="col-span-6">Left</div>
  <div className="col-span-6">Right</div>
</Grid>

Props:

| Prop | Type | Default | Description | | --- | --- | --- | --- | | columns | number | 9 (XS), 12 (SM+) | Override responsive column count. | | gap | string | Fluid token | Override gap (e.g. "space-4" or any CSS value). |

Container

Width-constrained content wrapper with responsive padding.

<Container>
  <Grid>
    <div className="col-span-12">Full-width inside container</div>
  </Grid>
</Container>

Props:

| Prop | Type | Default | Description | | --- | --- | --- | --- | | className | string | — | Additional CSS classes. |


Theming

The Jiwambe plugin registers all design tokens as Tailwind utilities. You can override semantic color mappings by passing options to the plugin:

import jiwambePlugin from '@jiwambe/components/plugin';

export default {
  content: [
    './src/**/*.{js,ts,jsx,tsx}',
    './node_modules/@jiwambe/components/dist/**/*.js',
  ],
  plugins: [
    jiwambePlugin({
      colors: {
        'text-primary': '#005748',
        'link-primary': '#19AE8A',
        'fill-action-primary': '#19AE8A',
        'fill-action-primary-hover': '#109274',
      },
    }),
  ],
};

Available Token Categories

| Category | Example Tailwind Class | Description | | --- | --- | --- | | Text colors | text-text-primary | Semantic text color | | Link colors | text-link-primary | Semantic link color | | Fill colors | bg-fill-action-primary | Background fills | | Border colors | border-border-light | Border colors | | Icon colors | text-icon-primary | Icon colors | | Typography | text-title-lg | Composite typography styles | | Spacing | p-space-4, gap-space-fluid-2-4 | Fixed and fluid spacing | | Border radius | rounded-rad-md | Border radius | | Box shadow | shadow-elevation-low | Elevation shadows |

CSS Custom Properties

All tokens are also available as CSS custom properties on :root:

.custom-element {
  color: var(--color-text-primary);
  padding: var(--space-4);
  border-radius: var(--rad-md);
  box-shadow: var(--elevation-low);
}

Design Tokens Reference

Breakpoints

| Name | Value | | --- | --- | | xs | 0px | | sm | 600px | | md | 800px | | lg | 940px | | xl | 1440px |

Grid

| Breakpoint | Columns | Gap | | --- | --- | --- | | XS (0+) | 9 | space-2 (8px) | | SM+ (600+) | 12 | space-fluid-2-4 (8–16px) |

Container

| Breakpoint | Behaviour | | --- | --- | | XS–LG | Horizontal padding space-fluid-4-9 (16–36px) | | XL+ | Max width 83rem (1328px), centred, no padding |


Development

# Install dependencies
pnpm install

# Type-check
pnpm typecheck

# Build
pnpm build

The build output lands in dist/ as ESM with TypeScript declarations and source maps.