What Causes This Error?
This error occurs when you call withDirectives() outside of a render function context. The withDirectives helper is designed to apply directives to vnodes during the render process.
The Problem
import { h, withDirectives, resolveDirective } from 'vue'
// ❌ Called outside render context
const vFocus = resolveDirective('focus')
const vnode = withDirectives(h('input'), [[vFocus]]) // Error!
export default {
setup() {
// Component setup
}
}
The Fix
Use Inside Render Function
import { h, withDirectives, resolveDirective } from 'vue'
export default {
setup() {
// ✅ Return render function
return () => {
const vFocus = resolveDirective('focus')
return withDirectives(
h('input', { type: 'text' }),
[[vFocus]]
)
}
}
}
With JSX
import { withDirectives, resolveDirective } from 'vue'
export default {
setup() {
return () => {
const vFocus = resolveDirective('focus')
// ✅ Inside render function
return withDirectives(
<input type="text" />,
[[vFocus]]
)
}
}
}
Common Scenarios
Applying v-show
import { h, withDirectives, vShow, ref } from 'vue'
export default {
setup() {
const isVisible = ref(true)
return () => withDirectives(
h('div', 'Content'),
[[vShow, isVisible.value]]
)
}
}
Custom Directive
import { h, withDirectives, resolveDirective } from 'vue'
// Register directive first
app.directive('tooltip', {
mounted(el, binding) {
el.title = binding.value
}
})
export default {
setup() {
return () => {
const vTooltip = resolveDirective('tooltip')
return withDirectives(
h('button', 'Hover me'),
[[vTooltip, 'This is a tooltip']]
)
}
}
}
With Directive Modifiers
import { h, withDirectives, resolveDirective } from 'vue'
export default {
setup() {
return () => {
const vCustom = resolveDirective('custom')
// [directive, value, argument, modifiers]
return withDirectives(
h('div', 'Content'),
[[vCustom, 'value', 'arg', { modifier1: true, modifier2: true }]]
)
}
}
}
Multiple Directives
import { h, withDirectives, vShow, resolveDirective, ref } from 'vue'
export default {
setup() {
const isVisible = ref(true)
return () => {
const vFocus = resolveDirective('focus')
const vTooltip = resolveDirective('tooltip')
return withDirectives(
h('input', { type: 'text' }),
[
[vShow, isVisible.value],
[vFocus],
[vTooltip, 'Enter text here']
]
)
}
}
}
v-model with withDirectives
import { h, withDirectives, vModelText, ref } from 'vue'
export default {
setup() {
const text = ref('')
return () => withDirectives(
h('input', {
'onUpdate:modelValue': (val) => { text.value = val }
}),
[[vModelText, text.value]]
)
}
}
Functional Component
import { h, withDirectives, vShow } from 'vue'
// ✅ Functional component returns vnode directly
const ConditionalBox = (props, { slots }) => {
return withDirectives(
h('div', { class: 'box' }, slots.default?.()),
[[vShow, props.visible]]
)
}
ConditionalBox.props = ['visible']
Local Directive Definition
import { h, withDirectives } from 'vue'
// Define directive locally
const focusDirective = {
mounted: (el) => el.focus()
}
export default {
setup() {
return () => withDirectives(
h('input'),
[[focusDirective]] // Use directive object directly
)
}
}
Alternative: Use Template
If you don’t need render functions, use template syntax:
<template>
<!-- Simpler for most cases -->
<input v-focus v-tooltip="'Tooltip text'" />
</template>
<script setup>
// Directive will be auto-resolved
</script>
Quick Checklist
- Call
withDirectivesinside a render function - Return render function from
setup()when usingwithDirectives - Use
resolveDirective()for registered directives - Built-in directives:
vShow,vModelText,vModelCheckbox, etc. - Directive format:
[directive, value, argument, modifiers] - Consider template syntax for simpler cases