@remix-run/cli 0.3.1 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,8 +2,7 @@
2
2
 
3
3
  ## What This Covers
4
4
 
5
- How server-rendered UI becomes interactive in the browser, and how the page updates without a full
6
- navigation. Read this when the task involves:
5
+ How server-rendered UI becomes interactive in the browser, and how the page updates without a full navigation. Read this when the task involves:
7
6
 
8
7
  - Marking a component for client-side hydration with `clientEntry`
9
8
  - Booting the client runtime with `run`
@@ -12,19 +11,13 @@ navigation. Read this when the task involves:
12
11
  - Server rendering with `renderToStream` or `renderToString`
13
12
  - Managing the document `<head>`
14
13
 
15
- For component-local state and updates, see `component-model.md`. For host-element behavior and
16
- events, see `mixins-styling-events.md`.
14
+ For component-local state and updates, see `component-model.md`. For host-element behavior and events, see `mixins-styling-events.md`.
17
15
 
18
16
  ## Server First, Then Hydrate
19
17
 
20
- Make the server route correct before adding `clientEntry(...)`. A POST should already do the right
21
- thing on its own — return HTML, a redirect, or an error response — and a GET should already render
22
- the page the user expects. `clientEntry` exists to layer interactivity on top of UI that already
23
- works without it.
18
+ Make the server route correct before adding `clientEntry(...)`. A POST should already do the right thing on its own — return HTML, a redirect, or an error response — and a GET should already render the page the user expects. `clientEntry` exists to layer interactivity on top of UI that already works without it.
24
19
 
25
- When server state changes after a mutation, prefer reloading a `<Frame>` when the UI region already
26
- maps cleanly to a server-rendered route. Frames re-fetch the same route, so the rendering logic
27
- stays in one place and the client does not need a parallel "state" API.
20
+ When server state changes after a mutation, prefer reloading a `<Frame>` when the UI region already maps cleanly to a server-rendered route. Frames re-fetch the same route, so the rendering logic stays in one place and the client does not need a parallel "state" API.
28
21
 
29
22
  ```tsx
30
23
  on('submit', async (event, signal) => {
@@ -39,15 +32,11 @@ on('submit', async (event, signal) => {
39
32
  })
40
33
  ```
41
34
 
42
- Use polling or a small JSON state endpoint when the data changes outside this page, or when a tiny
43
- shared widget would be heavier to model as a frame. Pick the lightest sync mechanism that preserves
44
- clear ownership of rendering logic.
35
+ Use polling or a small JSON state endpoint when the data changes outside this page, or when a tiny shared widget would be heavier to model as a frame. Pick the lightest sync mechanism that preserves clear ownership of rendering logic.
45
36
 
46
37
  ## Client Entries
47
38
 
48
- Use `clientEntry` to mark a component for client-side hydration. In source-served apps, prefer the
49
- source module's `import.meta.url` as the entry ID and let server rendering map it to the public
50
- asset URL:
39
+ Use `clientEntry` to mark a component for client-side hydration. In source-served apps, prefer the source module's `import.meta.url` as the entry ID and let server rendering map it to the public asset URL:
51
40
 
52
41
  ```tsx
53
42
  import { clientEntry, on, type Handle } from 'remix/ui'
@@ -76,9 +65,7 @@ export const Counter = clientEntry(
76
65
  )
77
66
  ```
78
67
 
79
- On the server, provide `resolveClientEntry` to `renderToStream(...)` so source file URLs become
80
- browser-loadable asset URLs. Keep this resolution in the render helper so component modules do not
81
- hard-code deployment-specific asset paths:
68
+ On the server, provide `resolveClientEntry` to `renderToStream(...)` so source file URLs become browser-loadable asset URLs. Keep this resolution in the render helper so component modules do not hard-code deployment-specific asset paths:
82
69
 
83
70
  ```tsx
84
71
  let stream = renderToStream(<App />, {
@@ -96,21 +83,15 @@ let stream = renderToStream(<App />, {
96
83
  })
97
84
  ```
98
85
 
