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

@ezyren/oppr_ui

v0.2.6

Published

Reusable UI components for Oppr

Readme

@ezyren/oppr_ui

Reusable UI components for Oppr.

📜 Table of Contents

Installation

npm install @ezyren/oppr_ui
or
yarn add @ezyren/oppr_ui

Usage

Avatar

import { Avatar } from "@ezyren/oppr_ui";

<Avatar src="https://randomuser.me/api/portraits/men/32.jpg" size="small" />
<Avatar src="https://randomuser.me/api/portraits/women/44.jpg" size="medium" />
<Avatar src="https://randomuser.me/api/portraits/men/56.jpg" size="large" />
<Avatar size="large" /> {/* Default avatar without image */}

BreadCrumbs

import { Breadcrumbs } from "@ezyren/oppr_ui";

const breadcrumbItems = [
    { label: "Home", href: "/" },
    { label: "Components", href: "/components" },
    { label: "Breadcrumbs" },
  ];

return <Breadcrumbs items={breadcrumbItems} />;

Button

import { Button } from "@ezyren/oppr_ui";
return <Button>Click Me</Button>;

Card

import { Card } from "@ezyren/oppr_ui";

return <Card title="Card Title" description="This is a sample card description." />;

Checkbox

import { Checkbox } from "@ezyren/oppr_ui";

function MyComponent() {
  const [isChecked, setIsChecked] = useState(false);

  return (
    <div>
      <Checkbox label="Subscribe to newsletter" checked={isChecked} onChange={setIsChecked} />
      {isChecked && <p className="text-green-600">Subscribed!</p>}
    </div>
  );
}

Dialog

import { Dialog} from "@ezyren/oppr_ui";

function MyComponent() {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <>
      <Button onClick={() => setIsOpen(true)}>Open Dialog</Button>
      <Dialog isOpen={isOpen} onClose={() => setIsOpen(false)} title="Example Dialog">
        <p>This is a sample dialog with some content.</p>
      </Dialog>
    </>
  );
}

Dropdown

import { Dropdown } from "@ezyren/oppr_ui";

function MyComponent() {
  const [selectedOption, setSelectedOption] = useState<string | null>(null);

  const options = [
    { label: "Option 1", value: "option1" },
    { label: "Option 2", value: "option2" },
    { label: "Option 3", value: "option3" },
  ];

  return (
    <>
      <Dropdown 
        label="Select Option" 
        options={options} 
        onSelect={(value) => setSelectedOption(value)} 
      />
      {selectedOption && (
        <p className="mt-4 text-gray-700">
          Selected Option: <span className="font-semibold">{selectedOption}</span>
        </p>
      )}
    </>
  );
}

Header

import { Header } from "@ezyren/oppr_ui";
<Header
      logoSrc="/images/opprlogo.svg"
      links={[
        { href: "/button", label: "Button" },
        { href: "/card", label: "Card" },
        { href: "/tooltip", label: "Tooltip" },
      ]}
    />

Input

import { Input } from "@ezyren/oppr_ui";

function MyComponent() {
  const [inputValue, setInputValue] = useState("");

  return (
    <Input
      label="Name"
      placeholder="Enter your name"
      value={inputValue}
      onChange={(e) => setInputValue(e.target.value)}
    />
  );
}

Logo

import { Logo } from "@ezyren/oppr_ui";
function CustomLogo() {
  return <Logo src="/custom-logo.png" width={150} height={50} />;
}

Searchbar

import { SearchBar } from "@ezyren/oppr_ui";

function MyComponent() {
  const handleSearch = (query: string) => {
    console.log("Search query:", query);
  };

  return <SearchBar placeholder="Search..." onSearch={handleSearch} />;
}

Sidebar

import { Sidebar } from "@ezyren/oppr_ui";

function MyComponent() {
  return (
    <Sidebar
      links={[
        { href: "/button", label: "Button" },
        { href: "/card", label: "Card" },
        { href: "/tooltip", label: "Tooltip" }
      ]}
      logoSrc="/images/opprlogo.svg"
    />
  );
}

Tables

import { Table } from "@ezyren/oppr_ui";

function TableExample() {
  const columns = ["Product", "Price", "Stock"];
  const data = [
    { Product: "Laptop", Price: "$1000", Stock: "Available" },
    { Product: "Smartphone", Price: "$600", Stock: "Out of Stock" },
    { Product: "Tablet", Price: "$400", Stock: "Available" },
  ];

  return <Table columns={columns} data={data} />;
}

Tabs

import { Tabs } from "@ezyren/oppr_ui";
function MyComponent() {
  const tabsData = [
    { label: "Tab 1", content: <p>This is the content for Tab 1.</p> },
    { label: "Tab 2", content: <p>This is the content for Tab 2.</p> },
    { label: "Tab 3", content: <p>This is the content for Tab 3.</p> },
  ];

  return <Tabs tabs={tabsData} />;
}

Textarea

import { TextArea } from "@ezyren/oppr_ui";
function TextAreaValidation() {
  const [message, setMessage] = useState("");
  const [error, setError] = useState("");

  const handleChange = (e) => {
    setMessage(e.target.value);
    if (e.target.value.length < 10) {
      setError("Message must be at least 10 characters.");
    } else {
      setError("");
    }
  };

  return (
    <TextArea
      label="Your Message"
      placeholder="Type at least 10 characters..."
      value={message}
      onChange={handleChange}
      error={error}
    />
  );
}

Theme

import { ThemeToggle } from "@ezyren/oppr_ui";
function MyComponent() {
  return (
    <div className="flex justify-center items-center h-screen">
      <ThemeToggle />
    </div>
  );
}

Tooltip

import { Tooltip } from "@ezyren/oppr_ui";
function MyComponent() {
  return (
    <div className="flex gap-6">
      <Tooltip text="Tooltip on Top" position="top">
        <button className="px-4 py-2 bg-blue-500 text-white rounded-md">
          Hover Me (Top)
        </button>
      </Tooltip>

      <Tooltip text="Tooltip on Bottom" position="bottom">
        <button className="px-4 py-2 bg-green-500 text-white rounded-md">
          Hover Me (Bottom)
        </button>
      </Tooltip>

      <Tooltip text="Tooltip on Left" position="left">
        <button className="px-4 py-2 bg-yellow-500 text-white rounded-md">
          Hover Me (Left)
        </button>
      </Tooltip>

      <Tooltip text="Tooltip on Right" position="right">
        <button className="px-4 py-2 bg-red-500 text-white rounded-md">
          Hover Me (Right)
        </button>
      </Tooltip>
    </div>
  );
}