React Zero-UI: Instant UI updates, ZERO re-renders, ZERO runtime

4 months ago 3

Instant UI state updates. ZERO React re‑renders. <1 KB runtime.

Pre‑render your UI once, flip a data-* attribute to update — that's it.

npm version npm version  MIT CI



Example Link What it shows Link to Code
Interactive menu with render tracker Main Demo↗ Compare Zero‑UI vs. React side‑by‑side while toggling a menu. Github
React benchmark (10 000 nested nodes) React 10k↗ How long the traditional React render path takes. Github
Zero‑UI benchmark (10 000 nested nodes) Zero‑UI 10k↗ Identical DOM, but powered by Zero‑UI's data-* switch. Github

Every setState in React triggers the full VDOM → Diff → Reconciliation → Paint pipeline. For pure UI state (themes, menus, toggles) that work is wasted.

Zero‑UI introduces "PRE‑rendering":

  1. Tailwind variants for every state are generated at build‑time.
  2. The app pre‑renders once.
  3. Runtime state changes only flip a data-* attribute on <body>.

Result → 5-10× faster visual updates with ZERO additional bundle cost.

📊 Micro‑benchmarks (Apple M1)

Nodes updated React state Zero‑UI Speed‑up
10,000 ~50 ms ~5 ms 10×
25,000 ~180 ms ~15 ms 12×
50,000 ~300 ms ~20 ms 15×

Re‑run these numbers yourself via the links above.


Prerequisite: Tailwind CSS v4 must already be initialized in your project.

# Inside an existing *Next.js (App Router)* or *Vite* repo npx create-zero-ui

That's it — the CLI patch‑installs the required Babel & PostCSS plugins and updates configs for you.

npm install @austinserb/react-zero-ui

Then follow Setup → for your bundler.


// vite.config.* import { zeroUIPlugin } from '@austinserb/react-zero-ui/vite'; export default { // ❗️Remove the default `tailwindcss()` plugin — Zero‑UI extends it internally plugins: [zeroUIPlugin()], };
  1. Spread bodyAttributes on <body> in your root layout.

    // app/layout.tsx import { bodyAttributes } from '@austinserb/react-zero-ui/attributes'; // or: import { bodyAttributes } from '../.zero-ui/attributes'; export default function RootLayout({ children }) { return ( <html lang="en"> <body {...bodyAttributes}>{children}</body> </html> ); }
  2. Add the PostCSS plugin (must come before Tailwind).

    // postcss.config.js module.exports = { plugins: { '@austinserb/react-zero-ui/postcss': {}, tailwindcss: {} } };

react zero ui usage explained


const [staleValue, setValue] = useUI<'open' | 'closed'>('sidebar', 'closed');
  • key → becomes data-{key} on <body>.
  • defaultValue → optional, prevents FOUC.
  • Note: the returned staleValue does not update (useUI is write‑only).
<div className="sidebar-open:translate-x-0 sidebar-closed:-translate-x-full" />

Any data-{key}="{value}" pair becomes a variant: {key}-{value}:.


  1. useUI → writes to data-* attributes on <body>.
  2. Babel plugin → scans code, finds every key/value, injects them into PostCSS.
  3. PostCSS plugin → generates static Tailwind classes at build‑time.
  4. Runtime → changing state only touches the attribute — no VDOM, no reconciliation, no re‑paint.

  • Zero React re‑renders for UI‑only state.
  • Global setters — call from any component or util.
  • Tiny: < 1 KB gzipped runtime.
  • TypeScript‑first.
  • SSR‑friendly (Next.js & Vite SSR).
  • Framework‑agnostic CSS — generated classes work in plain HTML / Vue / Svelte as well.

  1. UI state only → themes, layout toggles, feature flags.
  2. Business logic stays in React → fetching, data mutation, etc.
  3. Kebab‑case keys → e.g. sidebar-open.
  4. Provide defaults to avoid Flash‑Of‑Unstyled‑Content.

PRs & issues welcome! Please read the Contributing Guide.


MIT © Austin Serb


Built with ❤️ for the React community. If Zero‑UI makes your app feel ZERO fast, please ⭐️ the repo!

Read Entire Article