99
- If the module export name differs from the component function name, include `#ExportName` in the
100
- entry ID or return the exact export name from `resolveClientEntry`. A render helper that only
101
- supports source-owned entries can also fail fast when `entryId` is not a `file://` URL.
86
+ If the module export name differs from the component function name, include `#ExportName` in the entry ID or return the exact export name from `resolveClientEntry`. A render helper that only supports source-owned entries can also fail fast when `entryId` is not a `file://` URL.
102
87
 
103
- On the server, `clientEntry` components render like any other component. The server wraps their
104
- output in comment markers and serializes props into a `<script type="application/json">` tag.
88
+ On the server, `clientEntry` components render like any other component. The server wraps their output in comment markers and serializes props into a `<script type="application/json">` tag.
105
89
 
106
- Client entry props must be serializable: strings, numbers, booleans, `null`, `undefined`, plain
107
- objects/arrays of the above, JSX elements, and `<Frame>` elements. Functions and class instances
108
- cannot be passed.
90
+ Client entry props must be serializable: strings, numbers, booleans, `null`, `undefined`, plain objects/arrays of the above, JSX elements, and `<Frame>` elements. Functions and class instances cannot be passed.
109
91
 
110
92
  ## Booting the Client
111
93
 
112
- Use `run` to start the client runtime. It scans the document for client entry markers, loads
113
- modules, and hydrates each one:
94
+ Use `run` to start the client runtime. It scans the document for client entry markers, loads modules, and hydrates each one:
114
95
 
115
96
  ```tsx
116
97
  import { run } from 'remix/ui'
@@ -137,10 +118,8 @@ await app.ready()
137
118
 
138
119
  ### `run` options
139
120
 
140
- - **`loadModule(moduleUrl, exportName)`** (required) — return the component function for each
141
- client entry. Typically uses dynamic `import()`.
142
- - **`resolveFrame(src, signal, target)`** (optional) — called when a `<Frame>` loads or reloads
143
- content. `target` is available when frame targeting matters.
121
+ - **`loadModule(moduleUrl, exportName)`** (required) — return the component function for each client entry. Typically uses dynamic `import()`.
122
+ - **`resolveFrame(src, signal, target)`** (optional) — called when a `<Frame>` loads or reloads content. `target` is available when frame targeting matters.
144
123
 
145
124
  ### `app` methods
146
125
 
@@ -152,8 +131,7 @@ await app.ready()
152
131
 
153
132
  ## Frames
154
133
 
155
- A `<Frame>` renders server content into the page. Frames stream after the initial HTML, nest inside
156
- other frames, contain client entries, and can be reloaded without full page navigation.
134
+ A `<Frame>` renders server content into the page. Frames stream after the initial HTML, nest inside other frames, contain client entries, and can be reloaded without full page navigation.
157
135
 
158
136
  ```tsx
159
137
  import { Frame } from 'remix/ui'
