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 🙏

© 2025 – Pkg Stats / Ryan Hefner

compoui

v2.0.1

Published

A modern, customizable React component library featuring seamless Tailwind CSS integration, interactive UI elements, and optimized for developer productivity.

Readme

Compoui

Compoui is a React UI components library built with Tailwind CSS. It provides reusable and customizable components for authentication forms, buttons, and sidebars.

📦 Installation

Install the package using npm:

npm install compoui

🎨 Tailwind CSS Setup

If you are using Tailwind CSS, add the following to your tailwind.config.js file:

module.exports = {
  content: ["./node_modules/compoui/dist/**/*.{js,ts,jsx,tsx}"],
  theme: {
    extend: {},
  },
  plugins: [],
};

❌ Non-Tailwind Users

If you are not using Tailwind CSS, import the default styles into your project:

import "<path-to-your-node_modules>/compoui/dist/style.css";

🚀 Usage

🔐 AuthForm Component

import React from "react";
import { AuthForm } from "compoui";
import { User, Phone } from "lucide-react"; // Example icons

const MyAuthForm = () => {
  const handleSubmit = (data: Record<string, string>) => {
    console.log("Form submitted:", data);
  };

  return (
    <AuthForm
      onSubmit={handleSubmit}
      title="Sign In"
      buttonText="Login"
      customFields={[
        {
          name: "username",
          type: "text",
          placeholder: "Enter your username",
          icon: <User />,
          isRequired: true,
        },
        {
          name: "phone",
          type: "tel",
          placeholder: "Enter your phone number",
          icon: <Phone />,
          isRequired: false,
        },
      ]}
    />
  );
};

export default MyAuthForm;

Props Table

| Prop Name | Type | Description | Required? | | --------------------- | ---------------------------------------------------------------------------------------------------- | ------------------------------------ | --------- | | onSubmit | (data: Record<string, string>) => void | Function to handle form submission | ❌ No | | loading | boolean | Displays a loading state | ❌ No | | error | string | Displays an error message | ❌ No | | title | string | Sets the form title | ❌ No | | emailPlaceholder | string | Placeholder for email input | ❌ No | | passwordPlaceholder | string | Placeholder for password input | ❌ No | | buttonText | string | Text for submit button | ❌ No | | loadingText | string | Text when button is in loading state | ❌ No | | customFields | Array<{name: string, type: string, placeholder: string, icon?: JSX.Element, isRequired?: boolean}> | Array of custom input fields | ❌ No | | formStyle | string | Custom class for form styling | ❌ No | | buttonStyle | string | Custom class for button styling | ❌ No | | iconColor | string | Color for icons in custom fields | ❌ No |


🔘 Button Component

import React from "react";
import Button from "./Button";
import { ArrowRight, User } from "lucide-react";

export default function App() {
  return (
    <div className="p-6 space-y-4">
      <Button color="purple" size="md" leftIcon={User}>
        Profile
      </Button>
      <Button color="green" size="lg" rightIcon={ArrowRight}>
        Continue
      </Button>
    </div>
  );
}

Props Table

| Prop Name | Type | Description | Required? | | ----------- | --------------------------------------------------------- | ---------------------------------- | --------- | | size | "sm" | "md" | "lg" | Sets button size | ❌ No | | color | "blue" | "red" | "green" | "black" | "etc" | Button color | ❌ No | | onClick | () => void | Function called on click | ❌ No | | leftIcon | LucideIcon | Icon component to display on left | ❌ No | | rightIcon | LucideIcon | Icon component to display on right | ❌ No |


📂 Sidebar Component

import { SideBar } from "compoui";
import { Home, Table, Gift, User } from "lucide-react"; // Icons

