---
title: "JSX Renderer"
description: "The JSX Renderer is the core component within the Hono framework responsible for converting JSX structures into actionable DOM elements (client-side) or serialized HTML (server-side). Unlike standa..."
last_updated: "2026-07-02T09:13:46.837936+00:00"
canonical_url: "https://www.doc0.app/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/technical/rendering-jsx/jsx-renderer"
---

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [src/jsx/dom/render.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/render.ts)
- [src/context.ts](https://github.com/blade47/hono/blob/main/src/context.ts)
- [src/jsx/base.ts](https://github.com/blade47/hono/blob/main/src/jsx/base.ts)
- [src/jsx/components.ts](https://github.com/blade47/hono/blob/main/src/jsx/components.ts)
- [src/jsx/streaming.ts](https://github.com/blade47/hono/blob/main/src/jsx/streaming.ts)
- [package.json](https://github.com/blade47/hono/blob/main/package.json)
- [src/jsx/dom/intrinsic-element/components.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/intrinsic-element/components.ts)
- [src/jsx/jsx-runtime.ts](https://github.com/blade47/hono/blob/main/src/jsx/jsx-runtime.ts)
- [src/middleware/jsx-renderer/index.ts](https://github.com/blade47/hono/blob/main/src/middleware/jsx-renderer/index.ts)
- [src/jsx/intrinsic-element/components.ts](https://github.com/blade47/hono/blob/main/src/jsx/intrinsic-element/components.ts)
- [src/jsx/context.ts](https://github.com/blade47/hono/blob/main/src/jsx/context.ts)
- [src/jsx/dom/client.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/client.ts)
- [src/utils/html.ts](https://github.com/blade47/hono/blob/main/src/utils/html.ts)
- [src/jsx/jsx-dev-runtime.ts](https://github.com/blade47/hono/blob/main/src/jsx/jsx-dev-runtime.ts)
- [src/jsx/dom/jsx-dev-runtime.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/jsx-dev-runtime.ts)
- [src/jsx/index.ts](https://github.com/blade47/hono/blob/main/src/jsx/index.ts)
- [src/jsx/dom/jsx-runtime.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/jsx-runtime.ts)
- [src/helper/html/index.ts](https://github.com/blade47/hono/blob/main/src/helper/html/index.ts)
- [src/jsx/dom/server.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/server.ts)
- [src/jsx/dom/css.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/css.ts)
- [src/jsx/dom/index.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/index.ts)
- [runtime-tests/deno-jsx/deno.react-jsx.json](https://github.com/blade47/hono/blob/main/runtime-tests/deno-jsx/deno.react-jsx.json)
- [runtime-tests/deno-jsx/deno.precompile.json](https://github.com/blade47/hono/blob/main/runtime-tests/deno-jsx/deno.precompile.json)
- [src/jsx/dom/components.ts](https://github.com/blade47/hono/blob/main/src/jsx/dom/components.ts)
- [runtime-tests/deno/deno.json](https://github.com/blade47/hono/blob/main/runtime-tests/deno/deno.json)
- [jsr.json](https://github.com/blade47/hono/blob/main/jsr.json)
- [src/jsx/types.ts](https://github.com/blade47/hono/blob/main/src/jsx/types.ts)
- [src/jsx/intrinsic-elements.ts](https://github.com/blade47/hono/blob/main/src/jsx/intrinsic-elements.ts)
</details>

The JSX Renderer is the core component within the Hono framework responsible for converting JSX structures into actionable DOM elements (client-side) or serialized HTML (server-side). Unlike standard virtual DOM libraries that might prioritize universal hydration, the Hono JSX renderer is specifically architected to be lightweight, fast, and highly compatible with Hono's middleware-based request pipeline, facilitating both traditional server-side rendering (SSR) and modern dynamic DOM updates.

At its core, the system distinguishes between a static "base" JSX representation (used for initial serialization) and a "DOM" renderer that enables reactive, stateful updates. The renderer uses a custom reconciliation process that minimizes DOM manipulation by intelligently tracking component hierarchies, context, and hook state. By leveraging specialized internal tags and efficient property application, it ensures that changes to application state translate directly into optimized instructions for the underlying web browser.

The JSX Renderer is deeply integrated into Hono's `context.ts` and middleware systems. It provides the mechanism by which handlers can respond with complex HTML structures while maintaining the ability to inject dynamic metadata or perform streaming rendering, effectively bridging the gap between static HTML generation and interactive client-side application state.

## The Reconciliation Algorithm: Build and Apply

The rendering mechanism is split into two primary phases: `build` (determining what should change) and `apply` (executing those changes against the real DOM).

```mermaid
flowchart TD
    A["Trigger Update"] --> B["build(context, node)"]
    B --> C{"Invoke Tags<br/>and Reconcile Children"}
    C --> D["Calculate<br/>vR (nodes to remove)"]
    D --> E["apply(node, container)"]
    E --> F["Update<br/>Actual DOM"]
```
Sources: [src/jsx/dom/render.ts:497-665](https://github.com/blade47/hono/blob/main/src/jsx/dom/render.ts#L497-L665), [src/jsx/dom/render.ts:387-481](https://github.com/blade47/hono/blob/main/src/jsx/dom/render.ts#L387-L481)

The `build` phase recursively traverses the component tree. When a component function is invoked, the renderer checks if its output matches the previous state. If an old version of the node exists, it performs a key-based lookup to find a match and attempts to patch properties rather than recreate elements. If no match is found, the node is marked for creation.

> [!CAUTION]
> If a node lacks a `key`, the renderer reconciles children based strictly on their `tag`. This requires caution: switching components of the same tag type but different underlying implementation can lead to stale state being preserved in the stash.

Sources: [src/jsx/dom/render.ts:541-555](https://github.com/blade47/hono/blob/main/src/jsx/dom/render.ts#L541-L555)

The `apply` phase then consumes the children lists populated by the `build` phase. It maps these internal virtual nodes to browser-native `HTMLElement` instances. For efficiency, it performs property application by comparing `attributes` against `oldAttributes`, updating event listeners (using a `getEventSpec` lookup table) and styles dynamically.

## Lifecycle and Effect Management

The renderer supports lifecycle hooks (`useEffect`, `useLayoutEffect`, `useInsertionEffect`) by batching these callbacks in the `apply` phase. Once the DOM is updated, the renderer processes the collected effects, ensuring that `useInsertionEffect` runs first, followed by `useLayoutEffect`, and finally scheduling `useEffect` inside a `requestAnimationFrame`.

| Hook Type | Timing |
| :--- | :--- |
| `useInsertionEffect` | Before DOM mutations/layouts |
| `useLayoutEffect` | After DOM updates but before paint |
| `useEffect` | After paint (scheduled via `requestAnimationFrame`) |

Sources: [src/jsx/dom/render.ts:462-480](https://github.com/blade47/hono/blob/main/src/jsx/dom/render.ts#L462-L480)

## Middleware Integration: `jsxRenderer`

The `jsxRenderer` middleware integrates the JSX rendering system into the broader Hono request lifecycle. It allows developers to register a layout component that wraps every `c.render()` call. 

```typescript
// Example of how the jsxRenderer middleware is used to register a layout
app.get(
  '/page/*',
  jsxRenderer(({ children, Layout }) => {
    return (
      <Layout>
        <body>{children}</body>
      </Layout>
    )
  })
)
```
Sources: [src/middleware/jsx-renderer/index.ts:116-129](https://github.com/blade47/hono/blob/main/src/middleware/jsx-renderer/index.ts#L116-L129)

This middleware uses the `createRenderer` function, which binds the `Context` and `Layout` to the `render` function provided to the user. When `c.render()` is called, it constructs the component tree with a `RequestContext.Provider`, ensuring that downstream components can access the `Hono` context object directly via `useRequestContext()`.

Sources: [src/middleware/jsx-renderer/index.ts:33-80](https://github.com/blade47/hono/blob/main/src/middleware/jsx-renderer/index.ts#L33-L80)

## Performance Considerations

The renderer employs several strategies to maintain performance:
1. **Try-Catch Attribute Validation**: Instead of regex-validating every attribute name before application, the renderer applies them and only traps errors (e.g., `InvalidCharacterError`) at the point of application. This makes common-path rendering significantly faster.
2. **Event Caching**: The `eventCache` object pre-defines frequently used events like `onClick` to avoid repeated regex matching for standard DOM handlers.
3. **Memoization Support**: The `memo` utility uses a `DOM_MEMO` property on components. The reconciler checks this function before proceeding with a sub-tree update, allowing components to skip rendering entirely if properties remain stable.

Sources: [src/jsx/dom/render.ts:158-163](https://github.com/blade47/hono/blob/main/src/jsx/dom/render.ts#L158-L163), [src/jsx/dom/render.ts:115-118](https://github.com/blade47/hono/blob/main/src/jsx/dom/render.ts#L115-L118), [src/jsx/base.ts:384-405](https://github.com/blade47/hono/blob/main/src/jsx/base.ts#L384-L405)

## Related

- [DOM Rendering](https://www.doc0.app/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/technical/rendering-jsx/dom-rendering)
- [Streaming Utilities](https://www.doc0.app/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/technical/rendering-jsx/streaming-utilities)


## Sitemap

See the full [sitemap](https://www.doc0.app/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/llms.txt) for all pages in this wiki.
