This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
LiveReact is a library that integrates React components into Phoenix LiveView applications with end-to-end reactivity. It combines server-side rendering (SSR), client-side hydration, and bidirectional communication between LiveView and React components.
# Install dependencies
mix deps.get
npm install
# Run tests
mix test
# Format code
mix format
npm run format
# Code quality checks
mix credo
# Compile with warnings as errors
mix compile --force --warnings-as-errors
# Check for unused dependencies
mix deps.unlock --check-unused
# Generate documentation
mix docsThe demo app lives in its own repository:
mrdotb/live_react_examples. It
depends on the published package by default; clone it alongside this repo and
set LIVE_REACT_PATH to run it against your working copy of the library:
cd ../live_react_examples
export LIVE_REACT_PATH=../live_react
mix deps.get
ln -sfn ../../live_react deps/live_react # so the JS side resolves it too
mix setup
mix phx.serverSee that repository's README for the full workflow.
LiveReact Component (lib/live_react.ex)
- Main Phoenix component that renders React components inside LiveView
- Handles SSR rendering, props serialization, and slot interoperability
- Uses
phx-update="ignore"to prevent LiveView from overwriting React-managed DOM - Implements ID generation to avoid collisions while maintaining consistency across dead/live renders
SSR System (lib/live_react/ssr.ex, lib/live_react/ssr/*.ex)
- Behavior-based SSR abstraction with telemetry support
- Two implementations:
ViteJS: Makes POST requests to Vite dev server during development (requiresconfig :live_react, vite_host: "http://localhost:5173")NodeJS: Uses NodeJS supervisor for production rendering (requires{:nodejs, "~> 3.1"}dependency)
- Server responses can include preload links by splitting on
<!-- preload -->marker
React Hook (assets/js/live_react/hooks.js)
- Phoenix LiveView hook that manages React component lifecycle
- Handles hydration for SSR components vs fresh mounting
- Provides LiveView interop functions via props:
pushEvent,pushEventTo,handleEvent,removeHandleEvent,upload,uploadTo - Manages component unmounting on LiveView navigation
Vite Plugin (assets/js/live_react/vite-plugin.js)
- Custom Vite plugin that provides
/ssr_renderPOST endpoint during development - Handles hot module reloading for .ex and .heex files
- Configures process termination when Phoenix quits
Slots System (lib/live_react/slots.ex)
- Converts Phoenix slots to React children
- Only supports default slot (
:inner_block), passed as React children - Base64 encodes rendered HTML for transport to client
-
Server-side (First Render):
- LiveView calls
<.react name="ComponentName" props... /> - SSR renders component if configured and it's a dead view
- HTML sent to browser with data attributes:
data-name,data-props,data-slots,data-ssr
- LiveView calls
-
Client-side (Mounting):
- React hook reads data attributes from DOM
- If
data-ssrpresent, usesReactDOM.hydrateRoot(); otherwiseReactDOM.createRoot() - Props include both user-provided props and LiveView interop functions
-
Updates:
- LiveView updates trigger
updated()hook callback - React re-renders with new props
- React components can call
pushEvent()to send events back to LiveView - LiveView handles events and updates socket assigns
- LiveView updates trigger
lib/
live_react.ex # Main component
live_react/
ssr.ex # SSR behavior
ssr/node_js.ex # Production SSR via NodeJS
ssr/vite_js.ex # Development SSR via Vite
slots.ex # Slot/children handling
test.ex # Test helpers
reload.ex # Development reload utilities
mix/tasks/setup.ex # Setup task
assets/
js/live_react/
index.mjs # Client-side entry point
hooks.js # LiveView hook implementation
server.mjs # SSR server entry point
vite-plugin.js # Vite plugin for SSR endpoint
utils.js # Utilities
copy/ # Files copied during installation
The example Phoenix application lives in a separate repository, mrdotb/live_react_examples.
React components receive LiveView interop functions as props:
pushEvent(event, payload)- Send event to current LiveViewpushEventTo(selector, event, payload)- Send event to specific LiveViewhandleEvent(event, callback)- Subscribe to server eventsremoveHandleEvent(ref)- Unsubscribe from eventsupload(name, files)- Upload filesuploadTo(selector, name, files)- Upload to specific LiveView
Development (use Vite):
# config/dev.exs
config :live_react,
ssr_module: LiveReact.SSR.ViteJS,
vite_host: "http://localhost:5173"Production (use NodeJS):
# config/prod.exs
config :live_react, ssr_module: LiveReact.SSR.NodeJS
# application.ex
{NodeJS.Supervisor, [path: LiveReact.SSR.NodeJS.server_path(), pool_size: 4]}Client-side components must be registered in a components object:
// assets/react-components/index.jsx
export { default as Counter } from "./counter.jsx";
export { default as MyComponent } from "./my-component.jsx";Server-side (SSR) must export a render function:
// assets/js/server.js
import * as components from "../react-components/index.jsx";
export { render } from "live_react/server";The library includes a Link component for LiveView navigation:
import { Link } from "live_react";
<Link to="/path" navigate={true}>
Navigate
</Link>;Tests use LiveReact.Test module which provides utilities for testing React components in LiveView context. Run tests with mix test.
- React components are wrapped in a div with
phx-update="ignore"andphx-hook="ReactHook" - Component IDs are auto-generated per-process to avoid collisions while maintaining consistency
- Props and slots are JSON-encoded in data attributes
- SSR is enabled by default but can be disabled per component with
ssr={false} - Only one default slot is supported (passed as React children)
- The library uses Vite for development with custom HMR handling for .ex/.heex files
- Production builds require separate client and server bundles (
npm run buildandnpm run build-server)