const MySidebar = () => {
  return (
    <SideBar
      sections={[
        {
          title: "Home",
          path: "/", // Navigates to Home
          icon: <Home />,
        },
        {
          title: "Profile",
          onClick: () => alert("Profile clicked!"), // Only executes function
          icon: <User />,
        },
        {
          title: "Dashboard",
          path: "/dashboard",
          onClick: () => console.log("Navigating to dashboard..."), // Both navigate & run function
          icon: <Table />,
        },
        {
          title: "Gifts",
          icon: <Gift />, // No action, just display the title and the icon
        },
      ]}
    />
  );
};

export default MySidebar;

Props Table

| Prop Name | Type | Description | Required? | | ------------------- | --------------------------------------------------------------------------------- | ---------------------------- | --------- | | sections | Array<{title: string, path?: string, icon?: JSX.Element, onClick?: () => void}> | List of sidebar sections | ✅ Yes | | sideStyle | string | Custom sidebar styling | ❌ No | | toggleButtonStyle | string | Custom toggle button styling | ❌ No | | navStyle | string | Custom nav styling | ❌ No |


📌 Layout Component

import React from "react";
import { Layout } from "compoui";
import { Home, Search, User, Bell } from "lucide-react";

const MyLayout = () => {
  return (
    <Layout
      title="Dashboard"
      layoutColor="blue"
      isSearchVisible={true}
      searchTitle="Search..."
      onSearchChange={(query) => console.log("Search query:", query)}
      sections={[
        { title: "Home", path: "/", icon: <Home /> },
        { title: "Profile", path: "/profile", icon: <User /> },
      ]}
      icons={[
        {
          title: "Notification",
          icon: <Bell />,
          onClick: () => alert("Notification!"),
        },
      ]}
    >
      <div className="bg-white rounded-lg shadow-sm p-6 transition-all duration-300 hover:shadow-md">
        <h1 className="text-2xl font-bold mb-4 text-gray-800">
          Welcome to Dashboard
        </h1>
        <p className="text-gray-600">
          This is your main content area. The sidebar can be toggled on any
          screen size.
        </p>
      </div>
    </Layout>
  );
};

export default MyLayout;

Props Table

| Prop Name | Type | Description | Required? | | ----------------- | ------------------------------------------------------------------------------------ | ---------------------------------- | --------- | | sections | Array<{ title: string, path?: string, icon?: JSX.Element, onClick?: () => void }> | Sidebar sections | ✅ Yes | | icons | Array<{ title?: string, path?: string, icon?: JSX.Element, onClick?: () => void }> | Action icons | ❌ No | | isIconsVisible | boolean | Shows/hides action icons | ❌ No | | isSearchVisible | boolean | Shows search input | ❌ No | | children | React.ReactNode | Page content | ✅ Yes | | title | string | Layout title | ❌ No | | layoutColor | string | Layout background color | ❌ No | | searchTitle | string | Placeholder for search input | ❌ No | | onSearchChange | (query: string) => void | Callback function for search input | ❌ No |



🔔 Alert Component

Example

import React from "react";
import Alert from "./Alert";

export default function App() {
  return (
    <div className="p-6 space-y-4">
      <Alert message="Info message" type="info" />
      <Alert message="Success! Your action worked." type="success" duration={3000} />
      <Alert
        message="Something went wrong!"
        type="error"
        onClose={() => console.log("Alert closed")}
      />
    </div>
  );
}

Props

| Prop | Type | Default | Description | | ----------- | --------------------------------------------- | -------- | ---------------------------------------- | | message | React.ReactNode | — | The message to display inside the alert. | | type | "success" \| "error" \| "warning" \| "info" | "info" | Defines the alert style. | | duration | number | — | Auto-dismiss time (ms). | | onClose | () => void | — | Callback when alert is closed. | | className | string | — | Additional TailwindCSS classes. |


🃏 Card Component

Example

import React from "react";
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "./Card";
import Button from "./Button";

