Nexted Layouts

If you are using the JSX Renderer middleware, you can nest layouts using <Layout />.

import { const jsxRenderer: (component?: ComponentWithChildren, options?: RendererOptions) => MiddlewareHandler
JSX Renderer Middleware for hono.
@see{@link https://hono.dev/docs/middleware/builtin/jsx-renderer}@paramcomponent - The component to render, which can accept children and props.@paramoptions - The options for the JSX renderer middleware.@paramoptions.docType - The DOCTYPE to be added at the beginning of the HTML. If set to false, no DOCTYPE will be added.@paramoptions.stream - If set to true, enables streaming response with default headers. If a record is provided, custom headers will be used.@returnsThe middleware handler function.@example```ts const app = new Hono() app.get( '/page/*', jsxRenderer(({ children }) => { return ( <html> <body> <header>Menu</header> <div>{children}</div> </body> </html> ) }) ) app.get('/page/about', (c) => { return c.render(<h1>About me!</h1>) }) ```
jsxRenderer
} from 'hono/jsx-renderer'
export default function jsxRenderer(component?: ComponentWithChildren, options?: RendererOptions): MiddlewareHandler
JSX Renderer Middleware for hono.
@see{@link https://hono.dev/docs/middleware/builtin/jsx-renderer}@paramcomponent - The component to render, which can accept children and props.@paramoptions - The options for the JSX renderer middleware.@paramoptions.docType - The DOCTYPE to be added at the beginning of the HTML. If set to false, no DOCTYPE will be added.@paramoptions.stream - If set to true, enables streaming response with default headers. If a record is provided, custom headers will be used.@returnsThe middleware handler function.@example```ts const app = new Hono() app.get( '/page/*', jsxRenderer(({ children }) => { return ( <html> <body> <header>Menu</header> <div>{children}</div> </body> </html> ) }) ) app.get('/page/about', (c) => { return c.render(<h1>About me!</h1>) }) ```
jsxRenderer
(({ children: Childchildren, type Layout: FCLayout }) => {
return ( <type Layout: FCLayout> <JSX.IntrinsicElements.nav: JSX.HTMLAttributesnav>Posts Menu</JSX.IntrinsicElements.nav: JSX.HTMLAttributesnav> <JSX.IntrinsicElements.div: JSX.HTMLAttributesdiv>{children: Childchildren}</JSX.IntrinsicElements.div: JSX.HTMLAttributesdiv> </type Layout: FCLayout> ) })

Passing Additional Props in Nested Layouts

Props passed to nested renderers do not automatically propagate to the parent renderers. To ensure that the parent layouts receive the necessary props, you should explicitly pass them from the nested <Layout /> component. Here's how you can achieve that:

Let's start with our route handler:

import type { class Context<E extends Env = any, P extends string = any, I extends Input = {}>Context } from 'hono'
declare module 'hono' {
  interface ContextRenderer {
    (
      content: string | Promise<string>content: string | interface Promise<T>
Represents the completion of an asynchronous operation
Promise
<string>,
props: {
    title: string;
}
props
: { title: stringtitle: string }
): Response } } import { const createRoute: CreateHandlersInterface<Env, any>createRoute } from 'honox/factory' export default createRoute<{}, Response, any>(handler1: H<any, any, {}, Response>): [H<any, any, {}, Response>] (+9 overloads)createRoute((c: Context<any, any, {}>c: class Context<E extends Env = any, P extends string = any, I extends Input = {}>Context) => { return c: Context<any, any, {}>c.
Context<any, any, {}>.render: ContextRenderer
(content: string | Promise<string>, props: {
    title: string;
}) => Response
`.render()` can create a response within a layout.
@see{@link https://hono.dev/docs/api/context#render-setrenderer}@example```ts app.get('/', (c) => { return c.render('Hello!') }) ```
render
(<JSX.IntrinsicElements.div: JSX.HTMLAttributesdiv>Content</JSX.IntrinsicElements.div: JSX.HTMLAttributesdiv>, { title: stringtitle: 'Dashboard' })
})

Now, let's take a look at our nested renderer:

// @filename: app/routes/nested/_renderer.tsx
/** @jsx jsx */
/** @jsxImportSource hono/jsx */
import 'hono'
declare module 'hono' {
  interface ContextRenderer {
    (
      content: string | Promise<string>content: string | interface Promise<T>
Represents the completion of an asynchronous operation
Promise
<string>,
props: {
    title: string;
}
props
: { title: stringtitle: string }
): Response } } import { const jsxRenderer: (component?: ComponentWithChildren, options?: RendererOptions) => MiddlewareHandler
JSX Renderer Middleware for hono.
@see{@link https://hono.dev/docs/middleware/builtin/jsx-renderer}@paramcomponent - The component to render, which can accept children and props.@paramoptions - The options for the JSX renderer middleware.@paramoptions.docType - The DOCTYPE to be added at the beginning of the HTML. If set to false, no DOCTYPE will be added.@paramoptions.stream - If set to true, enables streaming response with default headers. If a record is provided, custom headers will be used.@returnsThe middleware handler function.@example```ts const app = new Hono() app.get( '/page/*', jsxRenderer(({ children }) => { return ( <html> <body> <header>Menu</header> <div>{children}</div> </body> </html> ) }) ) app.get('/page/about', (c) => { return c.render(<h1>About me!</h1>) }) ```
jsxRenderer
} from 'hono/jsx-renderer'
export default function jsxRenderer(component?: ComponentWithChildren, options?: RendererOptions): MiddlewareHandler
JSX Renderer Middleware for hono.
@see{@link https://hono.dev/docs/middleware/builtin/jsx-renderer}@paramcomponent - The component to render, which can accept children and props.@paramoptions - The options for the JSX renderer middleware.@paramoptions.docType - The DOCTYPE to be added at the beginning of the HTML. If set to false, no DOCTYPE will be added.@paramoptions.stream - If set to true, enables streaming response with default headers. If a record is provided, custom headers will be used.@returnsThe middleware handler function.@example```ts const app = new Hono() app.get( '/page/*', jsxRenderer(({ children }) => { return ( <html> <body> <header>Menu</header> <div>{children}</div> </body> </html> ) }) ) app.get('/page/about', (c) => { return c.render(<h1>About me!</h1>) }) ```
jsxRenderer
(({ children: Childchildren, type Layout: FCLayout, title: stringtitle }) => {
return ( <type Layout: FCLayout title: stringtitle={title: stringtitle}> {/* Pass the title prop to the parent renderer */} <JSX.IntrinsicElements.main: JSX.HTMLAttributesmain>{children: Childchildren}</JSX.IntrinsicElements.main: JSX.HTMLAttributesmain> </type Layout: FCLayout> ) })

In this setup, all the props sent to the nested renderer's <Layout /> are consumed by the parent renderer:

// @filename: app/routes/_renderer.tsx
/** @jsx jsx */
/** @jsxImportSource hono/jsx */
import 'hono'
declare module 'hono' {
  interface ContextRenderer {
    (
      content: string | Promise<string>content: string | interface Promise<T>
Represents the completion of an asynchronous operation
Promise
<string>,
props: {
    title: string;
}
props
: { title: stringtitle: string }
): Response } } import { const jsxRenderer: (component?: ComponentWithChildren, options?: RendererOptions) => MiddlewareHandler
JSX Renderer Middleware for hono.
@see{@link https://hono.dev/docs/middleware/builtin/jsx-renderer}@paramcomponent - The component to render, which can accept children and props.@paramoptions - The options for the JSX renderer middleware.@paramoptions.docType - The DOCTYPE to be added at the beginning of the HTML. If set to false, no DOCTYPE will be added.@paramoptions.stream - If set to true, enables streaming response with default headers. If a record is provided, custom headers will be used.@returnsThe middleware handler function.@example```ts const app = new Hono() app.get( '/page/*', jsxRenderer(({ children }) => { return ( <html> <body> <header>Menu</header> <div>{children}</div> </body> </html> ) }) ) app.get('/page/about', (c) => { return c.render(<h1>About me!</h1>) }) ```
jsxRenderer
} from 'hono/jsx-renderer'
export default function jsxRenderer(component?: ComponentWithChildren, options?: RendererOptions): MiddlewareHandler
JSX Renderer Middleware for hono.
@see{@link https://hono.dev/docs/middleware/builtin/jsx-renderer}@paramcomponent - The component to render, which can accept children and props.@paramoptions - The options for the JSX renderer middleware.@paramoptions.docType - The DOCTYPE to be added at the beginning of the HTML. If set to false, no DOCTYPE will be added.@paramoptions.stream - If set to true, enables streaming response with default headers. If a record is provided, custom headers will be used.@returnsThe middleware handler function.@example```ts const app = new Hono() app.get( '/page/*', jsxRenderer(({ children }) => { return ( <html> <body> <header>Menu</header> <div>{children}</div> </body> </html> ) }) ) app.get('/page/about', (c) => { return c.render(<h1>About me!</h1>) }) ```
jsxRenderer
(({ children: Childchildren, title: stringtitle }) => {
return ( <JSX.IntrinsicElements.html: HtmlHTMLAttributeshtml JSX.HTMLAttributes.lang?: string | undefinedlang='en'> <JSX.IntrinsicElements.head: JSX.HTMLAttributeshead> <JSX.IntrinsicElements.title: JSX.HTMLAttributestitle>{title: stringtitle}</JSX.IntrinsicElements.title: JSX.HTMLAttributestitle> {/* Use the title prop here */} </JSX.IntrinsicElements.head: JSX.HTMLAttributeshead> <JSX.IntrinsicElements.body: JSX.HTMLAttributesbody> {children: Childchildren} {/* Insert the Layout's children here */} </JSX.IntrinsicElements.body: JSX.HTMLAttributesbody> </JSX.IntrinsicElements.html: HtmlHTMLAttributeshtml> ) })