Guides

React Compatibility

Mreact's primary app path is the compiled App Router model, but the workspace also includes @reckona/mreact-compat for React compatibility. Use it when you need React-like runtime behavior, when you are evaluating third-party React libraries, or when an integration needs React-style JSX runtimes, hooks, roots, scheduling, hydration, Suspense, or server rendering APIs.

Most applications should import from @reckona/mreact:

import { createElement, useState } from "@reckona/mreact";

Importing @reckona/mreact-compat directly is mainly for tests, framework integration, compatibility experiments, and package-level debugging:

import ReactCompat, { createElement, useState } from "@reckona/mreact-compat";
import { jsx } from "@reckona/mreact-compat/jsx-runtime";

Vite configuration

You usually do not need a separate Vite alias just to use Mreact's app router. The mreactRouter() plugin wires the framework runtime, and most route code should import from @reckona/mreact.

When you evaluate React ecosystem libraries, the Vite configuration may still matter for normal Vite reasons. The react-libraries example pre-bundles browser-side React ecosystem packages with optimizeDeps.include so the dev server does not discover them after the page is already interactive and trigger a full reload. It also excludes server-only packages such as better-sqlite3 from dependency optimization and allows that package through the router import policy for server modules.

// vite.config.ts
import { defineConfig } from "vite";
import { mreactRouter } from "@reckona/mreact-router/vite";

export default defineConfig({
  optimizeDeps: {
    exclude: ["better-sqlite3"],
    include: [
      "recharts",
      "lexical",
      "@lexical/react/LexicalComposer",
      "@conform-to/react",
      "@conform-to/zod",
      "zod",
      "@radix-ui/react-dialog",
    ],
  },
  plugins: [
    mreactRouter({
      routesDir: "app",
      importPolicy: {
        allowedPackages: ["better-sqlite3"],
      },
    }),
  ],
});

Treat optimizeDeps.include as a dev-experience tool, not a compatibility switch. If a library imports browser globals during server render, let inference handle visible browser behavior or isolate browser-only code in a .compat.tsx component.

What it covers

@reckona/mreact-compat implements React compatibility for element creation, fragments, refs, hooks, context, roots, scheduling, reconciliation, hydration, Suspense, server rendering, resource hints, JSX runtimes, and selected Flight integration surfaces.

The compatibility gate tracks React 19.2.6 public export coverage for React, React DOM, React DOM client, and React DOM server. It is a compatibility runtime, not a byte-for-byte React reconciler, so use tests for the specific library behavior you depend on.

Compiler optimization

The compatibility runtime is not the only execution path for React-shaped code. When React-compatible JSX is compiled by Mreact, the compiler can lower proven-safe state text, prop bindings, and event bindings into reactive DOM blocks. Effect-sensitive, ref-sensitive, or otherwise unsupported shapes keep the normal compatibility reconciler path, so the optimization preserves observable behavior instead of acting as a benchmark-only shortcut.

App Router output

Static React-compatible createElement() trees can still flow through the App Router server string pipeline, so a server-renderable compat subtree does not need to pay the same runtime cost as a fully dynamic client integration. When a route uses compat client references, the router shares compat vendor chunks only across route artifacts that actually need them, keeping server-only and non-compat routes out of that client payload.

Use this as a performance model, not a compatibility switch: start from server-renderable route code, isolate browser-only libraries behind narrow client-interactive boundaries, and check the route's client bundle size on the Benchmarks page or in your own production build.

Known differences

useId() returns opaque underscore-delimited ids such as _R_0_ and _r_0_ instead of React's colon-delimited internal shape. Mreact keeps SSR and hydration ids stable through its hydrated-id map, but application code and libraries should treat the returned string as opaque and must not parse or compare it against React's exact internal format.

Server rendering normalizes standard HTML attribute casing, including readOnly. If a third-party library depends on byte-for-byte React markup rather than browser-observable DOM behavior, keep a focused compatibility test around that integration.

Library evaluation workflow

Start with examples/react-libraries on GitHub when you want to evaluate ecosystem packages. That example exercises libraries such as Recharts, Lexical, Conform, Zod, and Radix UI through a real Mreact app.

pnpm --filter @reckona/example-react-libraries dev
pnpm --filter @reckona/example-react-libraries build
pnpm --filter @reckona/example-react-libraries test:e2e

If a package works in the compatibility example but fails in an App Router route, check whether inference can see the browser behavior, whether an explicit client boundary is needed, whether the package imports browser-only modules during server render, and whether it expects React DOM behavior that is not part of the tested compatibility surface yet.

The repository also includes focused compatibility labs for ecosystem packages that need screenshot and DOM-summary comparison against React. Run pnpm compat-lab:radix when changing Radix-facing event or portal behavior, pnpm compat-lab:recharts when changing chart, SVG, animation, or tooltip behavior, pnpm compat-lab:react-flow when changing React Flow or xyflow-facing layout, store, handle, or pointer behavior, and pnpm compat-lab:ui-primitives when changing primitive-library behavior for Ark UI, Base UI, Headless UI, React Aria, React Spectrum, or Zag JS.

Focused conformance checks

Run the focused compatibility suite when changing the runtime or validating a React-facing behavior:

pnpm test:react-conformance
pnpm exec vitest run packages/react-compat/test/react-official-conformance.test.ts packages/react-compat/test/react-official-suite-gate.test.ts

API reference: @reckona/mreact-compat, hooks, JSX runtime, and scheduler.