export default function App() {
  return (
    <Card className="max-w-sm mx-auto">
      <CardHeader>
        <CardTitle>Product Title</CardTitle>
        <CardDescription>Brief description goes here</CardDescription>
      </CardHeader>
      <CardContent>
        <p>This is the card content. You can put anything inside: text, images, or forms.</p>
      </CardContent>
      <CardFooter>
        <Button size="sm" color="gray">Cancel</Button>
        <Button size="sm" color="blue">Confirm</Button>
      </CardFooter>
    </Card>
  );
}

Props

| Component | Prop | Type | Default | Description | | ----------------- | ----------- | ----------- | ------- | ------------------------------ | | Card | children | ReactNode | — | Content inside the card. | | | className | string | — | Extra TailwindCSS classes. | | CardHeader | children | ReactNode | — | Header content. | | CardTitle | children | ReactNode | — | Card title text. | | CardDescription | children | ReactNode | — | Small description text. | | CardContent | children | ReactNode | — | Main content body. | | CardFooter | children | ReactNode | — | Footer actions (e.g. buttons). |


⬇️ Dropdown Component

Example

import React from "react";
import Dropdown from "./Dropdown";
import { User, Settings } from "lucide-react";

export default function App() {
  return (
    <div className="p-6">
      <Dropdown
        options={[
          { label: "Profile", value: "profile", icon: <User size={16} /> },
          { label: "Settings", value: "settings", icon: <Settings size={16} /> },
        ]}
        placeholder="Choose an option"
        onChange={(val) => console.log("Selected:", val)}
      />
    </div>
  );
}

Props

| Prop | Type | Default | Description | | -------------- | ------------------------------------------------------ | -------------------- | ----------------------------------------- | | options | { label: string; value: string; icon?: ReactNode }[] | — | Dropdown items. | | placeholder | string | "Select an option" | Text shown when nothing selected. | | searchable | boolean | true | Enable search input inside dropdown. | | notFoundText | string | "No results found" | Text shown when search yields no results. | | onChange | (value: string) => void | — | Callback when option is selected. | | className | string | — | Extra TailwindCSS classes. |


🪟 Modal Component

Example

import React, { useState } from "react";
import Modal from "./Modal";

export default function App() {
  const [open, setOpen] = useState(false);

  return (
    <div className="p-6">
      <button
        onClick={() => setOpen(true)}
        className="px-4 py-2 bg-blue-600 text-white rounded-lg"
      >
        Open Modal
      </button>

      <Modal
        isOpen={open}
        onClose={() => setOpen(false)}
        title="Delete Item"
        description="Are you sure you want to delete this item?"
        cancelText="No"
        confirmText="Yes, delete"
        confirmColor="red"
        onConfirm={() => alert("Deleted!")}
      >
        <p className="text-gray-700">This action cannot be undone.</p>
      </Modal>
    </div>
  );
}

Props

| Prop | Type | Default | Description | | ----------------- | ----------------------------------------------------------- | ----------- | ------------------------------------------- | | isOpen | boolean | — | Controls modal visibility. | | onClose | () => void | — | Called when modal is closed. | | title | string | — | Optional modal title. | | description | string | — | Optional description text. | | children | ReactNode | — | Extra content inside modal body. | | cancelText | string | "Cancel" | Label for cancel button. | | cancelColor | Color string ("blue", "red", "green", "gray", etc.) | "gray" | Cancel button color. | | onCancel | () => void | — | Called when cancel is clicked. | | confirmText | string | "Confirm" | Label for confirm button. | | confirmColor | Color string ("blue", "red", "green", "gray", etc.) | "blue" | Confirm button color. | | onConfirm | () => void | — | Called when confirm is clicked. | | showCloseButton | boolean | true | Show/hide "X" close button. | | closeOnBackdrop | boolean | true | Allow closing modal when clicking backdrop. |


📊 ProgressBar Component

Example

import React from "react";
import ProgressBar from "./ProgressBar";

