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

meemaw

v1.0.2

Published

Elegant, declarative React utility components for common UI patterns

Readme

Meemaw

Elegant, declarative React utility components for common UI patterns

InstallationComponentsExamplesDocumentation


Why Meemaw?

Stop writing repetitive JSX patterns. Meemaw provides a collection of lightweight, zero-dependency React components that make your code more readable and maintainable.

// Before
{
  isLoggedIn ? <Dashboard /> : <Login />;
}

// After
<Show when={isLoggedIn} fallback={<Login />}>
  <Dashboard />
</Show>;

Features

  • Zero dependencies - Only React as peer dependency
  • Tiny bundle - Less than 10KB total
  • Tree-shakeable - Import only what you need
  • TypeScript first - Full type safety out of the box
  • 100% test coverage - Thoroughly tested and reliable
  • SSR compatible - Works with Next.js, Remix, and other frameworks

Installation

npm install meemaw
yarn add meemaw
pnpm add meemaw

Components

Conditional Rendering

<Switch>, <Case>, <Default>

Clean match-case pattern for multiple conditions. No more nested ternaries.

import { Switch, Case, Default } from 'meemaw';

function OrderStatus({ status }) {
  return (
    <Switch>
      <Case when={status === 'pending'}>
        <PendingIcon /> Processing your order...
      </Case>
      <Case when={status === 'shipped'}>
        <TruckIcon /> On the way!
      </Case>
      <Case when={status === 'delivered'}>
        <CheckIcon /> Delivered
      </Case>
      <Default>
        <ErrorIcon /> Unknown status
      </Default>
    </Switch>
  );
}

<Show>

Simple conditional rendering with optional fallback.

import { Show } from 'meemaw';

// Basic usage
<Show when={isLoggedIn}>
  <UserProfile />
</Show>

// With fallback
<Show when={hasPermission} fallback={<AccessDenied />}>
  <AdminPanel />
</Show>

// Using 'if' prop (alias for 'when')
<Show if={isLoading} fallback={<Content />}>
  <Spinner />
</Show>

<Hidden>

Hide content conditionally or based on viewport breakpoints.

import { Hidden } from 'meemaw';

// Conditional hiding
<Hidden when={!isPublic}>
  <SecretContent />
</Hidden>

// Responsive hiding
<Hidden on="mobile">
  <DesktopNav />
</Hidden>

<Hidden on={['mobile', 'tablet']}>
  <DesktopOnlyFeature />
</Hidden>

Breakpoints:

  • mobile: < 768px
  • tablet: < 1024px
  • desktop: ≥ 1024px

<Loadable>

Handle async operation states with built-in loading and error UI.

import { Loadable } from 'meemaw';

function UserData() {
  const { data, loading, error } = useFetch('/api/user');

  return (
    <Loadable loading={loading} error={error}>
      <UserProfile data={data} />
    </Loadable>
  );
}

// Custom loading and error components
<Loadable
  loading={isLoading}
  error={error}
  loadingComponent={<CustomSpinner />}
  errorComponent={<ErrorAlert message={err.message} />}
>
  <Content />
</Loadable>;

Iteration

<Repeat>

Iterate arrays or repeat elements n times with clean syntax.

import { Repeat } from 'meemaw';

// Repeat n times
<Repeat times={5}>
  {(_, index) => <Star key={index} />}
</Repeat>

// Iterate over array
const users = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }];

<Repeat each={users}>
  {(user, index) => (
    <UserCard key={user.id} user={user} />
  )}
</Repeat>

// Static children (repeated as-is)
<Repeat times={3}>
  <Divider />
</Repeat>

Time-based Components

<Delayed>

Delay rendering until a condition is met or timeout expires.

import { Delayed } from 'meemaw';

// Show after 3 seconds
<Delayed till={3000}>
  <Announcement />
</Delayed>

// Show at specific date/time
<Delayed till={new Date('2025-01-01')}>
  <NewYearMessage />
</Delayed>

// Show when condition becomes true
<Delayed until={dataLoaded} fallback={<Loading />}>
  <DataView />
</Delayed>

<ShowOnce>

Display content only once with optional persistence.

import { ShowOnce } from 'meemaw';

// Show for 5 seconds then hide forever
<ShowOnce for={5000} persist>
  <WelcomeBanner />
</ShowOnce>

// Show once per session
<ShowOnce persist persistType="session">
  <NewFeatureTooltip />
</ShowOnce>

// Show once across all sessions (localStorage)
<ShowOnce persist persistKey="onboarding-v1" persistType="local">
  <OnboardingTour />
</ShowOnce>

// Show once in memory (resets on page reload)
<ShowOnce persist persistType="memory">
  <FirstTimeHint />
</ShowOnce>

Persistence types:

  • local - Persists across browser sessions (localStorage)
  • session - Persists within current session (sessionStorage)
  • memory - Persists only in memory (resets on reload)

Interaction Components

<CopyToClipboard>

Copy text to clipboard with automatic success/error handling.