@@ -177,10 +155,8 @@ function App() {
177
155
 
178
156
  ### Blocking vs non-blocking
179
157
 
180
- - **Without `fallback`** (blocking) — the server waits for frame content before sending the initial
181
- HTML chunk
182
- - **With `fallback`** (non-blocking) — the fallback renders immediately; real content streams in
183
- later and replaces it
158
+ - **Without `fallback`** (blocking) — the server waits for frame content before sending the initial HTML chunk
159
+ - **With `fallback`** (non-blocking) — the fallback renders immediately; real content streams in later and replaces it
184
160
 
185
161
  ### Reloading frames
186
162
 
@@ -197,21 +173,17 @@ await handle.frames.get('cart-summary')?.reload()
197
173
  handle.frames.top.reload()
198
174
  ```
199
175
 
200
- When a frame reloads, matching DOM nodes are updated in place. Client entries receive updated props
201
- while preserving their local component state.
176
+ When a frame reloads, matching DOM nodes are updated in place. Client entries receive updated props while preserving their local component state.
202
177
 
203
178
  ### Nested frames
204
179
 
205
- Frames can nest. Each frame owns its own DOM region and hydrates client entries independently.
206
- During SSR, `handle.frame.src` points at the frame being rendered, while
207
- `handle.frames.top.src` stays fixed at the outer document URL.
180
+ Frames can nest. Each frame owns its own DOM region and hydrates client entries independently. During SSR, `handle.frame.src` points at the frame being rendered, while `handle.frames.top.src` stays fixed at the outer document URL.
208
181
 
209
182
  ## Server Rendering
210
183
 
211
184
  ### `renderToStream`
212
185
 
213
- Renders a component tree to a `ReadableStream<Uint8Array>`. Sends initial HTML immediately and
214
- streams frame content as it resolves:
186
+ Renders a component tree to a `ReadableStream<Uint8Array>`. Sends initial HTML immediately and streams frame content as it resolves:
215
187
 
216
188
  ```tsx
217
189
  import { renderToStream } from 'remix/ui/server'
@@ -235,11 +207,8 @@ return new Response(stream, {
235
207
  Options:
236
208
 
237
209
  - **`frameSrc`** — seeds SSR frame state; populates `handle.frame.src` and `handle.frames.top.src`
238
- - **`topFrameSrc`** — overrides the root frame URL for nested frame renders (carry forward from
239
- `resolveFrame` context)
240
- - **`resolveFrame(src, target, context)`** — return HTML string, `ReadableStream<Uint8Array>`, or a
241
- promise of either. `context.currentFrameSrc` is the containing frame URL; `context.topFrameSrc`
242
- is the outer document URL
210
+ - **`topFrameSrc`** — overrides the root frame URL for nested frame renders (carry forward from `resolveFrame` context)
211
+ - **`resolveFrame(src, target, context)`** — return HTML string, `ReadableStream<Uint8Array>`, or a promise of either. `context.currentFrameSrc` is the containing frame URL; `context.topFrameSrc` is the outer document URL
243
212
  - **`onError(error)`** — called on rendering errors
244
213
 
245
214
  ### `renderToString`
@@ -253,8 +222,7 @@ let html = await renderToString(<App />)
253
222
 
254
223
  ### CSS in SSR
255
224
 
256
- Components using the `css` mixin have styles collected during rendering and emitted as a single
257
- `<style>` tag in `<head>`. No client-side style injection needed.
225
+ Components using the `css` mixin have styles collected during rendering and emitted as a single `<style>` tag in `<head>`. No client-side style injection needed.
258
226
 
259
227
  ## Navigation
260
228
 
@@ -293,5 +261,4 @@ function App() {
293
261
  }
294
262
  ```
295
263
 
296
- Put `title`, `meta`, `link`, and `style` tags inside an explicit `<head>`. Bare head-like tags
297
- rendered outside `<head>` stay where they are — they are not moved into the document head for you.
264
+ Put `title`, `meta`, `link`, and `style` tags inside an explicit `<head>`. Bare head-like tags rendered outside `<head>` stay where they are — they are not moved into the document head for you.
@@ -2,22 +2,18 @@
2
2
 
3
3
  ## What This Covers
4
4
 
5
- How to compose the request lifecycle and bridge the router to a runtime. Read this when the task
6
- involves:
5
+ How to compose the request lifecycle and bridge the router to a runtime. Read this when the task involves:
7
6
 
8
- - Choosing or ordering built-in middleware in the root stack
7
+ - Choosing or ordering built-in middleware in the stack
9
8
  - Writing custom middleware that sets typed context values
10
- - Adding fast-exit handling (static files, CORS preflights) versus request-enriching layers
11
- (sessions, auth, data loading)
9
+ - Adding fast-exit handling (static files, CORS preflights) versus request-enriching layers (sessions, auth, data loading)
12
10
  - Choosing when to keep the generated Node server versus switching server adapters
13
11
 
14
- For data and persistence specifics, see `data-and-validation.md`. For session and auth specifics,
15
- see `auth-and-sessions.md`.
12
+ For data and persistence specifics, see `data-and-validation.md`. For session and auth specifics, see `auth-and-sessions.md`.
16
13
 
17
14
  ## Middleware Stack
18
15
 
19
- Middleware runs in order for every request. Place fast-exit middleware (static files) early and
20
- request-enriching middleware (session, auth) later.
16
+ Middleware runs in order for every request. Place fast-exit middleware (static files) early and request-enriching middleware (session, auth) later.
21
17
 
22
18
  Recommended ordering:
23
19
 
@@ -54,7 +50,7 @@ let router = createRouter({ middleware })
54
50
  | Middleware | Import | Use when | Notes |
55
51
  | -------------------------- | ---------------------------------- | ----------------------------------------------------------------------------- | -------------------------------------------------------------- |
56
52
  | `staticFiles(dir, opts?)` | `remix/middleware/static` | Serve files from `public/` or another directory exactly as they exist on disk | Fast exit; usually near the top |
57
- | `compression()` | `remix/middleware/compression` | Compress text-like responses | Usually global |
53
+ | `compression()` | `remix/middleware/compression` | Compress text-like responses | Usually app-wide |
58
54
  | `logger()` | `remix/middleware/logger` | Log requests and responses | Often development-only; `colors` can force color output on/off |
59
55
  | `cors(opts?)` | `remix/middleware/cors` | Endpoints must serve cross-origin browsers or preflight `OPTIONS` requests | Usually early so preflights can short-circuit |
60
56
  | `cop(opts?)` | `remix/middleware/cop` | Reject unsafe cross-origin browser requests without synchronizer tokens | Put before session or CSRF when used |
@@ -64,33 +60,26 @@ let router = createRouter({ middleware })
64
60
  | `csrf(opts?)` | `remix/middleware/csrf` | Session-backed form workflows need synchronizer-token CSRF protection | Requires `session()` before it |
65
61
  | `asyncContext()` | `remix/middleware/async-context` | Helpers outside handlers need request context via `getContext()` | Add before helpers rely on it |
66
62
  | `auth({ schemes })` | `remix/middleware/auth` | Resolve auth state into `context.get(Auth)` | Run after `session()` for session-backed auth |
67
- | `requireAuth()` | `remix/middleware/auth` | A controller or action must reject anonymous access | Usually controller-level or action-level, not global |
63
+ | `requireAuth()` | `remix/middleware/auth` | A controller or action must reject anonymous access | Usually controller middleware or action middleware |
68
64
 
69
65
  ### Static files vs browser modules
70
66
 
71
- - Use `staticFiles()` for files that should be served directly from disk, such as images, fonts,
72
- or already-built assets in `public/`
73
- - Use `remix/assets` when browser modules should be compiled and served from source files with
74
- import rewriting, preloads, or fingerprinted URLs
67
+ - Use `staticFiles()` for files that should be served directly from disk, such as images, fonts, or already-built assets in `public/`
68
+ - Use `remix/assets` when browser modules should be compiled and served from source files with import rewriting, preloads, or fingerprinted URLs
75
69
 
76
70
  ### Ordering notes
77
71
 
78
72
  - Put fast exits early: `staticFiles()`, `cors()` preflight handling, and `cop()` when used
79
- - Parse request bodies before middleware that depends on them, such as `methodOverride()` and form
80
- field token extraction in `csrf()`
73
+ - Parse request bodies before middleware that depends on them, such as `methodOverride()` and form field token extraction in `csrf()`
81
74
  - Run `session()` before `csrf()` and before session-backed `auth()`
82
75
  - Add `asyncContext()` before helpers or shared code call `getContext()`
83
- - Keep route protection like `requireAuth()` at controller or action scope unless the entire app is
84
- private
76
+ - Keep route protection like `requireAuth()` as controller middleware or action middleware unless the entire app is private
85
77
 
86
78
  ### Common stacks
87
79
 
88
- - **Session-backed HTML app** -> `compression()`, `staticFiles()`, optional `cop()`, `formData()`,
89
- `methodOverride()`, `session()`, optional `csrf()`, `asyncContext()`, `auth({ schemes })`
90
- - **Cross-origin API** -> `compression()`, `cors()`, optional `asyncContext()`, optional
91
- `auth({ schemes })`
92
- - **Upload flow** -> `compression()`, `staticFiles()`, `formData({ uploadHandler })`, then
93
- sessions, auth, and data-loading middleware as needed
80
+ - **Session-backed HTML app** -> `compression()`, `staticFiles()`, optional `cop()`, `formData()`, `methodOverride()`, `session()`, optional `csrf()`, `asyncContext()`, `auth({ schemes })`
81
+ - **Cross-origin API** -> `compression()`, `cors()`, optional `asyncContext()`, optional `auth({ schemes })`
82
+ - **Upload flow** -> `compression()`, `staticFiles()`, `formData({ uploadHandler })`, then sessions, auth, and data-loading middleware as needed
94
83
 
95
84
  ### Middleware with options
96
85
 
@@ -115,14 +104,11 @@ formData({
115
104
  })
116
105
  ```
117
106
 
118
- Errors thrown or rejected by `uploadHandler` propagate directly. Catch domain-specific upload
119
- errors at the route boundary when they should become user-facing `Response` objects.
107
+ Errors thrown or rejected by `uploadHandler` propagate directly. Catch domain-specific upload errors at the route boundary when they should become user-facing `Response` objects.
120
108
 
121
109
  ## Writing Custom Middleware
122
110
 
123
- Middleware is a function that receives `(context, next)`. Return a `Response` to short-circuit, call
124
- and return `next()` when you need the downstream response, or return nothing when you only set
125
- context and want the router to continue automatically.
111
+ Middleware is a function that receives `(context, next)`. Return a `Response` to short-circuit, call and return `next()` when you need the downstream response, or return nothing when you only set context and want the router to continue automatically.
126
112
 
127
113
  ### Setting context values
128
114
 
@@ -158,9 +144,7 @@ export function requireAdmin(): Middleware {
158
144
 
159
145
  ### Async context for helpers
160
146
 
161
- `asyncContext()` stores the request context in `AsyncLocalStorage` so helpers can reach it
162
- without the context being threaded through every call. Wrap `getContext()` in app-specific
163
- helpers:
147
+ `asyncContext()` stores the request context in `AsyncLocalStorage` so helpers can reach it without the context being threaded through every call. Wrap `getContext()` in app-specific helpers:
164
148
 
165
149
  ```typescript
166
150
  // app/utils/context.ts
@@ -191,17 +175,17 @@ export function getCurrentUserSafely() {
191
175
  }
192
176
  ```
193
177
 
194
- ## Middleware Layers
178
+ ## Middleware Types
195
179
 
196
- Middleware can be applied at three levels:
180
+ Middleware has three API-owned forms:
197
181
 
198
- 1. **Router-level** — runs for every request:
182
+ 1. **Router middleware** — runs for every request:
199
183
 
200
184
  ```typescript
201
- let router = createRouter({ middleware: [...] })
185
+ let router = createRouter({ middleware: [logger(), session(cookie, storage)] })
202
186
  ```
203
187
 
204
- 2. **Controller-level** — runs for the direct actions in one controller:
188
+ 2. **Controller middleware** — runs for the direct actions in one controller:
205
189
 
206
190
  ```typescript
207
191
  export default createController(routes.account, {
@@ -210,23 +194,23 @@ Middleware can be applied at three levels:
210
194
  })
211
195
  ```
212
196
 
213
- Controller middleware does not flow into other controllers. Add the middleware to each
214
- controller that needs it.
197
+ Controller middleware does not flow into other controllers. Add the middleware to each controller that needs it.
198
+
199
+ 3. **Action middleware** — runs for a single action:
215
200
 
216
- 3. **Action-level** — runs for a single route:
217
201
  ```typescript
218
202
  router.get(routes.account.index, {
219
203
  middleware: [requireAuth()],
220
- handler: accountAction.handler,
204
+ handler(context) {
205
+ return render(<AccountPage identity={context.auth.identity} />)
206
+ },
221
207
  })
222
208
  ```
223
209
 
210
+ Prefer inline arrays for `middleware` options. Use `RouterContext<typeof router>` to derive an app context from a router that uses inline middleware. Use `createMiddleware()` only when a chain is stored in a variable and its exact tuple type needs to be preserved, such as when deriving `MiddlewareContext<typeof rootMiddleware>` without a router value, exporting a reusable chain, or returning a chain from a factory.
211
+
224
212
  ## Node Server Setup
225
213
 
226
- New apps already include a `server.ts` that adapts the app router with
227
- `remix/node-fetch-server`. Keep that generated server unless the task specifically needs to change
228
- runtime behavior such as host/protocol handling, TLS, HTTP/2, WebSockets, deployment lifecycle, or
229
- test-only server setup.
214
+ New apps already include a `server.ts` that adapts the app router with `remix/node-fetch-server`. Keep that generated server unless the task specifically needs to change runtime behavior such as host/protocol handling, TLS, HTTP/2, WebSockets, deployment lifecycle, or test-only server setup.
230
215
 
231
- Use `remix/node-fetch-server` when you want to keep owning a standard Node `http`, `https`, or
232
- `http2` server directly.
216
+ Use `remix/node-fetch-server` when you want to keep owning a standard Node `http`, `https`, or `http2` server directly.
@@ -2,8 +2,7 @@
2
2
 
3
3
  ## What This Covers
4
4
 
5
- How to attach behavior, styles, and DOM-aware setup to host elements with `mix`. Read this when the
6
- task involves:
5
+ How to attach behavior, styles, and DOM-aware setup to host elements with `mix`. Read this when the task involves:
7
6
 
8
7
  - DOM event handling with `on(...)`
9
8
  - Static styling with `css(...)` and dynamic styling with `style`
@@ -12,18 +11,13 @@ task involves:
12
11
  - Native click, pointer, and keyboard behavior with `on(...)`, plus attributes with `attrs(...)`
13
12
  - Element-level animation mixins from `remix/ui/animation`
14
13
 
15
- For richer animation work (springs, tweens, layout transitions), see `animate-elements.md`. For
16
- authoring custom mixins, see `create-mixins.md`. For component lifecycle and updates, see
17
- `component-model.md`.
14
+ For richer animation work (springs, tweens, layout transitions), see `animate-elements.md`. For authoring custom mixins, see `create-mixins.md`. For component lifecycle and updates, see `component-model.md`.
18
15
 
19
- Compose behavior on host elements with `mix`. Pass a single mixin directly (`mix={on(...)}`), or
20
- an array when composing multiple mixins (`mix={[css(...), on(...)]}`). Core mixins are imported
21
- from `remix/ui`; animation mixins are imported from `remix/ui/animation`.
16
+ Compose behavior on host elements with `mix`. Pass a single mixin directly (`mix={on(...)}`), or an array when composing multiple mixins (`mix={[css(...), on(...)]}`). Core mixins are imported from `remix/ui`; animation mixins are imported from `remix/ui/animation`.
22
17
 
23
18
  ## `on(type, handler, capture?)`
24
19
 
25
- Attaches a typed DOM event handler. The handler receives the event and an `AbortSignal` that aborts
26
- when the handler is re-entered or the component is removed — this prevents race conditions:
20
+ Attaches a typed DOM event handler. The handler receives the event and an `AbortSignal` that aborts when the handler is re-entered or the component is removed — this prevents race conditions:
27
21
 
28
22
  ```tsx
29
23
  <input
@@ -56,9 +50,7 @@ Multiple events on the same element:
56
50
 
57
51
  ## `css(styles)`
58
52
 
59
- Applies generated class names for CSS object styles. Produces static CSS rules inserted into the
60
- document. Supports pseudo-selectors, pseudo-elements, attribute selectors, descendant selectors, and
61
- media queries using `&` to reference the current element:
53
+ Applies generated class names for CSS object styles. Produces static CSS rules inserted into the document. Supports pseudo-selectors, pseudo-elements, attribute selectors, descendant selectors, and media queries using `&` to reference the current element:
62
54
 
63
55
  ```tsx
64
56
  <button
@@ -80,9 +72,7 @@ media queries using `&` to reference the current element:
80
72
 
81
73
  ### `css(...)` vs `style` prop
82
74
 
83
- Use `css(...)` for static styles, selectors, and media queries. Use `style` for dynamic values that
84
- change often. Prefer CSS nested selectors for parent-state-affects-children over managing hover/focus
85
- state in JavaScript:
75
+ Use `css(...)` for static styles, selectors, and media queries. Use `style` for dynamic values that change often. Prefer CSS nested selectors for parent-state-affects-children over managing hover/focus state in JavaScript:
86
76
 
87
77
  ```tsx
88
78
  <div
@@ -96,8 +86,7 @@ state in JavaScript:
96
86
 
97
87
  ## `ref(callback)`
98
88
 
99
- Calls a callback when an element is inserted. The callback receives the DOM node and an
100
- `AbortSignal` that aborts when the element is removed:
89
+ Calls a callback when an element is inserted. The callback receives the DOM node and an `AbortSignal` that aborts when the element is removed:
101
90
 
102
91
  ```tsx
103
92
  <input mix={ref((node) => node.focus())} />
@@ -116,8 +105,7 @@ The `ref` callback runs once when the element is first rendered, not on every up
116
105
 
117
106
  ## `link(href, options?)`
118
107
 
119
- Adds client-side navigation behavior to any element. Makes non-anchor elements behave like Remix
120
- navigation links:
108
+ Adds client-side navigation behavior to any element. Makes non-anchor elements behave like Remix navigation links:
121
109
 
122
110
  ```tsx
123
111
  <article mix={link('/courses/intro')}>
@@ -125,20 +113,17 @@ navigation links:
125
113
  </article>
126
114
  ```
127
115
 
128
- Options match `NavigationOptions`: `src`, `target`, `history` (`'push' | 'replace'`),
129
- `resetScroll`.
116
+ Options match `NavigationOptions`: `src`, `target`, `history` (`'push' | 'replace'`), `resetScroll`.
130
117
 
131
118
  ## Native press and keyboard interactions
132
119
 
133
- Use native DOM events directly with `on(...)`. For buttons and links, `click` already includes
134
- keyboard activation when the element has the right semantics:
120
+ Use native DOM events directly with `on(...)`. For buttons and links, `click` already includes keyboard activation when the element has the right semantics:
135
121
 
136
122
  ```tsx
137
123
  <button mix={on('click', () => doAction())}>Action</button>
138
124
  ```
139
125
 
140
- For gesture-specific behavior, compose the pointer or keyboard events the interaction actually
141
- needs:
126
+ For gesture-specific behavior, compose the pointer or keyboard events the interaction actually needs:
142
127
 
143
128
  ```tsx
144
129
  <button
@@ -177,8 +162,7 @@ Animates an element when it is inserted into the DOM. Config specifies the **sta
177
162
 
178
163
  ### `animateExit(config)`
179
164
 
180
- Animates an element when it is removed. Config specifies the **ending** style. The element is kept
181
- in the DOM until the animation completes:
165
+ Animates an element when it is removed. Config specifies the **ending** style. The element is kept in the DOM until the animation completes:
182
166
 
183
167
  ```tsx
184
168
  {
@@ -206,8 +190,6 @@ Animates layout changes (position/size) using FLIP-style transforms:
206
190
  }
207
191
  ```
208
192
 
209
- Options: `duration` (default 200ms), `easing` (default spring snappy), `size` (boolean, default
210
- true — include scale projection for size changes).
193
+ Options: `duration` (default 200ms), `easing` (default spring snappy), `size` (boolean, default true — include scale projection for size changes).
211
194
 
212
- Always key elements you expect to animate. Use `...spring(preset)` to spread `duration` and
213
- `easing` into any animation config.
195
+ Always key elements you expect to animate. Use `...spring(preset)` to spread `duration` and `easing` into any animation config.