export default function App() {
  return (
    <div className="space-y-4 p-6">
      <ProgressBar value={40} label="Loading..." showLabel />
      <ProgressBar value={75} color="success" size="lg" />
      <ProgressBar value={20} max={200} color="error" />
    </div>
  );
}

Props

| Prop | Type | Default | Description | | ----------- | ---------------------------------------------------------------------------------------- | ----------- | ------------------------------------------- | | value | number | — | Current progress value. | | max | number | 100 | Maximum progress value. | | size | "xs" \| "sm" \| "md" \| "lg" \| "xl" | "md" | Height of the progress bar. | | color | "blue" \| "green" \| "red" | "blue" | Color variant. | | showLabel | boolean | false | Show percentage text. | | label | string | — | Custom label (replaces default percentage). | | className | string | — | Extra TailwindCSS classes. |


🔄 Spinner

Example

import Spinner from "./Spinner";

<Spinner size="lg" color="blue" />;

Props

| Prop | Type | Default | Description | | ----------- | -------------------------------------- | ---------------- | ------------------------------- | | size | "xs" \| "sm" \| "md" \| "lg" \| "xl" | "md" | Controls spinner size. | | color | string | "currentColor" | CSS color value for spinner. | | className | string | "" | Extra Tailwind/utility classes. |


🗂 Tabs

Example

import Tabs from "./Tabs";

const tabs = [
  { label: "Home", value: "home", content: <div>Welcome!</div> },
  { label: "Profile", value: "profile", content: <div>Your profile</div> },
];

<Tabs tabs={tabs} defaultValue="home" />;

Props

| Prop | Type | Default | Description | | -------------- | -------- | --------------- | ------------------------------------- | | tabs | Tab[] | required | Array of { label, value, content }. | | defaultValue | string | tabs[0].value | Initial active tab. | | className | string | "" | Extra Tailwind/utility classes. |


💬 Tooltip

Example

import Tooltip from "./Tooltip";

<Tooltip content="This is a tooltip" position="top">
  <button className="px-4 py-2 bg-blue-600 text-white rounded">
    Hover me
  </button>
</Tooltip>;

Props

| Prop | Type | Default | Description | | ----------- | ---------------------------------------- | ------------ | ----------------------------------- | | children | ReactNode | required | Element to wrap. | | content | ReactNode | required | Tooltip text/content. | | position | "top" \| "bottom" \| "left" \| "right" | "top" | Tooltip placement. | | delay | number | 200 | Delay in ms before showing tooltip. | | className | string | "" | Extra Tailwind/utility classes. |


Perfect 👍 Since you want more detailed documentation for the Table component, we can expand the README.md with full details of TableProps, TableColumn, TableAction, TableTranslations, and TableColors.

Here’s the improved README.md section for Table:


📊 Table

A powerful, feature-rich data table with: ✅ Sorting • ✅ Searching • ✅ Pagination • ✅ Row Actions • ✅ i18n Translations • ✅ Loading state


🔹 Usage Example

import Table from "./Table";
import { Edit, Trash } from "lucide-react";

type User = { id: number; name: string; email: string };

const users: User[] = [
  { id: 1, name: "Alice", email: "[email protected]" },
  { id: 2, name: "Bob", email: "[email protected]" },
];

const columns = [
  { key: "name", label: "Name", sortable: true },
  { key: "email", label: "Email" },
];

const actions = [
  {
    label: "Edit",
    icon: <Edit size={16} />,
    onClick: (row: User) => console.log("Edit", row),
  },
  {
    label: "Delete",
    icon: <Trash size={16} />,
    onClick: (row: User) => console.log("Delete", row),
    color: "red",
  },
];

<Table
  title="Users"
  data={users}
  columns={columns}
  actions={actions}
  pageSize={5}
  onCreate={() => console.log("Create new user")}
  onRefresh={() => console.log("Refresh data")}
  onExport={() => console.log("Export")}
  onImport={() => console.log("Import")}
