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

@ibis-design/react

v0.9.0

Published

React component library for the IBIS design system.

Readme

@ibis-design/react

React component library for the IBIS design system—buttons, inputs, feedback, and app shells—styled with tokens from @ibis-design/css.

Requirements

  • React 18 or 19
  • @ibis-design/css (peer dependency for tokens and component styles)

Installation

npm install @ibis-design/react @ibis-design/css

App setup

Load tokens and layout/card styles once at the root of your app, then set brand and color mode on <html>.

import "@ibis-design/css";
import "@ibis-design/react/styles.css";
import { setTheme } from "@ibis-design/css/theme";
import { Button, TextInput } from "@ibis-design/react";
import { useEffect } from "react";

export const App = () => {
  useEffect(() => {
    setTheme({ brand: "ib", colorMode: "light" });
  }, []);

  return (
    <>
      <Button variant="primary" size="md">
        Continue
      </Button>
      <TextInput label="Email" placeholder="[email protected]" />
    </>
  );
};

| data-brand | Brand | | ------------ | ------- | | ib | Ibis | | alc | Alchemy |

| data-color-mode | Mode | | ----------------- | ----- | | light | Light | | dark | Dark |

import { setTheme } from "@ibis-design/css/theme";

setTheme({ brand: "alc", colorMode: "dark" });

Your bundler must process CSS imports from @ibis-design/css and from this package (styles.css covers layout and Card styles; individual components import their own CSS).


Components

Button

Primary actions, form submit, and secondary cancel flows.

| Prop | Type | Default | Description | | ---------- | --------------------------------- | ----------- | ------------------------ | | variant | 'primary' \| 'secondary' | 'primary' | Visual style | | size | 'sm' \| 'md' \| 'lg' | 'md' | Padding and type size | | type | 'button' \| 'submit' \| 'reset' | 'button' | Native button type | | disabled | boolean | false | Disables interaction | | loading | boolean | false | Spinner + disabled | | skeleton | boolean | false | Placeholder shimmer | | iconOnly | boolean | false | Square icon button | | label | string | — | Text when no children |

import { Button } from "@ibis-design/react";

<Button variant="primary" size="md">Submit payment</Button>
<Button variant="secondary" size="sm">Cancel</Button>
<Button type="submit" loading>Saving…</Button>
<Button iconOnly aria-label="Search">🔍</Button>

TextInput

Labeled text fields with help, error, prefix/suffix, and prepend blocks. Extends native <input> props (except prefix, which is a React node slot).

| Prop | Type | Default | Description | | ------------- | ----------------------- | ------- | ------------------ | | label | string | — | Field label | | inputSize | 'sm' \| 'md' \| 'lg' | 'md' | Size scale | | invalid | boolean | false | Error styling | | error | string | — | Shown when invalid | | description | string | — | Below label | | helpText | string | — | Below field | | loading | boolean | false | Loading state | | prefix / suffix / prepend | ReactNode | — | Icons or blocks | | prefixText / suffixText / prependText | string | — | Plain text slots |

import { useState } from "react";
import { TextInput } from "@ibis-design/react";

const [email, setEmail] = useState("");

<TextInput
  label="Email"
  type="email"
  placeholder="[email protected]"
  description="Used for receipts."
  helpText="We never share your email."
  value={email}
  onChange={(e) => setEmail(e.target.value)}
/>

<TextInput
  label="Amount"
  invalid={!!error}
  error={error}
  prefixText="$"
  value={amount}
  onChange={(e) => setAmount(e.target.value)}
/>

TextArea

Multi-line input; same sizing and validation props as TextInput (inputSize, invalid, error, loading, rows, etc.).

import { useState } from "react";
import { TextArea } from "@ibis-design/react";

const [notes, setNotes] = useState("");

<TextArea
  label="Notes"
  rows={4}
  placeholder="Optional details…"
  value={notes}
  onChange={(e) => setNotes(e.target.value)}
/>

Checkbox

