slim-react
hadars's lightweight React-compatible SSR renderer — no react-dom/server required.
What it is
slim-react is hadars's own server-side renderer, located in src/slim-react/. It replaces react-dom/server entirely on the server side. Your components and any libraries they import render through it automatically — no code changes required.
For SSR builds, rspack aliases react and react/jsx-runtime to slim-react, so third-party components render through it transparently.
How it works
hydrateRoot.Supported React features
React.memo✓Wrapped components render normally.React.forwardRef✓Refs are ignored on the server (no DOM), render proceeds.React.lazy✓The lazy promise is awaited before rendering.Context.Provider✓Full context propagation through the tree.Context.Consumer✓Reads the nearest Provider value.React.Suspense✓Thrown Promises are awaited and the component is retried.async components✓Async function components are awaited directly.React.useId()✓Generates tree-position-based IDs matching React's client output.useState / useEffectpartialuseState returns the initial value. useEffect is a no-op on the server.useRef / useCallback / useMemopartialReturn the initial value or identity — no caching between renders.useId() compatibility
slim-react implements React 19's tree-position-based useId algorithm. IDs are derived from the component's position in the render tree, so they are deterministic across the server render and client hydration.
When your components call React.useId(), slim-react intercepts the call via a dispatcher shim and routes it through the same algorithm, producing IDs that React's hydrateRoot will agree with — no hydration warnings.
// Works in any component during SSR — no special imports needed
const FormField = ({ label }) => {
const id = React.useId(); // slim-react handles this during SSR
return (
<>
<label htmlFor={id}>{label}</label>
<input id={id} />
</>
);
};Emotion / CSS-in-JS
Because slim-react renders through the same React component model, CSS-in-JS libraries like @emotion/styled and @emotion/react work out of the box — styles are inlined into the rendered HTML on the server, and the client hydrates without a flash of unstyled content.