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

@page-speed/blocks

v0.1.3

Published

High-performance rendering runtime for @opensite/ui components with pre-compiled Tailwind CSS and tree-shakable architecture

Readme

@page-speed/blocks

High-performance rendering runtime for @opensite/ui components with pre-compiled Tailwind CSS, RouterProvider integration for Pressable components, and tree-shakable architecture.

Features

  • Performance-First: Optimized for minimal bundle size and maximum runtime performance
  • Tree-Shakable: Granular exports allow importing only what you need
  • Flexible Styling: Works with both pre-compiled CSS and runtime Tailwind
  • Registry-Based: Extensible component registry for custom renderers
  • RouterProvider Integration: Automatic RouterProvider wrapping for Pressable components
  • Direct Pressable Usage: Uses @page-speed/pressable directly for proper Tailwind styling
  • TypeScript: Full type safety with comprehensive type definitions
  • React 18+: Built for modern React with hooks and concurrent features

Installation

pnpm add @page-speed/blocks
# or
npm install @page-speed/blocks
# or
yarn add @page-speed/blocks

Peer Dependencies

pnpm add react react-dom @opensite/ui @page-speed/img @page-speed/video @page-speed/pressable @page-speed/router

Quick Start

Basic Usage

import { BlocksRenderer } from "@page-speed/blocks";
import type { Block } from "@page-speed/blocks/types";

const blocks: Block[] = [
  {
    _id: "1",
    _type: "Box",
    styles: "p-4 bg-gray-100",
    content: "Hello World",
  },
];

function App() {
  return <BlocksRenderer blocks={blocks} />;
}

Enhanced Usage (Recommended)

The EnhancedBlocksRenderer automatically wraps your blocks with RouterProvider from @page-speed/router, ensuring Pressable components work correctly:

import { EnhancedBlocksRenderer } from "@page-speed/blocks";
import type { Block } from "@page-speed/blocks/types";

const blocks: Block[] = [
  {
    _id: "1",
    _type: "Button",
    props: {
      variant: "default",
      size: "lg",
      onClick: () => console.log("Clicked!"),
    },
    content: "Click Me",
  },
];

function App() {
  return <EnhancedBlocksRenderer blocks={blocks} />;
}

Manual Provider Control

If your app already has a RouterProvider, you can disable the automatic wrapping:

import { EnhancedBlocksRenderer } from "@page-speed/blocks";

function App() {
  return (
    <EnhancedBlocksRenderer
      blocks={blocks}
      disableRouter={true}  // App already has RouterProvider
    />
  );
}

Core Concepts

Block Structure

Blocks are the fundamental building units, compatible with Chai design payloads:

interface Block {
  _id: string;              // Unique identifier
  _type: string;            // Component type (maps to renderer)
  _parent?: string | null;  // Parent block ID (null for root)
  styles?: string;          // Tailwind CSS classes
  content?: string;         // Text content
  props?: Record<string, any>; // Component-specific props
  // ... additional properties
}

Built-in Renderers

The library includes optimized renderers for common component types that use @page-speed/pressable directly:

// Automatically registered block types:
- Pressable, PressableButton, PressableLink, CTAButton, ActionButton
- Button, SubmitButton, FormButton
- Link, NavLink, CTALink, ExternalLink

These renderers ensure proper Tailwind styling by using the Pressable component from @page-speed/pressable directly instead of pass-through components.

Component Registry

Extend the library with custom renderers:

import { registerBlockRenderer } from "@page-speed/blocks/registry";

registerBlockRenderer("MyComponent", ({ block, context }) => {
  return (
    <div className={block.styles}>
      {block.content}
      {context.renderChildren(block._id)}
    </div>
  );
});

Tree-Shakable Imports

Import only what you need for optimal bundle size:

// Specific imports (recommended)
import { EnhancedBlocksRenderer } from "@page-speed/blocks/core/enhanced";
import { BlocksProvider } from "@page-speed/blocks/core/provider";
import { registerBlockRenderer } from "@page-speed/blocks/registry";
import type { Block } from "@page-speed/blocks/types";

// Custom renderers
import {
  pressableRenderer,
  buttonRenderer,
  linkRenderer
} from "@page-speed/blocks/renderers";

// Main export (includes all core functionality)
import {
  EnhancedBlocksRenderer,
  BlocksRenderer,
  registerBlockRenderer,
  initializeDefaultRenderers
} from "@page-speed/blocks";

API Reference

Components

<EnhancedBlocksRenderer />

The main component for rendering blocks with automatic RouterProvider wrapping:

