> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/honojs/hono/llms.txt
> Use this file to discover all available pages before exploring further.

# HTML & CSS

> Template literals for HTML and CSS-in-JS styling

Hono provides helpers for writing HTML with tagged template literals and experimental CSS-in-JS functionality with scoped styles and SSR support.

## HTML Helper

The `html` helper allows you to write HTML using tagged template literals with automatic escaping.

### Import

```typescript theme={null}
import { html, raw } from 'hono/html'
```

### Basic Usage

```typescript theme={null}
import { html } from 'hono/html'

app.get('/', (c) => {
  const name = 'World'
  return c.html(
    html`
      <!DOCTYPE html>
      <html>
        <head>
          <title>Hello</title>
        </head>
        <body>
          <h1>Hello ${name}!</h1>
        </body>
      </html>
    `
  )
})
```

### Automatic Escaping

String values are automatically escaped for security:

```typescript theme={null}
import { html } from 'hono/html'

app.get('/user', (c) => {
  const userInput = '<script>alert("XSS")</script>'
  
  return c.html(
    html`
      <div>
        User input: ${userInput}
      </div>
    `
  )
})
// Output: User input: &lt;script&gt;alert(&quot;XSS&quot;)&lt;/script&gt;
```

<Info>
  Values are escaped by default to prevent XSS attacks. Use the `raw` helper only when you trust the content.
</Info>

### Raw HTML

When you need to insert unescaped HTML:

```typescript theme={null}
import { html, raw } from 'hono/html'

app.get('/article', (c) => {
  const trustedHtml = '<p>This is <strong>safe</strong> HTML</p>'
  
  return c.html(
    html`
      <div class="article">
        ${raw(trustedHtml)}
      </div>
    `
  )
})
```

<Warning>
  Only use `raw()` with trusted content. Never use it with user-generated content as it bypasses XSS protection.
</Warning>

### Value Types

The `html` helper handles various types:

```typescript theme={null}
import { html } from 'hono/html'

app.get('/types', (c) => {
  return c.html(
    html`
      <ul>
        <li>String: ${'text'}</li>
        <li>Number: ${42}</li>
        <li>Boolean: ${true}</li>
        <li>Null: ${null}</li>
        <li>Undefined: ${undefined}</li>
      </ul>
    `
  )
})
// Boolean, null, and undefined are not rendered
```

### Arrays

Arrays are automatically flattened:

```typescript theme={null}
import { html } from 'hono/html'

app.get('/list', (c) => {
  const items = ['Apple', 'Banana', 'Cherry']
  
  return c.html(
    html`
      <ul>
        ${items.map(item => html`<li>${item}</li>`)}
      </ul>
    `
  )
})
```

### Async Content

Supports Promise values for async rendering:

```typescript theme={null}
import { html } from 'hono/html'

app.get('/async', async (c) => {
  const fetchData = async () => {
    // Fetch data from API
    return 'Fetched content'
  }
  
  return c.html(
    html`
      <div>
        ${fetchData()}
      </div>
    `
  )
})
```

## CSS Helper

<Warning>
  The CSS helper is **experimental**. The API may change in future versions.
</Warning>

The CSS helper provides CSS-in-JS functionality with automatic class name generation and scoped styles.

### Import

```typescript theme={null}
import { css, cx, keyframes, Style } from 'hono/css'
```

### Basic Styling

```typescript theme={null}
import { css, Style } from 'hono/css'
import { html } from 'hono/html'

app.get('/', (c) => {
  const className = css`
    color: blue;
    font-size: 16px;
    &:hover {
      color: red;
    }
  `
  
  return c.html(
    html`
      <!DOCTYPE html>
      <html>
        <head>
          <${Style} />
        </head>
        <body>
          <h1 class="${className}">Styled text</h1>
        </body>
      </html>
    `
  )
})
```

<Note>
  The `<Style />` component must be included in the document head to inject generated styles.
</Note>

### CSS Variables

Use JavaScript variables in your styles:

```typescript theme={null}
import { css } from 'hono/css'

app.get('/dynamic', (c) => {
  const color = 'blue'
  const size = 20
  
  const className = css`
    color: ${color};
    font-size: ${size}px;
  `
  
  return c.html(html`<div class="${className}">Dynamic styling</div>`)
})
```

