Hono: JSX templates

We’ve previously seen how to render some HTML using c.html().

Hono lets you write your server responses as JSX, which I think it’s the optimal way of mixing HTML markup and JavaScript data.

JSX is the templating engine introduced by React, and now used in many other libraries too. React is a UI library and runs in the browser.

In this case, we have Hono that is a server-side framework.

And we use JSX to generate HTML on the server.

There is no React involved in this, except at a very low level (and transparent to you) to generate HTML from JSX.

To use JSX, we import it at the top of the index.js file:

/** @jsx jsx */
import { jsx } from 'hono/jsx'

Now we can use JSX in our Hono responses:

app.get('/', (c) => {
  const numbers = ['one', 'two', 'three']

  return c.html(
    <html>
      <head>
        <title>test</title>
      </head>
      <body>
        <h1>test</h1>
        {numbers.map((num) => (
          <p>{num}</p>
        ))}
      </body>
    </html>
  )
})

If this is the first time you see JSX, it seems strange at first, but look at what we don’t need any more: we don’t need a template literal. And we don’t need to do that annoying “HTML string building” we did before:

${numbers.map((num) => '<p>' + num + '</p>').join('\n')}

now we use a much cleaner syntax, embedding data using the {expression} syntax.

And this is just the beginning.

Because now you can start doing what JSX unlocks: components-based UI building.

We can create our first component in the file, let’s call it Numbers:

const Numbers = () => {
  const numbers = ['one', 'two', 'three']

  return (
    <div>
      {numbers.map((num) => (
        <p>{num}</p>
      ))}
    </div>
  )
}

and we can use it in the app.get('/') callback:

app.get('/', (c) => {
  return c.html(
    <html>
      <head>
        <title>test</title>
      </head>
      <body>
        <h1>test</h1>
        <Numbers />
      </body>
    </html>
  )
})

We could also pass the numbers data as a prop to the Numbers component:

const Numbers = ({ numbers }) => {
  return (
    <div>
      {numbers.map((num) => (
        <p>{num}</p>
      ))}
    </div>
  )
}

app.get('/', (c) => {
  const numbers = ['one', 'two', 'three']

  return c.html(
    <html>
      <head>
        <title>test</title>
      </head>
      <body>
        <h1>test</h1>
        <Numbers numbers={numbers} />
      </body>
    </html>
  )
})

We can also move components to different files as the application grows in complexity.

This looks like a React application, right?

Except this is server-side, so we can’t use things like useState, useEffect, and all the other frontend-facing functionality.

But it’s still a great way to build a UI on the server.

Lessons in this unit:

0: Introduction
1: Your first Hono app
2: The Request object
3: Send a response to the client
4: Manage cookies
5: Work with HTTP headers
6: Handling redirects
7: Routing
8: ▶︎ JSX templates
9: Middleware
10: Hono on Node.js