Skip to main content
The CSS Helper is experimental. The API may change in future versions.
The CSS Helper provides CSS-in-JS functionality with automatic scoping, allowing you to write CSS directly in your TypeScript/JavaScript code.

Import

import { css, cx, keyframes, Style, createCssContext } from 'hono/css'

Functions

css()

Defines scoped CSS styles and returns a unique class name.
function css(
  strings: TemplateStringsArray,
  ...values: CssVariableType[]
): Promise<string>
strings
TemplateStringsArray
required
The CSS template string
values
CssVariableType[]
required
Values to interpolate into the CSS (variables, other css() results, etc.)
return
Promise<string>
A unique class name for the scoped styles
Example
import { Hono } from 'hono'
import { css, Style } from 'hono/css'
import { html } from 'hono/html'

const app = new Hono()

app.get('/', (c) => {
  const className = css`
    background-color: #f0f0f0;
    color: #333;
    padding: 20px;
    border-radius: 8px;
    
    &:hover {
      background-color: #e0e0e0;
    }
  `
  
  return c.html(html`
    <html>
      <head>
        ${Style()}
      </head>
      <body>
        <div class="${className}">
          Hello, styled world!
        </div>
      </body>
    </html>
  `)
})

cx()

Combines multiple class names, similar to the popular classnames library.
function cx(
  ...args: (CssClassName | Promise<string> | string | boolean | null | undefined)[]
): Promise<string>
args
(CssClassName | Promise<string> | string | boolean | null | undefined)[]
required
Class names to combine. Falsy values are ignored.
return
Promise<string>
Combined class names as a single string
Example
app.get('/button', (c) => {
  const baseStyles = css`
    padding: 10px 20px;
    border: none;
    border-radius: 4px;
    cursor: pointer;
  `
  
  const primaryStyles = css`
    background-color: #007bff;
    color: white;
  `
  
  const isActive = true
  const activeStyles = css`
    box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.5);
  `
  
  const className = cx(
    baseStyles,
    primaryStyles,
    isActive && activeStyles
  )
  
  return c.html(html`
    <html>
      <head>${Style()}</head>
      <body>
        <button class="${className}">Click me</button>
      </body>
    </html>
  `)
})

keyframes()

Defines CSS keyframe animations.
function keyframes(
  strings: TemplateStringsArray,
  ...values: CssVariableType[]
): CssClassNameCommon
strings
TemplateStringsArray
required
The keyframes template string
values
CssVariableType[]
required
Values to interpolate
return
CssClassNameCommon
A keyframes name that can be used in CSS animations
Example
import { css, keyframes, Style } from 'hono/css'
import { html } from 'hono/html'

app.get('/animation', (c) => {
  const fadeIn = keyframes`
    from {
      opacity: 0;
      transform: translateY(-10px);
    }
    to {
      opacity: 1;
      transform: translateY(0);
    }
  `
  
  const animatedBox = css`
    animation: ${fadeIn} 0.5s ease-in-out;
    padding: 20px;
    background: #007bff;
    color: white;
  `
  
  return c.html(html`
    <html>
      <head>${Style()}</head>
      <body>
        <div class="${animatedBox}">Animated content!</div>
      </body>
    </html>
  `)
})

Style()

Renders the <style> tag containing all accumulated CSS.
function Style(args?: { children?: Promise<string>; nonce?: string }): HtmlEscapedString
args.children
Promise<string>
Optional CSS content to include in the style tag
args.nonce
string
Optional nonce attribute for Content Security Policy
return
HtmlEscapedString
A style tag containing all CSS styles used in the current render
Example
app.get('/', (c) => {
  return c.html(html`
    <html>
      <head>
        <title>My App</title>
        ${Style({ nonce: 'random-nonce-123' })}
      </head>
      <body>
        <!-- Your content -->
      </body>
    </html>
  `)
})

viewTransition()

Creates styles for view transitions API.
function viewTransition(
  strings: TemplateStringsArray,
  ...values: CssVariableType[]
): Promise<string>

function viewTransition(content: Promise<string>): Promise<string>
function viewTransition(): Promise<string>
strings
TemplateStringsArray
The CSS template for view transition
values
CssVariableType[]
Values to interpolate
return
Promise<string>
A view transition name
Example
import { css, viewTransition, Style } from 'hono/css'
import { html } from 'hono/html'

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

createCssContext()

Creates an isolated CSS context with a custom style ID.
function createCssContext({ id }: { id: string }): {
  css: CssType
  cx: CxType
  keyframes: KeyframesType
  viewTransition: ViewTransitionType
  Style: StyleType
}
id
string
required
A unique identifier for the style tag
return
object
An object containing isolated versions of css, cx, keyframes, viewTransition, and Style
Example
import { createCssContext } from 'hono/css'

// Create isolated context for a specific part of your app
const { css, Style } = createCssContext({ id: 'my-component' })

app.get('/component', (c) => {
  const className = css`
    color: red;
  `
  
  return c.html(html`
    <html>
      <head>${Style()}</head>
      <body>
        <div class="${className}">Isolated styles</div>
      </body>
    </html>
  `)
})

Features

Automatic Scoping

All styles defined with css() are automatically scoped with unique class names, preventing style conflicts:
const style1 = css`color: red;`
const style2 = css`color: blue;`
// Generates unique class names like: css-abc123, css-def456

Nesting Support

Supports CSS nesting for pseudo-classes and nested selectors:
const button = css`
  padding: 10px;
  
  &:hover {
    background: #eee;
  }
  
  &.active {
    font-weight: bold;
  }
`

CSS Variables

Interpolate values and other styles:
const primaryColor = '#007bff'
const spacing = '20px'

const card = css`
  padding: ${spacing};
  background: ${primaryColor};
  border-radius: 8px;
`

Performance Considerations

  • Styles are generated on-demand during rendering
  • Duplicate styles are automatically deduplicated
  • The Style component must be included in the <head> for styles to render

Types

type CssClassName = HtmlEscapedString & CssClassNameCommon

interface CssClassNameCommon {
  [CLASS_NAME]: string
  [STYLE_STRING]: string
  [SELECTOR]: string
  [SELECTORS]: Array<{
    [CLASS_NAME]: string
    [STYLE_STRING]: string
  }>
}

type CssVariableType = string | number | CssClassNameCommon

Build docs developers (and LLMs) love