| Prop | Type | Default | Description | | --------------- | ---------------------- | ------- | --------------- | | label | string | — | Label text | | checked | boolean | — | Controlled | | onChange | — | — | Native handler | | inputSize | 'sm' \| 'md' \| 'lg' | 'md' | Control size | | disabled | boolean | false | | | invalid | boolean | false | | | description | string | — | Helper copy | | helpText | string | — | | | error | string | — | | | checkboxIcon | ReactNode | — | Custom checkmark |

import { useState } from "react";
import { Checkbox } from "@ibis-design/react";

const [accepted, setAccepted] = useState(false);

<Checkbox
  label="I accept the terms"
  description="Required to open an account."
  checked={accepted}
  onChange={(e) => setAccepted(e.target.checked)}
/>

Radio

Share name across options and control selection with group + onGroupChange (or checked via group === value).

| Prop | Type | Default | Description | | ---------------- | ---------------------- | ------- | -------------- | | label | string | — | Option label | | value | string \| number | required | Option value | | group | string \| number | — | Selected value | | onGroupChange | (value) => void | — | Group handler | | name | string | — | Radio group | | inputSize | 'sm' \| 'md' \| 'lg' | 'md' | | | disabled / invalid | boolean | | |

import { useState } from "react";
import { Radio } from "@ibis-design/react";

const [accountType, setAccountType] = useState("personal");

<Radio
  name="account"
  label="Personal"
  value="personal"
  group={accountType}
  onGroupChange={setAccountType}
/>
<Radio
  name="account"
  label="Business"
  value="business"
  group={accountType}
  onGroupChange={setAccountType}
/>

Switch

Toggle for settings; uses checkbox input semantics with checked and onChange.

import { useState } from "react";
import { Switch } from "@ibis-design/react";

const [enabled, setEnabled] = useState(true);

<Switch
  label="Email notifications"
  checked={enabled}
  onChange={(e) => setEnabled(e.target.checked)}
/>

Dropdown

Select-style control with options: { label, value }[] and controlled value / onValueChange.

import { useState } from "react";
import { Dropdown } from "@ibis-design/react";

const [currency, setCurrency] = useState("usd");
const options = [
  { label: "US Dollar", value: "usd" },
  { label: "Euro", value: "eur" },
];

<Dropdown
  label="Currency"
  options={options}
  value={currency}
  onValueChange={setCurrency}
  placeholder="Choose currency"
/>

DropdownButton

Menu anchored to a button. Pass menu as a render prop that receives close to dismiss after an action.

| Prop | Type | Description | | ------------- | ---------------------------- | ------------------------ | | label | string | Trigger button text | | trigger | ReactNode | Custom trigger element | | menu | (close: () => void) => ReactNode | Menu items | | disabled | boolean | |

import { DropdownButton } from "@ibis-design/react";

<DropdownButton label="Account">
  {(close) => (
    <>
      <button type="button" className="ibis-dropdown-menu__item" onClick={close}>
        Profile
      </button>
      <button type="button" className="ibis-dropdown-menu__item" onClick={close}>
        Sign out
      </button>
    </>
  )}
</DropdownButton>

Chips

Filter or toggle chips.

| Prop | Type | Default | Description | | ------------------ | ---------------------- | ------- | ------------------ | | size | 'sm' \| 'md' \| 'lg' | 'md' | | | selected | boolean | false | Toggle state | | onSelectedChange | (selected) => void | — | | | loading / skeleton | boolean | false | | | label | string | — | Text if no children | | icon / iconText | ReactNode / string | — | Leading icon |

import { useState } from "react";
import { Chips } from "@ibis-design/react";

const [active, setActive] = useState(false);

<Chips label="Pending" selected={active} onSelectedChange={setActive} />
<Chips label="Starred" iconText="★" size="sm" />

PillTab & PillTabs

Segmented control built on radio inputs. Wrap tabs in PillTabs; share name and group / onGroupChange.

import { useState } from "react";
import { PillTabs, PillTab } from "@ibis-design/react";

