Orientation Arc
Routing Algorithms
Rendering and JSX
Runtime Adapters
Middleware Ecosystem
Developer Helpers
System Utilities
The following files were used as context for generating this wiki page:
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 rendering mechanism is split into two primary phases: build (determining what should change) and apply (executing those changes against the real DOM).
Sources: src/jsx/dom/render.ts:497-665, src/jsx/dom/render.ts:387-481
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
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.
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.
Sources: src/jsx/dom/render.ts:462-480
jsxRendererThe 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.
// 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
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
The renderer employs several strategies to maintain performance:
InvalidCharacterError) at the point of application. This makes common-path rendering significantly faster.eventCache object pre-defines frequently used events like onClick to avoid repeated regex matching for standard DOM handlers.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, src/jsx/dom/render.ts:115-118, src/jsx/base.ts:384-405