interface EnhancedBlocksRendererProps {
  blocks: Block[];           // Array of blocks to render
  className?: string;        // Optional CSS class for wrapper
  wrapper?: React.ComponentType<{ children: React.ReactNode }>;
  disableRouter?: boolean;   // Disable RouterProvider if app already has one
}

<BlocksRenderer />

Base renderer without RouterProvider (for advanced use cases):

interface BlocksRendererProps {
  blocks: Block[];
  className?: string;
  wrapper?: React.ComponentType<{ children: React.ReactNode }>;
}

<BlocksProvider />

Provider component for wrapping blocks with necessary context:

interface BlocksProviderProps {
  children: React.ReactNode;
  disableRouter?: boolean;  // Optional: disable router provider
}

Registry Functions

// Register a custom renderer for a block type
registerBlockRenderer(type: string, renderer: BlockRenderer): void

// Get renderer for a specific type
getBlockRenderer(type: string): BlockRenderer | undefined

// Check if a renderer exists
hasBlockRenderer(type: string): boolean

// Remove a renderer
unregisterBlockRenderer(type: string): void

// Clear all custom renderers
clearRegistry(): void

// Get all registered types
getRegisteredTypes(): string[]

// Register multiple renderers at once
registerRenderers(renderers: Record<string, BlockRenderer>): void

// Initialize default renderers (auto-called in browser)
initializeDefaultRenderers(): void

Utility Functions

// Parse design payload string to blocks
parseDesignPayload(payload: string | DesignPayload): Block[]

// Get root blocks (no parent)
getRootBlocks(blocks: Block[]): Block[]

// Get child blocks of a parent
getChildBlocks(blocks: Block[], parentId: string): Block[]

// Build element props from block
buildElementProps(block: Block): Record<string, any>

// Extract className from styles string
extractClassName(styles?: string): string

// Extract background styles
extractBackgroundStyle(styles?: string): React.CSSProperties | undefined

Pre-compiled CSS Support

For production environments, use pre-compiled Tailwind CSS:

// In your HTML/layout
<link rel="stylesheet" href="https://cdn.example.com/tailwind.css" />

// Then use BlocksRenderer normally
<EnhancedBlocksRenderer blocks={blocks} />

The library automatically works with pre-compiled styles, ensuring all button variants and component styles are properly applied.

Pressable Component Integration

The library includes direct integration with @page-speed/pressable for proper button and link styling:

// This will use the optimized Pressable renderer
const buttonBlock: Block = {
  _id: "btn-1",
  _type: "Button",
  props: {
    variant: "default",
    size: "lg",
    onClick: () => console.log("Clicked!"),
  },
  content: "Click Me",
};

// Links also use Pressable
const linkBlock: Block = {
  _id: "link-1",
  _type: "Link",
  props: {
    href: "/about",
    variant: "link",
  },
  content: "Learn More",
};

Advanced Usage

Custom Block Renderer

import { registerBlockRenderer } from "@page-speed/blocks";
import { Pressable } from "@page-speed/pressable";

registerBlockRenderer("CustomCTA", ({ block, context }) => {
  const { href, label, icon } = block.props || {};

  return (
    <Pressable
      href={href}
      variant="default"
      size="lg"
      className="my-custom-class"
    >
      {icon && <Icon name={icon} />}
      {label || block.content}
      {context.renderChildren(block._id)}
    </Pressable>
  );
});

Server-Side Rendering

import { renderToString } from "react-dom/server";
import { EnhancedBlocksRenderer } from "@page-speed/blocks";

const html = renderToString(
  <EnhancedBlocksRenderer blocks={blocks} />
);

Dynamic Block Loading

import { BlocksRenderer, parseDesignPayload } from "@page-speed/blocks";

async function loadAndRenderBlocks() {
  const response = await fetch("/api/blocks");
  const payload = await response.json();
  const blocks = parseDesignPayload(payload);

  return <BlocksRenderer blocks={blocks} />;
}

Migration from @opensite/blocks

If migrating from @opensite/blocks:

  1. Replace imports:
// Before
import { BlocksRenderer } from "@opensite/blocks";

// After
import { EnhancedBlocksRenderer } from "@page-speed/blocks";
  1. Use EnhancedBlocksRenderer for automatic RouterProvider:
// Before
<BlocksRenderer blocks={blocks} />

// After
<EnhancedBlocksRenderer blocks={blocks} />
  1. The library automatically uses @page-speed/pressable for button/link components, ensuring proper Tailwind styling.

Browser Support

  • Chrome/Edge 90+
  • Firefox 88+
  • Safari 14+
  • React 17+ required

Contributing

See ARCHITECTURE.md for detailed architecture documentation.

License

BSD-3-Clause - see LICENSE for details.