### Combining Classes

Use `cx` to combine multiple class names:

```typescript theme={null}
import { css, cx } from 'hono/css'

app.get('/combined', (c) => {
  const base = css`
    padding: 10px;
  `
  
  const primary = css`
    background: blue;
    color: white;
  `
  
  const className = cx(base, primary)
  
  return c.html(html`<button class="${className}">Click me</button>`)
})
```

### Conditional Classes

`cx` supports conditional classes:

```typescript theme={null}
import { css, cx } from 'hono/css'

app.get('/conditional', (c) => {
  const base = css`padding: 10px;`
  const active = css`background: blue;`
  
  const isActive = true
  const className = cx(base, isActive && active)
  
  return c.html(html`<div class="${className}">Content</div>`)
})
```

### Keyframes

Define CSS animations:

```typescript theme={null}
import { css, keyframes, Style } from 'hono/css'
import { html } from 'hono/html'

app.get('/animation', (c) => {
  const fadeIn = keyframes`
    from {
      opacity: 0;
    }
    to {
      opacity: 1;
    }
  `
  
  const className = css`
    animation: ${fadeIn} 1s ease-in;
  `
  
  return c.html(
    html`
      <!DOCTYPE html>
      <html>
        <head>
          <${Style} />
        </head>
        <body>
          <div class="${className}">Fading in...</div>
        </body>
      </html>
    `
  )
})
```

### View Transitions

Support for View Transitions API:

```typescript theme={null}
import { css, viewTransition, Style } from 'hono/css'
import { html } from 'hono/html'

app.get('/transition', (c) => {
  const transitionName = viewTransition`slide`
  
  const className = css`
    view-transition-name: ${transitionName};
  `
  
  return c.html(
    html`
      <!DOCTYPE html>
      <html>
        <head>
          <${Style} />
        </head>
        <body>
          <div class="${className}">Transitioning element</div>
        </body>
      </html>
    `
  )
})
```

### Multiple CSS Contexts

Create separate CSS contexts for isolation:

```typescript theme={null}
import { createCssContext } from 'hono/css'

const { css: css1, Style: Style1 } = createCssContext({ id: 'app1' })
const { css: css2, Style: Style2 } = createCssContext({ id: 'app2' })

app.get('/context1', (c) => {
  const className = css1`color: blue;`
  return c.html(
    html`
      <html>
        <head><${Style1} /></head>
        <body><div class="${className}">App 1</div></body>
      </html>
    `
  )
})
```

### CSP Nonce Support

Add nonce for Content Security Policy:

```typescript theme={null}
import { Style } from 'hono/css'
import { html } from 'hono/html'

app.get('/secure', (c) => {
  const nonce = 'random-nonce-value'
  
  return c.html(
    html`
      <!DOCTYPE html>
      <html>
        <head>
          <${Style} nonce="${nonce}" />
        </head>
        <body>
          <div>Secure content</div>
        </body>
      </html>
    `
  )
})
```

## Raw CSS Strings

For advanced use cases, work with raw CSS strings:

```typescript theme={null}
import { rawCssString } from 'hono/css'

const cssString = rawCssString`
  .custom {
    color: blue;
  }
`
```

## Best Practices

<CardGroup cols={2}>
  <Card title="Always Escape User Input" icon="shield">
    Use the default escaping behavior for all user-generated content
  </Card>

  <Card title="Include Style Component" icon="wand-magic-sparkles">
    Remember to add `<Style />` in the document head when using CSS helper
  </Card>

  <Card title="Reuse Classes" icon="recycle">
    Define common styles once and reuse them with `cx()`
  </Card>

  <Card title="Test Browser Support" icon="browser">
    CSS helper is experimental - test thoroughly in your target browsers
  </Card>
</CardGroup>

## Performance

<Info>
  The CSS helper automatically deduplicates styles and only injects each class once, even if used multiple times.
</Info>

## SSR Support

Both helpers work seamlessly with server-side rendering, with styles injected inline for immediate availability.
