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

@demodev-ui/react

v1.0.3

Published

CSS-only design system built on [HeroUI v3](https://v3.heroui.com). Provides custom themes, design tokens, and component styles.

Readme

@demodev-ui/react

CSS-only design system built on HeroUI v3. Provides custom themes, design tokens, and component styles.

All React components come from @heroui/react. This package only provides style overrides via a single CSS import.

Installation

npm install @demodev-ui/react @heroui/[email protected] @heroui/[email protected] tailwindcss@^4 @tailwindcss/vite

Setup

CSS (import order matters)

@import "tailwindcss";
@import "@heroui/styles";
@import "@demodev-ui/react/styles";

@source "../node_modules/@heroui/react/dist";

Vite Config

import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import tailwindcss from "@tailwindcss/vite";

export default defineConfig({
  plugins: [tailwindcss(), react()],
});

App Root (Toast provider)

import { Toast } from "@heroui/react";

function App() {
  return (
    <div className="min-h-screen bg-background text-foreground">
      {/* your app */}
      <Toast.Provider />
    </div>
  );
}

Critical Rules

1. Import source

// CORRECT
import { Button, Input, Modal } from "@heroui/react";

// WRONG — this package has no component exports
import { Button } from "@demodev-ui/react"; // does not exist

2. Collection components must be inside their parent

These crash at runtime if rendered outside their collection context:

| Component | Must be inside | |-----------|---------------| | ListBox.Item | <ListBox> | | Tag | <TagGroup.List> | | Dropdown.Item | <Dropdown.Menu> | | Tabs.Tab | <Tabs.List> |

3. Trigger button nesting

Some Trigger components render their own <button>. Putting <Button> inside them creates invalid HTML (<button> inside <button>):

| Trigger | Renders as | Can contain <Button>? | |---------|-----------|----------------------| | Modal.Trigger | <div> | YES | | AlertDialog.Trigger | <div> | YES | | Dropdown.Trigger | <div> | YES | | Tooltip.Trigger | <button> | NO — use <span> as child | | ComboBox.Trigger | <button> | NO |

4. Button color via data attribute

Button does not have a color prop. Use data-color for outline/ghost color variants:

<Button variant="outline" data-color="accent">Accent</Button>
<Button variant="ghost" data-color="danger">Danger</Button>
// Available: "accent" | "danger" | "success" | "warning"

Design Tokens

Colors

/* Gray (oklch) */
--color-gray-50 ~ --color-gray-950  /* 11-step neutral scale */

/* Semantic */
--danger:  #ef1026;
--success: #27c961;
--warning: #ffdc18;

Border Radius

--radius-button-xs: var(--radius-md)
--radius-button-sm: var(--radius-lg)
--radius-button-md: 0.625rem   /* 10px */
--radius-button-lg: var(--radius-xl)
--radius-chip-sm:   var(--radius-md)
--radius-chip-md:   var(--radius-lg)
--radius-input-lg:  var(--radius-button-lg)
--radius-list-box:  var(--radius-xl)
--radius-toast:     var(--radius-2xl)

Spacing (component heights)

--spacing-button-sm: 36px
--spacing-button-md: 40px
--spacing-button-lg: 48px
--spacing-chip-sm:   24px
--spacing-chip-md:   32px
--spacing-chip-lg:   36px
--spacing-input-lg:  48px

Component Reference

Every code example below is verified and runs without errors.

Button

import { Button } from "@heroui/react";

// Variants: "primary" | "secondary" | "outline" | "ghost" | "danger" | "danger-soft" | "tertiary"
// Sizes: "sm" | "md" | "lg"
<Button variant="primary" size="md">Click me</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="danger">Danger</Button>
<Button size="sm" isIconOnly>+</Button>
<Button isDisabled>Disabled</Button>

// Color variants for outline/ghost (use data-color, not color prop)
<Button variant="outline" data-color="accent">Accent</Button>
<Button variant="outline" data-color="danger">Danger</Button>
<Button variant="outline" data-color="success">Success</Button>
<Button variant="outline" data-color="warning">Warning</Button>

ButtonGroup

import { Button, ButtonGroup } from "@heroui/react";

// Horizontal (default)
<ButtonGroup>
  <Button>Left</Button>
  <ButtonGroup.Separator />
  <Button>Center</Button>
  <ButtonGroup.Separator />
  <Button>Right</Button>
</ButtonGroup>

// Vertical
<ButtonGroup orientation="vertical">
  <Button>Top</Button>
  <ButtonGroup.Separator />
  <Button>Bottom</Button>
</ButtonGroup>

// Group with size
<ButtonGroup size="sm">
  <Button>A</Button>
  <ButtonGroup.Separator />
  <Button>B</Button>
</ButtonGroup>

Input

import { Input } from "@heroui/react";

// Variants: "primary" | "secondary"
<Input placeholder="Primary" variant="primary" />
<Input placeholder="Secondary" variant="secondary" />
<Input placeholder="Disabled" disabled />

TextField

import { TextField, Input, Label, Description } from "@heroui/react";

<TextField variant="primary">
  <Label>Email</Label>
  <Input placeholder="[email protected]" />
  <Description>We'll never share your email.</Description>
</TextField>

<TextField variant="primary" isRequired>
  <Label>Password</Label>
  <Input type="password" placeholder="Enter password" />
</TextField>

InputGroup

import { InputGroup } from "@heroui/react";

<InputGroup variant="primary">
  <InputGroup.Prefix>https://</InputGroup.Prefix>
  <InputGroup.Input placeholder="example.com" />
</InputGroup>

<InputGroup variant="primary">
  <InputGroup.Input placeholder="Amount" />
  <InputGroup.Suffix>USD</InputGroup.Suffix>
</InputGroup>

TextArea

import { TextField, TextArea, Label } from "@heroui/react";

<TextField variant="primary">
  <Label>Message</Label>
  <TextArea placeholder="Type your message..." />
</TextField>

NumberField

import { NumberField, Label } from "@heroui/react";

<NumberField variant="primary" defaultValue={5} minValue={0} maxValue={100}>
  <Label>Quantity</Label>
  <NumberField.Group>
    <NumberField.DecrementButton>-</NumberField.DecrementButton>
    <NumberField.Input />
    <NumberField.IncrementButton>+</NumberField.IncrementButton>
  </NumberField.Group>
</NumberField>

SearchField

import { SearchField, Label } from "@heroui/react";

<SearchField variant="primary">
  <Label>Search</Label>
  <SearchField.Group>
    <SearchField.SearchIcon />
    <SearchField.Input placeholder="Search..." />
    <SearchField.ClearButton />
  </SearchField.Group>
</SearchField>

ComboBox

import { ComboBox, Input, Label, ListBox } from "@heroui/react";

<ComboBox variant="primary">
  <Label>Fruit</Label>
  <ComboBox.InputGroup>
    <Input placeholder="Select a fruit..." />
    <ComboBox.Trigger />
  </ComboBox.InputGroup>
  <ComboBox.Popover>
    <ListBox>
      <ListBox.Item id="apple" textValue="Apple">
        Apple
        <ListBox.ItemIndicator />
      </ListBox.Item>
      <ListBox.Item id="banana" textValue="Banana">
        Banana
        <ListBox.ItemIndicator />
      </ListBox.Item>
    </ListBox>
  </ComboBox.Popover>
</ComboBox>

Select

import { Select, Label, ListBox } from "@heroui/react";

// Variants: "primary" | "secondary"
<Select variant="primary">
  <Label>Country</Label>
  <Select.Trigger>
    <Select.Value>Select a country</Select.Value>
    <Select.Indicator />
  </Select.Trigger>
  <Select.Popover>
    <ListBox>
      <ListBox.Item id="kr" textValue="South Korea">
        South Korea
        <ListBox.ItemIndicator />
      </ListBox.Item>
      <ListBox.Item id="us" textValue="United States">
        United States
        <ListBox.ItemIndicator />
      </ListBox.Item>
    </ListBox>
  </Select.Popover>
</Select>

Checkbox

import { Checkbox, Label, Description } from "@heroui/react";

// Variants: "primary" | "secondary"
<Checkbox variant="primary" id="terms">
  <Checkbox.Control />
  <Checkbox.Content>
    <Label>Accept terms</Label>
    <Description>You agree to the terms of service</Description>
  </Checkbox.Content>
</Checkbox>

<Checkbox variant="primary" id="newsletter" defaultSelected>
  <Checkbox.Control />
  <Checkbox.Content>
    <Label>Newsletter</Label>
  </Checkbox.Content>
</Checkbox>

<Checkbox variant="primary" id="disabled" isDisabled>
  <Checkbox.Control />
  <Checkbox.Content>
    <Label>Disabled</Label>
  </Checkbox.Content>
</Checkbox>

RadioGroup

import { RadioGroup, Radio, Label, Description } from "@heroui/react";

<RadioGroup variant="primary" defaultValue="option1">
  <Label>Select an option</Label>
  <Radio value="option1">
    <Radio.Control>
      <Radio.Indicator />
    </Radio.Control>
    <Radio.Content>
      <Label>Option 1</Label>
      <Description>First choice</Description>
    </Radio.Content>
  </Radio>
  <Radio value="option2">
    <Radio.Control>
      <Radio.Indicator />
    </Radio.Control>
    <Radio.Content>
      <Label>Option 2</Label>
    </Radio.Content>
  </Radio>
  <Radio value="option3" isDisabled>
    <Radio.Control>
      <Radio.Indicator />
    </Radio.Control>
    <Radio.Content>
      <Label>Option 3 (Disabled)</Label>
    </Radio.Content>
  </Radio>
</RadioGroup>

ToggleButton

import { ToggleButton } from "@heroui/react";

// Variants: "default" | "ghost"
// Sizes: "sm" | "md" | "lg"
<ToggleButton size="md" variant="default">Toggle</ToggleButton>
<ToggleButton size="sm" variant="ghost">Ghost</ToggleButton>

ToggleButtonGroup

import { ToggleButton, ToggleButtonGroup } from "@heroui/react";

// Single selection
<ToggleButtonGroup selectionMode="single" defaultSelectedKeys={["bold"]}>
  <ToggleButton id="bold">B</ToggleButton>
  <ToggleButton id="italic">I</ToggleButton>
  <ToggleButton id="underline">U</ToggleButton>
</ToggleButtonGroup>

// Multiple selection, detached style
<ToggleButtonGroup selectionMode="multiple" isDetached>
  <ToggleButton id="a">A</ToggleButton>
  <ToggleButton id="b">B</ToggleButton>
  <ToggleButton id="c">C</ToggleButton>
</ToggleButtonGroup>

Tag + TagGroup

Tag MUST be inside TagGroup.List:

import { Tag, TagGroup, Label } from "@heroui/react";

// Sizes: "sm" | "md" | "lg"
// Variants: "default" | "surface"
<TagGroup selectionMode="multiple">
  <Label>Select tags</Label>
  <TagGroup.List>
    <Tag id="tag1" size="sm">Small</Tag>
    <Tag id="tag2" size="md">Medium</Tag>
    <Tag id="tag3" size="lg">Large</Tag>
  </TagGroup.List>
</TagGroup>

// Removable
<TagGroup onRemove={(keys) => console.log(keys)}>
  <Label>Removable tags</Label>
  <TagGroup.List>
    <Tag id="r1">
      Tag 1
      <Tag.RemoveButton />
    </Tag>
    <Tag id="r2">
      Tag 2
      <Tag.RemoveButton />
    </Tag>
  </TagGroup.List>
</TagGroup>

Chip

import { Chip } from "@heroui/react";

// Variants: "primary" | "secondary" | "tertiary"
// Sizes: "sm" | "md" | "lg"
// Colors: "accent" | "success" | "warning" | "danger"
<Chip size="md" variant="primary" color="accent"><Chip.Label>Accent</Chip.Label></Chip>
<Chip variant="secondary" color="success"><Chip.Label>Success</Chip.Label></Chip>
<Chip variant="tertiary" color="warning"><Chip.Label>Warning</Chip.Label></Chip>

Modal

Modal.Trigger renders <div>, so <Button> inside is safe.

import { Modal, Button } from "@heroui/react";

// Container sizes: "sm" | "md" | "lg"
<Modal>
  <Modal.Trigger>
    <Button variant="outline">Open Modal</Button>
  </Modal.Trigger>
  <Modal.Backdrop />
  <Modal.Container size="md">
    <Modal.Dialog>
      <Modal.Header>
        <Modal.Heading>Title</Modal.Heading>
        <Modal.CloseTrigger />
      </Modal.Header>
      <Modal.Body>
        <p>Modal content here.</p>
      </Modal.Body>
      <Modal.Footer>
        <Button variant="ghost">Cancel</Button>
        <Button variant="primary">Confirm</Button>
      </Modal.Footer>
    </Modal.Dialog>
  </Modal.Container>
</Modal>

AlertDialog

AlertDialog.Trigger renders <div>, so <Button> inside is safe.

import { AlertDialog, Button } from "@heroui/react";

// AlertDialog.Icon status: "danger" | "success" | "warning"
<AlertDialog>
  <AlertDialog.Trigger>
    <Button variant="danger">Delete</Button>
  </AlertDialog.Trigger>
  <AlertDialog.Backdrop />
  <AlertDialog.Container size="sm">
    <AlertDialog.Dialog>
      <AlertDialog.Header>
        <AlertDialog.Icon status="danger" />
        <AlertDialog.Heading>Delete Item?</AlertDialog.Heading>
      </AlertDialog.Header>
      <AlertDialog.Body>
        This action cannot be undone. Are you sure?
      </AlertDialog.Body>
      <AlertDialog.Footer>
        <Button variant="ghost">Cancel</Button>
        <Button variant="danger">Delete</Button>
      </AlertDialog.Footer>
    </AlertDialog.Dialog>
  </AlertDialog.Container>
</AlertDialog>

Dropdown

Dropdown.Trigger renders <div>, so <Button> inside is safe.

import { Dropdown, Button } from "@heroui/react";

<Dropdown>
  <Dropdown.Trigger>
    <Button variant="outline">Open Menu</Button>
  </Dropdown.Trigger>
  <Dropdown.Popover>
    <Dropdown.Menu onAction={(key) => console.log(key)}>
      <Dropdown.Item id="edit">Edit</Dropdown.Item>
      <Dropdown.Item id="duplicate">Duplicate</Dropdown.Item>
      <Dropdown.Item id="delete">Delete</Dropdown.Item>
    </Dropdown.Menu>
  </Dropdown.Popover>
</Dropdown>

Tooltip

Tooltip.Trigger IS a <button> — use <span> as child, not <Button>.

import { Tooltip } from "@heroui/react";

<Tooltip>
  <Tooltip.Trigger>
    <span className="inline-block cursor-pointer rounded-lg border border-gray-300 px-4 py-2 text-sm">
      Hover me
    </span>
  </Tooltip.Trigger>
  <Tooltip.Content>Tooltip text</Tooltip.Content>
</Tooltip>

// With arrow
<Tooltip>
  <Tooltip.Trigger>
    <span>Hover</span>
  </Tooltip.Trigger>
  <Tooltip.Content showArrow>With arrow</Tooltip.Content>
</Tooltip>

Toast

Add <Toast.Provider /> once at app root, then trigger from anywhere:

import { Toast, Button } from "@heroui/react";

// In your app root: <Toast.Provider />

// Trigger toasts:
<Button onPress={() => Toast.toast("Default message")}>Toast</Button>
<Button onPress={() => Toast.toast.success("Done!")}>Success</Button>
<Button onPress={() => Toast.toast.danger("Error!")}>Danger</Button>
<Button onPress={() => Toast.toast.warning("Warning!")}>Warning</Button>

Tabs

import { Tabs } from "@heroui/react";

<Tabs variant="primary">
  <Tabs.List>
    <Tabs.Tab id="tab1">General</Tabs.Tab>
    <Tabs.Tab id="tab2">Settings</Tabs.Tab>
    <Tabs.Tab id="tab3">Profile</Tabs.Tab>
  </Tabs.List>
  <Tabs.Panel id="tab1">
    <div className="p-4 border border-gray-200 rounded-lg mt-2">
      General content
    </div>
  </Tabs.Panel>
  <Tabs.Panel id="tab2">
    <div className="p-4 border border-gray-200 rounded-lg mt-2">
      Settings content
    </div>
  </Tabs.Panel>
  <Tabs.Panel id="tab3">
    <div className="p-4 border border-gray-200 rounded-lg mt-2">
      Profile content
    </div>
  </Tabs.Panel>
</Tabs>

Pagination

import { Pagination } from "@heroui/react";

// Sizes: "sm" | "md" | "lg"
<Pagination size="md">
  <Pagination.Content>
    <Pagination.Item>
      <Pagination.Previous>
        <Pagination.PreviousIcon />
      </Pagination.Previous>
    </Pagination.Item>
    <Pagination.Item>
      <Pagination.Link isActive>1</Pagination.Link>
    </Pagination.Item>
    <Pagination.Item>
      <Pagination.Link>2</Pagination.Link>
    </Pagination.Item>
    <Pagination.Item>
      <Pagination.Ellipsis />
    </Pagination.Item>
    <Pagination.Item>
      <Pagination.Link>10</Pagination.Link>
    </Pagination.Item>
    <Pagination.Item>
      <Pagination.Next>
        <Pagination.NextIcon />
      </Pagination.Next>
    </Pagination.Item>
  </Pagination.Content>
</Pagination>

Slider

import { Slider, Label } from "@heroui/react";

// Single value
<Slider defaultValue={50} minValue={0} maxValue={100}>
  <div className="flex justify-between">
    <Label>Volume</Label>
    <Slider.Output />
  </div>
  <Slider.Track>
    <Slider.Fill />
    <Slider.Thumb />
  </Slider.Track>
</Slider>

// Range (two thumbs)
<Slider defaultValue={[20, 80]} minValue={0} maxValue={100}>
  <div className="flex justify-between">
    <Label>Range</Label>
    <Slider.Output />
  </div>
  <Slider.Track>
    <Slider.Fill />
    <Slider.Thumb />
    <Slider.Thumb />
  </Slider.Track>
</Slider>

Alert

import { Alert, Button } from "@heroui/react";

// Status: "default" | "accent" | "success" | "warning" | "danger"
<Alert status="success">
  <Alert.Indicator />
  <Alert.Content>
    <Alert.Title>Success</Alert.Title>
    <Alert.Description>Your action completed.</Alert.Description>
  </Alert.Content>
</Alert>

// With action button
<Alert status="warning">
  <Alert.Indicator />
  <Alert.Content>
    <Alert.Title>Warning</Alert.Title>
    <Alert.Description>Please review.</Alert.Description>
  </Alert.Content>
  <Button size="sm" variant="outline">Action</Button>
</Alert>

CloseButton

import { CloseButton } from "@heroui/react";

<CloseButton variant="default" onPress={() => {}} />

Full App Example

import { Toast } from "@heroui/react";

function App() {
  return (
    <div className="min-h-screen bg-background text-foreground p-8">
      <div className="mx-auto max-w-3xl space-y-12">
        {/* your components here */}
      </div>
      <Toast.Provider />
    </div>
  );
}

License

MIT