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

@babajaga3/react-bricks

v0.1.1

Published

A tiny factory for building composable, Tailwind-friendly React layout component systems.

Readme

react-bricks

A tiny (~1 kB gzipped) factory for building composable, Tailwind-friendly React layout component systems. Define your own named layout slots once, then snap them together like bricks anywhere in your codebase.

const MobileLayout = createLayout({
  Main:    { as: 'main',   className: 'flex flex-col min-h-screen' },
  Header:  { as: 'header', className: 'sticky top-0 z-50 h-14 border-b' },
  Content: {               className: 'flex-1 overflow-y-auto px-4 py-6' },
  Footer:  { as: 'footer', className: 'h-16 border-t flex items-center px-4' },
});

function Page() {
  return (
    <MobileLayout.Main>
      <MobileLayout.Header>My App</MobileLayout.Header>
      <MobileLayout.Content>Hello world</MobileLayout.Content>
      <MobileLayout.Footer>© 2025</MobileLayout.Footer>
    </MobileLayout.Main>
  );
}

Features

  • Zero config — works with plain CSS classes, Tailwind, or any utility framework
  • Tailwind-aware — uses tailwind-merge to resolve class conflicts when installed
  • Fully typed — TypeScript generics infer slot names from your config; invalid slot access is a compile error
  • Polymorphic — every slot accepts an as prop to swap the rendered element
  • Composable — extend layouts, merge layouts, override per-instance
  • Tree-shakeable — dual ESM + CJS output, "sideEffects": false
  • React 17+ compatible, framework agnostic (Next.js, Vite, Remix…)

Installation

npm install @babajaga3/react-bricks
# or
pnpm add @babajaga3/react-bricks

Optional peer dependencies (recommended)

For Tailwind class-conflict resolution and conditional class support:

npm install tailwind-merge clsx

The package works without them — it falls back to plain space-joined class concatenation.


API

createLayout(config, name?)

Creates a namespaced object of slot components from a config.

function createLayout<T extends LayoutConfig>(
  config: T,
  name?: string,   // shown in React DevTools as "name.SlotKey"
): Layout<T>

Config shape:

| Property | Type | Default | Description | |---------------|-----------------------|----------|------------------------------------------------------| | as | React.ElementType | 'div' | The HTML element or component this slot renders as | | className | string | '' | Default classes applied to every instance | | displayName | string | inferred | Label in React DevTools |

Slot component props:

Every generated slot accepts:

| Prop | Type | Description | |-------------|---------------------|--------------------------------------------------------------------------| | as | React.ElementType | Override the rendered element/component for this single instance | | className | string | Extra classes merged on top of defaults (via tailwind-merge if present)| | children | React.ReactNode | Slot content | | ...rest | element props | All other props forwarded to the underlying element |


extendLayout(base, extension, name?)

Creates a new layout by extending an existing one. Slots in extension override matching slots in base; new keys are added.

const DesktopLayout = extendLayout(
  MobileLayout,
  {
    // Override
    Content: { className: 'flex-1 px-8 max-w-5xl mx-auto' },
    // Add new
    Sidebar: { as: 'aside', className: 'w-64 border-r hidden lg:block' },
  },
  'DesktopLayout',
);

// DesktopLayout.Header  ← from MobileLayout (unchanged)
// DesktopLayout.Content ← overridden
// DesktopLayout.Sidebar ← new

mergeLayouts(a, b)

Merges two already-built layout objects into one. Slots in b win when keys collide.

const CardLayout = createLayout({ Root: { … }, Body: { … } });
const AppLayout  = mergeLayouts(MobileLayout, CardLayout);

// AppLayout.Main / .Header / .Content / .Footer / .Root / .Body

cn(...classes)

The internal class merger is exported in case you want to use it in your own components.

import { cn } from '@babajaga3/react-bricks';

<div className={cn('px-4', isActive && 'bg-blue-500', props.className)} />

Patterns

One layout file per breakpoint / product area

// layouts/mobile.ts
export const MobileLayout = createLayout({ … });

// layouts/desktop.ts
export const DesktopLayout = extendLayout(MobileLayout, { … });

// layouts/dashboard.ts
export const DashboardLayout = createLayout({ … });

Per-page className overrides

Default classes live in the layout definition. Instance overrides are merged at render time — Tailwind conflicts are resolved automatically.

// Default: px-4
<MobileLayout.Content className="px-8">…</MobileLayout.Content>
// Rendered: px-8  (tailwind-merge resolves the conflict)

Polymorphic slot rendering

// Render Content as <article> for semantic HTML
<MobileLayout.Content as="article" className="prose">
  <h2>…</h2>
</MobileLayout.Content>

// Render Content as a third-party motion component
import { motion } from 'motion/react';
<MobileLayout.Content as={motion.div} animate={{ opacity: 1 }}>
  …
</MobileLayout.Content>

TypeScript

Slot names are inferred from your config — accessing a slot that doesn't exist is a compile-time error.

const Layout = createLayout({ Main: { … }, Header: { … } });

<Layout.Main />    // ✅
<Layout.Footer />  // ❌ Property 'Footer' does not exist on type 'Layout<…>'

You can also export the layout type for use in other files:

import type { Layout } from '@babajaga3/react-bricks';
import type { myLayoutConfig } from './layouts/mobile';

type MobileLayoutType = Layout<typeof myLayoutConfig>;

Acknowledgement

The majority of the initial codebase has been generated with Claude Sonnet 4.6 - everything from commit 0b67bb3. I had this idea in my mind and it was a fast way to prototype it. Do what you will with that information.


License

MIT