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

@carbonbits/sixr

v1.4.0

Published

e-commerce geared component library

Readme

Sixr

E-commerce geared React component library for carbonbits.

Ships ESM + CJS builds with type declarations, and a prebuilt stylesheet. Static components are React Server Component safe and need no "use client" boundary in the Next.js App Router; interactive ones carry their own directive, so either kind imports cleanly into a server component.

Install

pnpm add @carbonbits/sixr

react and react-dom are peer dependencies (^19.0.0). zod (^4) is an optional peer dependency, needed only for @carbonbits/sixr/validation.

Usage

Load the stylesheet once, at the root of your app:

// app/layout.tsx
import "@carbonbits/sixr/styles.css";

Each component has its own subpath. Import from there:

// app/cart/page.tsx
import { Cart, type CartProduct } from "@carbonbits/sixr/cart";

const products: CartProduct[] = [
  { name: "Stovetop kettle", price: 1500 },
  { name: "Enamel mug", price: 500 },
];

export default function Page() {
  return <Cart products={products} currency="KES" locale="en-KE" />;
}

The root barrel (@carbonbits/sixr) re-exports everything and works too, but the subpath is the one to reach for.

Components

Cart

import { Cart } from "@carbonbits/sixr/cart";

| Prop | Type | Default | Description | | ---------- | --------------- | --------- | --------------------------------------- | | products | CartProduct[] | [] | Lines to render. Empty shows a placeholder. | | currency | string | "KES" | ISO 4217 code used to format prices. | | locale | string | "en-KE" | BCP 47 locale used to format prices. |

type CartProduct = {
  /** Stable identity for the line, used as the React key. Falls back to `name`. */
  id?: string;
  name: string;
  price: number;
};

Pass an id whenever a cart can hold two lines with the same name. Prices are formatted with Intl.NumberFormat, and the total is summed from price.

Typography

import { Typography } from "@carbonbits/sixr/typography";

The type scale. Every piece of text the library renders goes through it, and it is the component to reach for when yours does too. Server-safe.

| Prop | Type | Default | Description | | -------------- | ------------------------------------------------------------------------- | ------------------ | -------------------------------------------------------- | | variant | "display" \| "heading" \| "subheading" \| "body" \| "label" \| "hint" \| "code" | "body" | Size, default element and default weight. | | tone | "default" \| "muted" \| "subtle" \| "accent" \| "on-accent" \| "success" \| "warning" \| "info" \| "danger" | "default" | Colour role from the design tokens. | | weight | "regular" \| "medium" \| "semibold" \| "bold" | per variant | Overrides the variant's weight. | | align | "start" \| "center" \| "end" | — | Text alignment. | | truncate | boolean | false | One line, clipped with an ellipsis. | | icon | ReactNode | — | An icon beside the text, sized to it, aria-hidden. | | iconPosition | "leading" \| "trailing" | "leading" | Which side the icon sits on. | | as | "p" \| "span" \| "div" \| "h1"…"h6" \| "label" \| "code" \| … | per variant | The element to render. | | asChild | boolean | false | Merge the styles onto the child element instead. |

Default elements: display → h1, heading → h2, subheading → h3, body and hint → p, label → span, code → code. Any other HTML attribute passes through.

<Typography variant="heading">Welcome back</Typography>
<Typography tone="muted">Sign in to your Carbonbits workspace.</Typography>
<Typography variant="hint" tone="success" icon={<CheckIcon />}>
  Verification code accepted
</Typography>

// Style your own element — a Next.js Link, a Radix Label — with `asChild`.
<Typography variant="label" tone="accent" asChild>
  <Link href="/reset">Forgot your password?</Link>
</Typography>

Inputs: TextInput, EmailInput, PasswordInput, PhoneInput

import { TextInput } from "@carbonbits/sixr/text-input";
import { EmailInput } from "@carbonbits/sixr/email-input";
import { PasswordInput } from "@carbonbits/sixr/password-input";
import { PhoneInput } from "@carbonbits/sixr/phone-input";

Labelled single-line fields with optional schema validation. Each one is for a single kind of value and fixes the input type, keyboard and autofill hints that value needs:

| Component | Value | Fixes | | --------------- | ---------------- | ---------------------------------------------------------------------- | | TextInput | Free text | type="text". Adds mono for the monospace face (verification codes). | | EmailInput | An email address | type="email", inputMode="email", autoComplete="email", no autocapitalise or spellcheck. | | PasswordInput | A secret | type="password", autoComplete="current-password", and a built-in Show/Hide toggle. | | PhoneInput | A phone number | type="tel", inputMode="tel", autoComplete="tel". |

Interactive, so each ships its own "use client" directive and is reachable only at its subpath — none is on the root barrel, which stays server-safe.

They share these props:

