Render Functions & JSX

Write Templates in JS When You Need More Power

Render Functions & JSX

A render function returns a VNode tree directly. Useful for highly dynamic UI in libraries — reach for templates first in app code.

4 min read Level 3/5 #vue#render-functions#jsx
What you'll learn
  • Define a render function from setup
  • Use the h() helper to build VNodes
  • Optionally enable JSX with @vitejs/plugin-vue-jsx

Templates compile to render functions — but you can write them by hand. Useful when output depends on data in ways templates can’t express cleanly (libraries, framework code, dynamic tags). For everyday app code, stick with templates.

h() — The VNode Builder

h(type, props, children) creates a VNode. Returning a function from setup makes Vue use it as the component’s render.

import { defineComponent, h, ref } from 'vue'

export default defineComponent({
  setup() {
    const count = ref(0)
    return () => h(
      'div',
      { class: 'box' },
      [
        h('p', `count is ${count.value}`),
        h('button', { onClick: () => count.value++ }, '+'),
      ],
    )
  },
})

type can be a string (HTML element) or another component.

JSX

Enable JSX with the official plugin:

npm i -D @vitejs/plugin-vue-jsx
// vite.config.ts
import vueJsx from '@vitejs/plugin-vue-jsx'
export default { plugins: [vueJsx()] }

Now you can write the same component as JSX:

import { defineComponent, ref } from 'vue'

export default defineComponent({
  setup() {
    const count = ref(0)
    return () => (
      <div class="box">
        <p>count is {count.value}</p>
        <button onClick={() => count.value++}>+</button>
      </div>
    )
  },
})

When to Choose Which

  • Templates: 95% of the time. Best tooling, best perf via compile-time optimizations.
  • Render functions / JSX: when output structure depends heavily on runtime data, or when authoring components for other devs (Headless UI, design systems).
TypeScript in Vue →