Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Vue 3 debugging reference for reactivity issues, computed errors, watcher bugs, async failures, and SSR hydration problems.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
reference/rendering-resolve-component-for-string-names.md
1---2title: Use resolveComponent for String Component Names in Render Functions3impact: HIGH4impactDescription: String component names don't work in Vue 3 render functions; causes silent failures or runtime errors5type: gotcha6tags: [vue3, render-function, components, resolveComponent, migration]7---89# Use resolveComponent for String Component Names in Render Functions1011**Impact: HIGH** - In Vue 2, render functions could use string names for globally or locally registered components. In Vue 3, you must either import components directly or use `resolveComponent()`. Using string names causes components to render as HTML elements or fail silently.1213## Task Checklist1415- [ ] Import components directly when possible (preferred)16- [ ] Use `resolveComponent()` for dynamically registered components17- [ ] Use `resolveDynamicComponent()` for `<component :is="">` equivalent18- [ ] Call `resolveComponent()` inside `setup()` or the render function19- [ ] Handle the case when component is not found2021**Incorrect:**22```js23import { h } from 'vue'2425export default {26render() {27// WRONG: String names don't resolve to components28return h('div', [29h('my-component', { value: 1 }), // Renders <my-component> HTML element!30h('router-link', { to: '/' }, 'Home') // Also fails31])32}33}34```3536**Correct (Direct Import - Preferred):**37```js38import { h } from 'vue'39import MyComponent from './MyComponent.vue'40import { RouterLink } from 'vue-router'4142export default {43render() {44return h('div', [45h(MyComponent, { value: 1 }),46h(RouterLink, { to: '/' }, () => 'Home')47])48}49}50```5152**Correct (resolveComponent for Registered Components):**53```js54import { h, resolveComponent } from 'vue'5556export default {57components: {58MyComponent: () => import('./MyComponent.vue')59},6061setup() {62// Resolve inside setup - component context is available63const MyComponent = resolveComponent('MyComponent')6465return () => h('div', [66h(MyComponent, { value: 1 })67])68}69}7071// Or resolve inside render function72export default {73render() {74const MyComponent = resolveComponent('MyComponent')75const RouterLink = resolveComponent('RouterLink')7677return h('div', [78h(MyComponent, { value: 1 }),79h(RouterLink, { to: '/' }, () => 'Home')80])81}82}83```8485## When to Use Each Approach8687| Approach | Use When |88|----------|----------|89| Direct Import | Component is known at build time (most common) |90| `resolveComponent()` | Component is registered globally or locally by name |91| `resolveComponent()` | Dynamic component selection from registered set |9293## Handling Missing Components9495```js96import { h, resolveComponent } from 'vue'9798export default {99setup() {100// resolveComponent returns the component or the string name if not found101const DynamicComponent = resolveComponent('MaybeRegistered')102103// Check if resolution succeeded104if (typeof DynamicComponent === 'string') {105console.warn(`Component "${DynamicComponent}" not found`)106}107108return () => h(DynamicComponent, { value: 1 })109}110}111```112113## Dynamic Component Selection114115```js116import { h, resolveComponent, computed } from 'vue'117118export default {119props: ['componentName'],120121setup(props) {122// For truly dynamic components, resolve in render function123return () => {124const Component = resolveComponent(props.componentName)125return h(Component, { /* props */ })126}127}128}129```130131For the equivalent of `<component :is="componentName">`, use `resolveDynamicComponent`:132133```js134import { h, resolveDynamicComponent } from 'vue'135136export default {137props: ['componentType'],138setup(props) {139return () => {140// Resolves string names, component objects, or built-in elements141const component = resolveDynamicComponent(props.componentType)142return h(component, { /* props */ })143}144}145}146```147148## Practical Example: Tab Component149150```js151import { h, resolveComponent, ref } from 'vue'152153export default {154setup() {155const currentTab = ref('TabA')156const tabs = ['TabA', 'TabB', 'TabC']157158return () => h('div', [159// Tab buttons160h('div', { class: 'tabs' },161tabs.map(tab =>162h('button', {163key: tab,164class: { active: currentTab.value === tab },165onClick: () => currentTab.value = tab166}, tab)167)168),169170// Dynamic component based on current tab171h(resolveComponent(currentTab.value))172])173}174}175```176177## Resolving Built-in Components178179For built-in components like `<Transition>` or `<KeepAlive>`, import them directly from Vue:180181```js182import { h, Transition, KeepAlive, Teleport, Suspense } from 'vue'183184export default {185setup() {186return () => h(Transition, { name: 'fade' }, () =>187h('div', 'Content')188)189}190}191```192193## Resolving Directives194195Similar pattern for custom directives:196197```js198import { h, resolveDirective, withDirectives } from 'vue'199200export default {201render() {202const vFocus = resolveDirective('focus')203204return withDirectives(205h('input', { type: 'text' }),206[[vFocus]]207)208}209}210```211212## Migration from Vue 2213214```js215// Vue 2 (worked with registered components)216render(h) {217return h('my-component', { props: { value: 1 } })218}219220// Vue 3 (must resolve or import)221import { h, resolveComponent } from 'vue'222223render() {224const MyComponent = resolveComponent('my-component')225return h(MyComponent, { value: 1 }) // Note: props go directly, not in 'props' key226}227```228229## Reference230- [Vue 3 Migration - Render Function API](https://v3-migration.vuejs.org/breaking-changes/render-function-api.html)231- [Vue.js Render Function API - resolveComponent](https://vuejs.org/api/render-function.html#resolvecomponent)232