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

comixa-ui

v0.1.5

Published

Comixa UI — comic-themed React components built with Tailwind CSS

Readme

Comic-themed React components built with Tailwind CSS. Hard shadows, ink borders, punchy motion.

import {
  Button,
  ComicPanel,
  Features,
  Gallery,
  PageTransition,
  toast,
  ToastProvider,
} from "comixa-ui";

Install

npm i comixa-ui

Peer deps (required in your app):

npm i react react-dom tailwindcss

Setup Tailwind

1. Use the Comixa UI preset

// tailwind.config.js
const comixaPreset = require("comixa-ui/preset");

/** @type {import('tailwindcss').Config} */
module.exports = {
  presets: [comixaPreset],
  content: [
    "./src/**/*.{js,ts,jsx,tsx}",
    // IMPORTANT: scan the package so Tailwind keeps comic utility classes
    "./node_modules/comixa-ui/dist/**/*.{js,mjs,cjs}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
};

ESM:

import comixaPreset from "comixa-ui/preset";

export default {
  presets: [comixaPreset],
  content: [
    "./src/**/*.{js,ts,jsx,tsx}",
    "./node_modules/comixa-ui/dist/**/*.{js,mjs,cjs}",
  ],
};

2. Optional fonts

<link rel="preconnect" href="https://fonts.googleapis.com" />
<link
  href="https://fonts.googleapis.com/css2?family=Bangers&family=Comic+Neue:wght@400;700&display=swap"
  rel="stylesheet"
/>

Usage

import { Button, Input, Badge } from "comixa-ui";

export function Example() {
  return (
    <div className="flex flex-col gap-4 bg-paper p-8">
      <Badge variant="yellow">New</Badge>

      <Button variant="pop" effect="pop">
        Pow!
      </Button>

      <Button variant="primary" size="lg">
        Continue
      </Button>

      <Button variant="danger" effect="shake">
        Boom
      </Button>

      <Input placeholder="Hero name..." />
      <Input state="error" placeholder="Try again..." />
      <Input variant="filled" state="success" placeholder="Looks good" />
    </div>
  );
}

Components

| Preview | Component | What it is | |:-------:|-----------|------------| | | Button | CTAs with variants, loading, icon buttons | | | Badge | Status tags and labels | | | Sticker | Tilted promo stickers | | | Input | Ink-bordered text fields | | | Select | Custom listbox dropdown | | | Checkbox | Checkable options | | | Radio | Single-choice radios | | | Toast | Notifications | | | Divider | Comic rules | | | Stats | Metric tiles | | - | Ribbon | Promo ribbons, tickets, burst labels | | - | ComicPage / ComicPanel | Comic grids and cover-grade hero panels | | - | Gallery | Grid, featured, and draggable horizontal image strips | | - | PageTransition | Route/content enter effects | | - | ComicLoader | Comic loading indicators | | - | ComicReveal | Replayable section reveal animations | | - | ComicCursor | Global cursor follower with trailing dots | | - | Features | Feature grids and comic highlight cards |

Button

| Prop | Values | Default | |------|--------|---------| | variant | pop primary danger success outline ghost | pop | | size | sm md lg | md | | loading | true / false | false | | icon | true / false — square icon-only button | false | | effect | none pop shake wiggle | none |

<Button loading>Saving…</Button>

<Button icon aria-label="Add">
  <PlusIcon />
</Button>

Input

| Prop | Values | Default | |------|--------|---------| | variant | default ghost filled | default | | inputSize | sm md lg | md | | state | default error success | default |

Badge

| Prop | Values | Default | |------|--------|---------| | variant | yellow red blue green pink orange outline ink soft | yellow | | size | sm md lg | md |

Select

Custom listbox (not a native <select>). Arrow stays on the right.

<Select
  value={hero}
  onValueChange={setHero}
  variant="pop"
  placeholder="Pick a hero"
  options={[
    { value: "zap", label: "Captain Zap" },
    { value: "boom", label: "Boom Knight" },
  ]}
/>

| Prop | Values / notes | Default | |------|--------|---------| | options | { value, label, disabled? }[] | required | | value / defaultValue | string | — | | onValueChange | (value: string) => void | — | | variant | default ghost filled pop | default | | selectSize | sm md lg | md | | state | default error success | default | | classNames | root trigger value placeholder icon list option optionActive | — |

Checkbox / Radio / Switch

| | Checkbox / Radio | Switch | |--|--|--| | variant | default primary danger success pink | same | | size prop | checkboxSize / radioSize: sm md lg | switchSize | | extras | label | checked, onCheckedChange, label |

RadioGroup wraps radios (orientation: horizontal | vertical).

Avatar

| Prop | Values | Default | |------|--------|---------| | variant | default yellow blue red green pink ink | default | | size | sm md lg xl | md | | shape | rounded square circle | rounded |

Also: src, name (initials), fallback, plus AvatarGroup.

Tooltip

<Tooltip content="Hello!" side="top" variant="pop">
  <Button>Hover me</Button>
</Tooltip>

| Prop | Values | Default | |------|--------|---------| | side | top right bottom left | top | | variant | default pop paper danger success blue | default | | delay | ms | 120 |

SpeechBubble

Classic comic dialogue bubble (no boom/explosion).

<SpeechBubble shape="speech" tone="cream" tail="bottomLeft">
  Hey! Did you see that?
</SpeechBubble>
<SpeechBubble shape="thought" tail="bottomRight">
  Hmm…
</SpeechBubble>

| Prop | Values | Default | |------|--------|---------| | shape | speech thought | speech | | tone | default pop danger blue pink cream | default | | size | sm md lg | md | | tail | bottomLeft bottomRight bottom none | bottomLeft |

ComicPage

Comic-strip grid. layout="2-1" = two panels on top, one full-width below. ComicPanel can also be used on its own as a cover-grade hero panel.

<ComicPage layout="2-1">
  <ComicPanel caption="1">Top left</ComicPanel>
  <ComicPanel caption="2">Top right</ComicPanel>
  <ComicPanel variant="alert">Wide bottom</ComicPanel>
</ComicPage>

<ComicPanel variant="hero" shadow="xl" halftone tilt hover>
  <ComicHero />
</ComicPanel>

Layouts: 1 1-1 2 2-1 1-2 2-2 3 1-1-1

Panel variants: default cream sky alert pop night hero
Panel shadow: none sm md lg xl
Panel flags: halftone, tilt, hover

SoundBadge

<SoundBadge variant="pow" />
<SoundBadge variant="boom" burst />
<SoundBadge variant="bam" word="SNAP!" />

Variants: pow bam wow boom zap crash wham bang kapow splash

Divider

variant: solid dashed zigzag dots burst — optional label

Sticker

variant colors + tilt (none left right wild) + shape (square circle ticket)

Ribbon

Comic promo labels for launch pages, tickets, corners, and bursts.

<Ribbon variant="banner">New issue</Ribbon>
<Ribbon variant="corner" tilt="right">Hot</Ribbon>
<Ribbon variant="ticket">Limited</Ribbon>
<Ribbon variant="burst">Pow</Ribbon>

| Prop | Values | Default | |------|--------|---------| | variant | banner corner ticket burst | banner | | size | sm md lg | md | | tilt | none left right | none |

Card

| Prop | Values | Default | |------|--------|---------| | variant | default cream pop panel danger speech outline | default | | padding | none sm md lg | md | | effect | none pop wiggle | none |

Parts: CardHeader, CardTitle, CardDescription, CardContent, CardFooter.

<Card variant="speech">
  <CardHeader>
    <CardTitle>Caption</CardTitle>
    <CardDescription>A comic speech bubble.</CardDescription>
  </CardHeader>
  <CardContent>Pow!</CardContent>
</Card>

Dialog (Modal)

| Prop (root) | Values | Default | |------|--------|---------| | open | boolean | required | | onOpenChange | (open: boolean) => void | required |

| Prop (DialogContent) | Values | Default | |------|--------|---------| | variant | default cream boom alert success panel | default | | size | sm md lg | md | | effect | none pop shake | pop |

const [open, setOpen] = useState(false);

<>
  <Button onClick={() => setOpen(true)}>Open</Button>
  <Dialog open={open} onOpenChange={setOpen}>
    <DialogContent variant="boom">
      <DialogHeader>
        <DialogTitle>Boom!</DialogTitle>
        <DialogDescription>Something exploded (in a good way).</DialogDescription>
      </DialogHeader>
      <DialogFooter>
        <Button onClick={() => setOpen(false)}>Got it</Button>
      </DialogFooter>
    </DialogContent>
  </Dialog>
</>

Navbar

Customizable compound navbar — every part accepts className.

| Prop (Navbar) | Values | Default | |------|--------|---------| | variant | default cream pop panel ink transparent | default | | position | static sticky fixed | static |

Parts: NavbarBrand, NavbarContent, NavbarMenu, NavbarLink, NavbarActions, NavbarItem, NavbarToggle, NavbarMobileMenu.

<Navbar variant="pop" position="sticky" className="px-6">
  <NavbarBrand href="/" className="text-ink">Comixa</NavbarBrand>
  <NavbarContent>
    <NavbarMenu className="gap-2">
      <NavbarLink href="/" active className="shadow-comic">Home</NavbarLink>
      <NavbarLink href="/docs">Docs</NavbarLink>
    </NavbarMenu>
  </NavbarContent>
  <NavbarActions className="gap-3">
    <Button size="sm">Join</Button>
    <NavbarToggle className="bg-comic-yellow" />
  </NavbarActions>
  <NavbarMobileMenu className="bg-paper-cream">
    <NavbarLink href="/">Home</NavbarLink>
    <NavbarLink href="/docs">Docs</NavbarLink>
  </NavbarMobileMenu>
</Navbar>

Toast

Wrap your app with ToastProvider, then call toast() anywhere.

<ToastProvider
  position="bottom-right"
  duration={3500}
  closable
  viewportClassName="p-2"
>
  <App />
</ToastProvider>

toast({ title: "Pow!", description: "Saved.", variant: "success" });
toast.success("Done");
toast.danger("Oops", "Try again");

// Duration (ms). 0 or Infinity = stay until dismissed
toast({ title: "Quick", duration: 1000 });
toast({ title: "Sticky", duration: 0 });

// Hide the × button
toast({ title: "No close", closable: false, duration: 3000 });

// Per-toast position (overrides provider default)
toast({ title: "Top!", position: "top-center" });
toast.info("Hi", "From the corner", { position: "top-left", duration: 5000 });

// Custom classes per slot
toast({
  title: "Styled",
  className: "max-w-sm",
  classNames: {
    root: "rounded-2xl",
    title: "text-comic-red",
    description: "opacity-80",
    close: "bg-comic-yellow",
  },
});

| | | |--|--| | Variant | default pop success danger info | | Position | top-left top-right top-center bottom-left bottom-right bottom-center | | duration | ms number — 0 / Infinity keeps toast open | | closable | true / false — show/hide × button |

Testimonials / Features / Pricing / FAQ / Stats

Compound marketing sections:

import {
  Features,
  Feature,
  Testimonials,
  Testimonial,
  Pricing,
  PricingTier,
  FAQ,
  FAQItem,
  Stats,
  Stat,
  Button,
  Avatar,
} from "comixa-ui";

<Testimonials columns={3}>
  <Testimonial
    quote="Pow!"
    author="Captain Zap"
    role="Hero"
    rating={5}
    avatar={<Avatar name="CZ" size="sm" shape="circle" />}
  />
</Testimonials>

<Features columns={3}>
  <Feature
    variant="yellow"
    title="Hero panels"
    description="Cover-grade panels with halftone and hard shadows."
  />
  <Feature
    variant="blue"
    title="Composable"
    description="Stack sections without leaving the comic visual language."
  />
</Features>

<Pricing>
  <PricingTier
    name="Hero"
    price="$19"
    period="mo"
    featured
    badge="Popular"
    features={["All components"]}
    cta={<Button className="w-full">Start</Button>}
  />
</Pricing>

<FAQ type="single" defaultValue="a">
  <FAQItem value="a" title="What is Comixa?">
    Comic React UI with Tailwind.
  </FAQItem>
</FAQ>

<Stats columns={4}>
  <Stat value="12k+" label="Heroes" animate />
</Stats>

Feature variants: default yellow blue burst outline
Feature alignment: left center
Features columns: 1 2 3 4

Gallery

Image galleries for covers, portfolio work, products, and proof sections.

const items = [
  {
    src: "/covers/neon.jpg",
    alt: "Neon skyline",
    title: "Neon Alley",
    description: "Campaign cover.",
    badge: "New",
  },
  {
    src: "/covers/road.jpg",
    alt: "Desert road",
    title: "Road Cut",
    badge: "Hot",
  },
];

<Gallery variant="featured" items={items} />
<Gallery variant="strip" items={items} />

| Prop | Values / notes | Default | |------|--------|---------| | variant | grid strip featured | grid | | items | { src, alt, title?, description?, badge? }[] | required | | framed | true / false | true |

variant="featured" makes the first image the featured card.
variant="strip" supports horizontal wheel scrolling and mouse drag scrolling.

PageTransition

Replayable content/page enter transitions.

<PageTransition variant="panel-swipe" transitionKey={routeId}>
  <YourPage />
</PageTransition>

Variants: panel-swipe burst flip speed-lines
Props: transitionKey, duration, easing, padding

ComicLoader

<ComicLoader variant="dots" />
<ComicLoader variant="burst" label="Zap" tone="red" />

Variants: dots burst panel speech
Tones: yellow blue red green pink

ComicReveal

Replayable section reveals.

<ComicReveal variant="panel-wipe" revealKey={id}>
  <Card>Fresh panel</Card>
</ComicReveal>

Variants: pop slide-up panel-wipe spotlight
Props: revealKey, delay, duration

ComicCursor

Global cursor follower with trailing dots. Mount it once on a page.

<ComicCursor variant="dot" trailCount={6} />

<button data-comixa-cursor-zone>
  Hovering this grows and fades the follower
</button>

Variants: dot ring spark
Props: enabled, hideNativeCursor, size, trailCount

Animated text

repeat controls how many times the animation plays (Infinity = forever, default).

import { LetterReveal, Typewriter, ComicText, Highlight } from "comixa-ui";

<LetterReveal repeat={Infinity}>Boom Town</LetterReveal>
<LetterReveal repeat={3}>Three times</LetterReveal>

<Typewriter speed={40} repeat={Infinity}>Typing with ink…</Typewriter>
<Typewriter repeat={1}>Once only</Typewriter>

<ComicText effect="pop" tilt="left" repeat={Infinity}>Kapow!</ComicText>
<p>
  Ship <Highlight tone="yellow" repeat={Infinity}>faster</Highlight> pages.
</p>

Background

import {
  DotsBackground,
  GridBackground,
  ExplosionBackground,
  ComicPaperBackground,
} from "comixa-ui";

<DotsBackground className="rounded-xl p-8" intensity="md">
  Hero copy
</DotsBackground>

Variants: dots grid lines pattern explosion comic-paper
Tone: paper cream yellow ink · Intensity: sm md lg

Design tokens (via preset)

  • Colors: ink, paper, comic.yellow|red|blue|green|pink|orange
  • Shadows: shadow-comic, shadow-comic-sm, shadow-comic-lg
  • Animations: animate-comic-pop, animate-comic-shake, animate-comic-wiggle, animate-comic-dialog-in, animate-comic-overlay-in, animate-comic-letter-in, animate-comic-caret-blink, animate-comic-highlight-wipe
  • Fonts: font-comic, font-body