| Prop | Type | Default | Description | | -------------------- | ------------------------------------ | -------- | ----------------------------------------------------- | | label | string | — | Field label, associated with the input. | | hint | ReactNode | — | Guidance below the field. Replaced by an error. | | error | string | — | Caller-supplied error. Outranks the schema. | | schema | FieldSchema | — | Any zod schema. Only safeParse is called. | | validateOn | "blur" \| "change" \| "never" | "blur" | When the schema runs. | | onValidationChange | (state: FieldValidation) => void | — | Fires on each validation pass. | | onChange | (value: string) => void | — | Receives the value, not the event. | | value | string | — | Makes the field controlled. | | defaultValue | string | "" | Initial value when uncontrolled. | | optional | boolean | false | Shows an "Optional" marker on the label. | | action | ReactNode | — | Trailing label slot, e.g. a "Forgot?" link. | | trailing | ReactNode | — | Trailing in-field slot. Not on PasswordInput, which owns it. |

And their own:

| Component | Prop | Type | Default | Description | | --------------- | -------------- | -------------------------------- | -------------------------------- | ------------------------------------ | | TextInput | mono | boolean | false | Renders the value in the monospace face. | | PasswordInput | revealable | boolean | true | Shows the Show/Hide toggle. | | PasswordInput | revealLabels | { show: string; hide: string } | { show: "Show", hide: "Hide" } | Toggle text, for localisation. |

Any other <input> attribute — placeholder, maxLength, disabled, autoComplete — is passed straight through, and overrides the component's default where there is one.

import { EmailInput } from "@carbonbits/sixr/email-input";
import { emailSchema } from "@carbonbits/sixr/validation";

<EmailInput
  label="Work email"
  placeholder="[email protected]"
  schema={emailSchema}
  onChange={setEmail}
/>;

Validation runs on blur by default, then on every keystroke once the field has gone invalid, so a corrected value clears the message immediately. The first schema issue is shown, the input gets aria-invalid, and the message is announced via role="alert" and wired up with aria-describedby.

schema is structurally typed, so any zod schema satisfies it without zod appearing in this package's types — you only need zod installed if you use it. The inputs never default to a schema for the same reason; pair them with the ready-made ones under "Validation schemas".

Form / FormError / SubmitButton

import { Form, FormError, SubmitButton } from "@carbonbits/sixr/form";

The shared skeleton behind the login/signup screens: a <form> that disables its fields for the duration of onSubmit, plus a submit button that swaps to a spinner for the same duration. Interactive, so it ships its own "use client" directive and is reachable only at this subpath.

| Component | Prop | Type | Description | | ------------- | -------------- | -------------------------- | --------------------------------------------------------- | | Form | onSubmit | () => void \| Promise<void> | Called after preventDefault. A returned promise drives the disabled/spinner state until it settles. | | Form | children | ReactNode | Fields, FormError, SubmitButton — whatever the design calls for, in order. | | FormError | children | ReactNode | Form-level error (a rejected credential, a failed request). Renders nothing when empty. | | SubmitButton| loadingLabel | ReactNode | Shown next to the spinner in place of children while submitting. |

import { EmailInput } from "@carbonbits/sixr/email-input";
import { Form, FormError, SubmitButton } from "@carbonbits/sixr/form";
import { PasswordInput } from "@carbonbits/sixr/password-input";

function LoginForm() {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [error, setError] = useState<string>();

  const handleSubmit = async () => {
    setError(undefined);
    const ok = await signIn(email, password);
    if (!ok) setError("That email and password don't match.");
  };

  return (
    <Form onSubmit={handleSubmit}>
      <EmailInput label="Work email" onChange={setEmail} />
      <PasswordInput label="Password" onChange={setPassword} />
      <FormError>{error}</FormError>
      <SubmitButton loadingLabel="Signing in…">Sign in</SubmitButton>
    </Form>
  );
}

A field never needs its own disabled={isLoading} — Form groups its children in a fieldset that disables for the duration of onSubmit, so SubmitButton (and any other control inside Form) picks that up for free. Fields, OAuth rows, dividers — anything the design puts between the top of the form and the submit button — are just children; Form doesn't assume a shape beyond that.

Validation schemas

import { emailSchema, passwordSchema } from "@carbonbits/sixr/validation";

Ready-made zod schemas matching the Carbonbits auth rules: emailSchema, passwordSchema, verificationCodeSchema, backupCodeSchema, fullNameSchema, jobTitleSchema and phoneSchema. They are ordinary zod schemas — extend them with .refine, or replace the message with .min(8, "…").

This subpath needs zod (^4), which is an optional peer dependency. Nothing else in the package requires it.

Styling

dist/styles.css is compiled by Tailwind 4 and contains only the utilities the library itself uses, so it is safe to load alongside a consumer's own Tailwind build.

Colours and control metrics come from CSS custom properties, all namespaced --sixr-*, so nothing here can clobber your own Tailwind theme. Override any of them to retheme the library without rebuilding it:

:root {
  --sixr-accent: #0f766e;
  --sixr-line: #d4d4d8;
}

Dark values follow prefers-color-scheme by default. To drive the theme yourself, set data-theme="dark" or data-theme="light" on the root element.

Versioning

Released under semantic versioning: breaking changes only land in major versions, so ^ ranges are safe to pin against.

License

MIT