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.
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).