zeroOnClick Experimental Runtime
Use SSR-safe click handling for React Server Components and UI state updates without adding broad client components.
Why This Approach?
The Problem: A single onClick event forces your entire component tree to become client-rendered. In Next.js, this means shipping extra JavaScript, losing SSR benefits, and adding hydration overhead, all for basic interactivity.
The Solution: This design creates the perfect bridge between static HTML and interactive UX, while maintaining:
- Server-rendered performance
- Zero JavaScript bundle overhead
- Instant visual feedback
Why sacrifice server-side rendering for a simple click handler when 300 bytes of runtime can handle all the clicks in your app?
Core Functionality
activateZeroUiRuntime()
The core runtime entrypoint that enables client-side interactivity in server components:
How it works:
- Single Global Listener - Registers one click event listener on
document - Smart Detection - Listens for clicks on elements with
data-uiattributes - Directive Parsing - Interprets
data-uidirectives in this format.
+ data-ui="global:key(val1,val2,...)" -> flips data-key on document.body
+ data-ui="scoped:key(val1,val2,...)" -> flips data-key on closest ancestor/self- Round-Robin Cycling - Cycles through values in sequence
- Instant DOM Updates - Updates DOM immediately for Tailwind responsiveness
Note: Guards against duplicate initialization using
window.__zeroflag.
Helper Functions
zeroSSR.onClick() & scopedZeroSSR.onClick()
Utility functions that generate valid data-ui attributes for JSX/TSX:
Global Example:
zeroSSR.onClick("theme", ["dark", "light"]);
// Returns: { 'data-ui': 'global:theme(dark,light)' }Scoped Example:
scopedZeroSSR.onClick("modal", ["open", "closed"]);
// Returns: { 'data-ui': 'scoped:modal(open,closed)' }Development Validation:
- Ensures keys are kebab-case
- Validates at least one value is provided
Installation & Setup
Step 1: Install Package
npm install @react-zero-ui/coreStep 2: Generate Variants
Run your development server to generate the required variant map:
npm run devThis creates .zero-ui/attributes.ts containing the variant map needed for runtime activation.
Step 3: Create <InitZeroUI> Component
"use client";
import { variantKeyMap } from "path/to/.zero-ui/attributes";
import { activateZeroUiRuntime } from "@react-zero-ui/core/experimental/runtime";
activateZeroUiRuntime(variantKeyMap);
export const InitZeroUI = () => null;Step 4: Add to Root Layout
import { InitZeroUI } from "path/to/InitZeroUI";
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<InitZeroUI />
{children}
</body>
</html>
);
}Usage Examples
Global Theme Toggle
import { zeroSSR } from "@react-zero-ui/core/experimental";
<div {...zeroSSR.onClick("theme", ["dark", "light", "spanish"])}>Click me to cycle themes!</div>;Pair with Tailwind variants:
<div class="theme-dark:bg-black theme-light:bg-white theme-spanish:bg-red-500">Interactive Server Component!</div>Scoped Modal Toggle
import { scopedZeroSSR } from "@react-zero-ui/core/experimental";
// Scopes based on matching data-* attribute (e.g. data-modal)
<div data-modal="open">
<button {...scopedZeroSSR.onClick("modal", ["open", "closed"])}>Toggle Modal</button>
</div>;Design Philosophy
Core Principles
- No React State - Zero re-renders involved
- Pure DOM Mutations - Works entirely via
data-*attribute changes - Server Component Compatible - Full compatibility with all server components
- Tailwind-First - Designed for conditional CSS classes
Summary
| Feature | Description |
|---|---|
activateZeroUiRuntime() | Enables click handling on static components via data-ui |
zeroSSR / scopedZeroSSR | Generate valid click handlers as JSX props |
| Runtime Overhead | ~300 bytes total |
| React Re-renders | Zero |
| Server Component Support | Full compatibility |
Source Code: See experimental for implementation details.
The bridge between static HTML and interactive UX
No state. No runtime overhead. Works in server components. ZERO re-renders.