/>;

🔹 Table Props

| Prop | Type | Default | Description | | ----------------------- | ---------------------------- | ----------------- | -------------------------------------- | | data | T[] | required | Array of rows to display. | | columns | TableColumn<T>[] | required | Column definitions (see below). | | actions | TableAction<T>[] | [] | Action buttons per row. | | pageSize | number | 5 | Rows per page. | | onRowClick | (row: T) => void | undefined | Called when a row is clicked. | | className | string | "" | Extra Tailwind/utility classes. | | title | string | "Data Table" | Table title in the header. | | loading | boolean | false | Show loading spinner overlay. | | head | boolean | true | Show header (title, search, controls). | | onImport | () => void | undefined | Callback for import button. | | onExport | () => void | undefined | Callback for export button. | | onRefresh | () => void | undefined | Callback for refresh button. | | onCreate | () => void | undefined | Callback for create button. | | createButtonColor | keyof TableColors | "blue" | Color for create button. | | importButtonColor | keyof TableColors | "red" | Color for import button. | | exportButtonColor | keyof TableColors | "orange" | Color for export button. | | refreshButtonColor | keyof TableColors | "black" | Color for refresh button. | | paginationButtonColor | keyof TableColors | "white" | Color for active pagination button. | | translations | Partial<TableTranslations> | defaults provided | Override built-in i18n translations. |


🔹 TableColumn

export interface TableColumn<T> {
  key: keyof T;              // Data key
  label: string;             // Column header label
  sortable?: boolean;        // Enables sorting
  width?: string;            // Optional column width
}

Example:

const columns = [
  { key: "name", label: "Name", sortable: true },
  { key: "email", label: "Email" },
];

🔹 TableAction

export interface TableAction<T> {
  label: string;                       // Action button text
  icon: React.ReactNode;               // Icon to display
  onClick: (row: T) => void;           // Callback when clicked
  color?: keyof TableColors;           // Optional color
}

Example:

const actions = [
  {
    label: "Edit",
    icon: <Edit size={16} />,
    onClick: (row) => console.log("Edit", row),
  },
  {
    label: "Delete",
    icon: <Trash size={16} />,
    onClick: (row) => console.log("Delete", row),
    color: "red",
  },
];

🔹 TableTranslations

Supports full i18n customization:

export interface TableTranslations {
  title: string;
  create: string;
  import: string;
  export: string;
  refresh: string;
  rowsPerPage: string;
  total: string;
  first: string;
  last: string;
  searchPlaceholder: string;
  loading: string;
  noResults: string;
  showing: (start: number, end: number, total: number) => string;
}

Default:

const defaultTranslations = {
  title: "Data Table",
  create: "Create",
  import: "Import",
  export: "Export",
  refresh: "Refresh",
  rowsPerPage: "Rows per page:",
  total: "total entries",
  first: "First",
  last: "Last",
  searchPlaceholder: "Search across all columns...",
  loading: "Loading...",
  noResults: "No results found",
  showing: (start, end, total) =>
    `Showing ${start} to ${end} of ${total} results`,
};

| All animations are full-screen, responsive, and optimized for performance.

Available Colors

blue, red, green, yellow, gray, indigo, purple, pink, orange, teal, cyan, lime, emerald, fuchsia, rose, slate, zinc, neutral, stone, black, white


🎨 Customization

Some components allows style customization through props. You can override default styles using:

  • Custom Tailwind classes
  • Bootstrap classes
  • Your own CSS styles

Example with Bootstrap:

<AuthForm formStyle="form-control" buttonStyle="btn btn-primary" />

Example with CSS:

<AuthForm formStyle="my-custom-form" buttonStyle="my-custom-button" />

💡 Features

Fully customizable
Reusable components
Supports custom form fields
Lightweight & easy to use


License

This project is licensed under the MIT License. See the LICENSE file for details.


🚀 Happy coding! 🎉