Component Overview
The component package is Remix V3's built-in UI layer. It is a lightweight JSX runtime --- not React, not Preact, not a virtual DOM diffing library. It produces real DOM nodes on the client and HTML strings or streams on the server, with a small footprint and no external dependencies.
What is a JSX runtime?
A JSX runtime is the library that turns <div>Hello</div> into JavaScript function calls. React is one JSX runtime; Remix has its own. You write the same JSX syntax, but the behavior underneath is different.
Key Features
| Feature | What It Does |
|---|---|
| Server rendering | renderToString and renderToStream produce HTML on the server. |
| Client hydration | run() attaches interactivity to server-rendered HTML without re-rendering. |
| Double-function components | Setup logic runs once; the render function runs on every update. |
| Mixins | Composable behaviors (css, on, ref, link, pressEvents) attached via the mix attribute. |
| Animations | Spring physics, tweens, and layout animations built in. |
| Frames | The Frame component loads streaming server content into page regions. |
| Context | Pass data through the component tree without prop drilling. |
| Client entries | Mark components for selective hydration with clientEntry. |
The Double-Function Pattern
Every component is a function that returns another function. The outer function is the setup phase (runs once per instance). The inner function is the render phase (runs each time the component updates).
A simple component with no interactivity:
function Greeting() {
// Setup phase --- runs once
return ({ name }: { name: string }) => (
// Render phase --- runs on every update
<p>Hello, {name}!</p>
)
}An interactive component adds a handle parameter. The handle provides update() to trigger re-renders:
function Counter() {
return (handle) => {
let count = 0
return ({ initial = 0 }: { initial?: number }) => {
count = initial
return (
<div>
<p>Count: {count}</p>
<button mix={on('click', () => {
count++
handle.update()
})}>
Increment
</button>
</div>
)
}
}
}What is a handle?
The handle is a runtime object that Remix gives to interactive components. It provides update() to schedule re-renders, signal for cleanup, context for the context API, and frame for frame navigation.
Minimal Example
Here is a complete server-rendered page with a styled heading:
import { css, Fragment } from 'remix/component'
import { renderToString } from 'remix/component/server'
function Page() {
return ({ title }: { title: string }) => (
<html>
<head><title>{title}</title></head>
<body>
<h1 mix={css({ color: '#333', fontFamily: 'sans-serif' })}>
{title}
</h1>
<p>Welcome to Remix V3.</p>
</body>
</html>
)
}
let html = renderToString(<Page title="Home" />)TypeScript Configuration
Set the JSX import source in your tsconfig.json so that .tsx files use Remix's runtime instead of React:
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "remix/component"
}
}Imports at a Glance
// Components and mixins
import { css, on, ref, link, pressEvents, spring, tween, Fragment, Frame, navigate } from 'remix/component'
// Server rendering
import { renderToString, renderToStream } from 'remix/component/server'
// Client hydration
import { run, createRoot } from 'remix/component'How It Differs from React
| Concept | React | Remix Component |
|---|---|---|
| Component shape | Single function returning JSX | Outer function (setup) returning inner function (render) |
| State | useState, useReducer | Local variables + handle.update() |
| Side effects | useEffect | handle.queueTask(), handle.signal |
| Styling | className + external CSS | css() mixin with scoped styles |
| Event handling | onClick prop | on('click', handler) mixin |
| Refs | useRef | ref() mixin |
TIP
If you are coming from React, the biggest shift is that there are no hooks. State is plain variables. You call handle.update() when you want to re-render.
Related
- Component Tutorial --- Build an interactive counter, a todo list, and a streaming page step by step.
- Component Reference --- Full API reference for every export.
- Streaming --- How
renderToStreamand Frames work together. - Styling Guide --- Patterns for using the
cssmixin.