import { CopyToClipboard } from 'meemaw';

// Copy specific text
<CopyToClipboard text="npm install meemaw">
  <button>Copy command</button>
</CopyToClipboard>

// Copy with callbacks
<CopyToClipboard
  text={code}
  onSuccess={() => toast.success('Copied!')}
  onError={(err) => toast.error(err.message)}
>
  <CopyButton />
</CopyToClipboard>

// Render function pattern with copy state
<CopyToClipboard text={shareUrl}>
  {(copy, copied) => (
    <button onClick={copy}>
      {copied ? 'Copied!' : 'Copy link'}
    </button>
  )}
</CopyToClipboard>

// Auto-extract text from children
<CopyToClipboard>
  <code>const greeting = "Hello, World!";</code>
</CopyToClipboard>

<Clamp>

Truncate text with optional expand/collapse functionality.

import { Clamp } from 'meemaw';

// Clamp by character count
<Clamp maxChar={100}>
  {longText}
</Clamp>

// Clamp by line count
<Clamp maxLines={3}>
  <p>{article}</p>
</Clamp>

// Expandable with custom text
<Clamp
  maxChar={200}
  expandable
  expandText="Read more"
  collapseText="Show less"
  truncateEnd="..."
  onToggle={(isExpanded) => console.log('Expanded:', isExpanded)}
>
  {biography}
</Clamp>

Real-World Examples

Loading States

function UserDashboard() {
  const { data, loading, error } = useQuery('/api/dashboard');

  return (
    <Loadable loading={loading} error={error} loadingComponent={<DashboardSkeleton />}>
      <Switch>
        <Case when={!data.posts.length}>
          <EmptyState />
        </Case>
        <Case when={data.posts.length > 0}>
          <Repeat each={data.posts}>{post => <PostCard key={post.id} post={post} />}</Repeat>
        </Case>
      </Switch>
    </Loadable>
  );
}

Responsive Navigation

function Navigation() {
  return (
    <>
      <Hidden on={['mobile', 'tablet']}>
        <DesktopNav />
      </Hidden>

      <Hidden on="desktop">
        <MobileNav />
      </Hidden>
    </>
  );
}

First-Time User Experience

function App() {
  return (
    <div>
      <ShowOnce persist persistKey="welcome-v2" persistType="local">
        <WelcomeModal />
      </ShowOnce>

      <Delayed until={userDataLoaded}>
        <MainContent />
      </Delayed>
    </div>
  );
}

Role-Based Content

function Dashboard({ user }) {
  return (
    <Switch>
      <Case when={user.role === 'admin'}>
        <AdminDashboard />
      </Case>
      <Case when={user.role === 'moderator'}>
        <ModeratorDashboard />
      </Case>
      <Case when={user.role === 'user'}>
        <UserDashboard />
      </Case>
      <Default>
        <GuestView />
      </Default>
    </Switch>
  );
}

Code Snippet with Copy

function CodeBlock({ code, language }) {
  return (
    <div className="code-block">
      <CopyToClipboard text={code}>
        {(copy, copied) => (
          <button onClick={copy} className="copy-btn">
            {copied ? '✓ Copied' : 'Copy'}
          </button>
        )}
      </CopyToClipboard>
      <pre>
        <code className={language}>{code}</code>
      </pre>
    </div>
  );
}

Article Preview

function ArticleCard({ article }) {
  return (
    <article>
      <h2>{article.title}</h2>
      <Clamp maxLines={3} expandable expandText="Read more" collapseText="Show less">
        <p>{article.content}</p>
      </Clamp>
    </article>
  );
}

TypeScript Support

All components are written in TypeScript with full type definitions included.

import { Show, Repeat, ShowOnce, PersistenceType } from 'meemaw';

interface User {
  id: number;
  name: string;
}

const users: User[] = [
  /* ... */
];

<Repeat<User> each={users}>{(user, index) => <div key={user.id}>{user.name}</div>}</Repeat>;

const persistType: PersistenceType = 'local';
<ShowOnce persist persistType={persistType}>
  <Notification />
</ShowOnce>;

Bundle Size

Meemaw is optimized for minimal bundle impact:

| Export | Size (minified + gzipped) | | --------------------- | ------------------------- | | Full package | ~7 KB | | Individual components | ~0.5-1.5 KB each |

Check the current size: npm run size

Only import what you need - tree-shaking ensures you only ship the components you use.


Browser Support

Meemaw supports all modern browsers:

  • Chrome (last 2 versions)
  • Firefox (last 2 versions)
  • Safari (last 2 versions)
  • Edge (last 2 versions)

For older browsers, you may need to include appropriate polyfills.


Development

# Install dependencies
npm install

# Run tests
npm test

# Run tests in watch mode
npm test:watch

# Build the library
npm run build

# Type check
npm run typecheck

# Lint
npm run lint

# Format code
npm run format

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

MIT © spiderocious


Links


Made with ❤️ for the React community

If you find this library useful, please consider giving it a star on GitHub!