const [tab, setTab] = useState("overview");

<PillTabs>
  <PillTab name="main" label="Overview" value="overview" group={tab} onGroupChange={setTab} />
  <PillTab name="main" label="Activity" value="activity" group={tab} onGroupChange={setTab} />
  <PillTab name="main" label="Settings" value="settings" group={tab} onGroupChange={setTab} />
</PillTabs>

TextLink

Styled anchor with underline modes and optional icons.

| Prop | Type | Default | | ----------- | --------------------------------- | --------- | | href | string | — | | underline | 'always' \| 'hover' \| 'none' | 'hover' | | linkSize | 'sm' \| 'md' \| 'lg' | 'md' | | disabled / loading / skeleton | boolean | false |

import { TextLink } from "@ibis-design/react";

<TextLink href="/help" underline="hover">
  Need help?
</TextLink>

Banner

Inline page-level message. Types: success, error, default. Optional closable, loading, icon / iconText, and children for rich body content.

import { Banner } from "@ibis-design/react";

<Banner
  type="success"
  title="Transfer complete"
  message="Funds will arrive in 1–2 days."
  closable
/>
<Banner type="error" title="Payment failed">
  Check your card details and try again.
</Banner>

Toaster

Compact toast-style message. Types: success, error, accent, default.

import { Toaster } from "@ibis-design/react";

<Toaster
  type="accent"
  title="Session expiring"
  message="Sign in again to continue."
  closable
/>

TipIndicator

Hover/focus tooltip on an information indicator. Requires text.

| Prop | Type | Default | | ---------- | ----------------------------------------- | -------- | | text | string | required | | position | 'top' \| 'bottom' \| 'left' \| 'right' | 'top' | | width | 'auto' \| '240' \| '360' | 'auto' | | disabled | boolean | false |

import { TipIndicator } from "@ibis-design/react";

<TipIndicator
  text="International transfers may include fees."
  position="top"
  width="240"
/>

Card

Simple surfaced container (requires styles.css import at app root).

import { Card } from "@ibis-design/react";

<Card>
  <h2>Account summary</h2>
  <p>Balance and recent activity.</p>
</Card>

Layouts

Optional region props accept ReactNode. Main content goes in children.

AppLayout

header, sidebar, footer, and children (main).

import { AppLayout } from "@ibis-design/react";

<AppLayout
  header={<nav>My app</nav>}
  sidebar={<aside>Navigation</aside>}
  footer={<footer>© IBIS</footer>}
>
  <h1>Dashboard</h1>
  <p>Main content.</p>
</AppLayout>

AuthLayout

Centered column for sign-in / sign-up. Optional logo and footer.

import { AuthLayout } from "@ibis-design/react";

<AuthLayout logo={<img src="/logo.svg" alt="IBIS" />}>
  <form>
    <h1>Sign in</h1>
    {/* fields */}
  </form>
</AuthLayout>

DashboardLayout

Dashboard shell with themed header and sidebar (same region API as AppLayout).

import { DashboardLayout } from "@ibis-design/react";

<DashboardLayout header={<header>Dashboard</header>} sidebar={<nav>Menu</nav>}>
  <p>Widgets and charts.</p>
</DashboardLayout>

Vanilla HTML / other frameworks

Component classes and tokens live in @ibis-design/css. Use this package for ready-made React components; use the CSS package directly for Vue or plain HTML. See the @ibis-design/css README.

For Svelte 5, see @ibis-design/svelte.


Exports

Components: Button, DropdownButton, PillTab, PillTabs, TextInput, TextArea, Checkbox, Radio, Switch, Dropdown, Chips, TextLink, Banner, Toaster, TipIndicator, Card, AuthLayout, AppLayout, DashboardLayout

Types: ButtonVariant, ButtonSize, BannerType, ToasterType, DropdownOption, AuthLayoutProps, AppLayoutProps, DashboardLayoutProps

import { Button, type ButtonVariant } from "@ibis-design/react";