The Lightweight
Virtual DOM Library

A minimal, React-like library with fiber-based reconciliation. Keep bundles tiny with split entrypoints, Preact-like SVG handling, and opt-in ecosystem bridges like React.use, Suspense fallback rendering, and JSX runtime aliases.

Get Started
npm install @ipxjs/refract

Tiny Bundle Size

Significantly smaller footprint than React. Ideal for performance-critical applications and micro-frontends.

Modular Entrypoints

Choose @ipxjs/refract/core for basics, @ipxjs/refract/full for the complete API, or opt into refract/compat/* for createRoot, flushSync, React.use, and Suspense fallback support.

Familiar Hooks API

Standard Hooks like useState, useEffect, useMemo, and useContext work exactly as you expect.

See it in action

Explore memoization, keyed list diffing, and realtime state — all running live in your browser.

Search and patch incidents to exercise keyed list diffing and memoized rows.

IncidentBoardDemo.js
Loading demo code...
Live Preview
Loading interactive demos...
Rendered with @ipxjs/refract

Alias React imports to Refract

Use these snippets when React ecosystem packages import react and react-dom. Point them to node_modules/@ipxjs/refract/src/refract/compat/* so existing packages run on Refract.

Vite

vite.config.ts
import { defineConfig } from "vite";
const compatRoot = "node_modules/@ipxjs/refract/src/refract/compat";

export default defineConfig({
  resolve: {
    alias: {
      react: `${compatRoot}/react`,
      "react-dom": `${compatRoot}/react-dom`,
      "react-dom/client": `${compatRoot}/react-dom/client`,
      "react/jsx-runtime": `${compatRoot}/react/jsx-runtime`,
      "react/jsx-dev-runtime": `${compatRoot}/react/jsx-dev-runtime`,
    },
  },
});

Webpack

webpack.config.js
const compatRoot = "node_modules/@ipxjs/refract/src/refract/compat";

module.exports = {
  resolve: {
    alias: {
      react$: `${compatRoot}/react`,
      "react-dom$": `${compatRoot}/react-dom`,
      "react-dom/client$": `${compatRoot}/react-dom/client`,
      "react/jsx-runtime$": `${compatRoot}/react/jsx-runtime`,
      "react/jsx-dev-runtime$": `${compatRoot}/react/jsx-dev-runtime`,
    },
  },
};

Rollup

rollup.config.mjs
import alias from "@rollup/plugin-alias";
const compatRoot = "node_modules/@ipxjs/refract/src/refract/compat";

export default {
  plugins: [
    alias({
      entries: [
        { find: "react", replacement: `${compatRoot}/react` },
        { find: "react-dom", replacement: `${compatRoot}/react-dom` },
        { find: "react-dom/client", replacement: `${compatRoot}/react-dom/client` },
        { find: "react/jsx-runtime", replacement: `${compatRoot}/react/jsx-runtime` },
        { find: "react/jsx-dev-runtime", replacement: `${compatRoot}/react/jsx-dev-runtime` },
      ],
    }),
  ],
};

esbuild

build.mjs
import esbuild from "esbuild";
const compatRoot = "node_modules/@ipxjs/refract/src/refract/compat";

await esbuild.build({
  entryPoints: ["src/main.tsx"],
  bundle: true,
  outdir: "dist",
  alias: {
    react: `${compatRoot}/react`,
    "react-dom": `${compatRoot}/react-dom`,
    "react-dom/client": `${compatRoot}/react-dom/client`,
    "react/jsx-runtime": `${compatRoot}/react/jsx-runtime`,
    "react/jsx-dev-runtime": `${compatRoot}/react/jsx-dev-runtime`,
  },
});

Built for Modern Apps

  • Context API: Built-in dependency injection for complex state management.
  • Automatic Batching: Updates are batched via microtasks for performance.
  • SVG Support: Automatic SVG namespace handling with foreignObject HTML fallback and Preact-like prop normalization (xlinkHref/xlink:href -> href).
  • Security First: Sanitized dangerouslySetInnerHTML by default.
  • React Compat Layer: Optional refract/compat/* entrypoints cover React.use, Suspense fallback boundaries, and a safe findDOMNode stub for ecosystem interop.
  • Compat Status (February 23, 2026): 15 test files / 100 tests passing, including dedicated compat and react-router smoke suites.

API Surface

createElement render useState useEffect useMemo useCallback useReducer createContext memo createRef use Suspense