What Causes This Warning?
This warning appears when Vue encounters a component or directive in your template that hasn’t been registered or imported. Vue doesn’t recognize the element and treats it as an unknown custom element.
The Problem
<template>
<!-- ❌ MyButton is not imported or registered -->
<MyButton>Click me</MyButton>
</template>
<script setup>
// Missing import!
</script>
The Fix
Import the Component
<script setup>
// ✅ Import the component
import MyButton from './MyButton.vue'
</script>
<template>
<MyButton>Click me</MyButton>
</template>
Register Globally
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import MyButton from './components/MyButton.vue'
const app = createApp(App)
// ✅ Register globally
app.component('MyButton', MyButton)
app.mount('#app')
Register Locally (Options API)
import MyButton from './MyButton.vue'
export default {
components: {
MyButton // ✅ Registered locally
}
}
Common Scenarios
Case Sensitivity
<!-- ❌ Wrong case -->
<template>
<mybutton>Click</mybutton>
</template>
<!-- ✅ Use PascalCase or kebab-case correctly -->
<template>
<MyButton>Click</MyButton>
<!-- or -->
<my-button>Click</my-button>
</template>
Auto-Imports Not Working
// vite.config.js - Check unplugin-vue-components setup
import Components from 'unplugin-vue-components/vite'
export default {
plugins: [
Components({
// ✅ Configure component directories
dirs: ['src/components'],
// Deep search
deep: true,
// Extensions to search
extensions: ['vue'],
})
]
}
Third-Party Components
// ❌ Not imported
<template>
<ElButton>Click</ElButton>
</template>
// ✅ Import from library
import { ElButton } from 'element-plus'
// Or register globally
import ElementPlus from 'element-plus'
app.use(ElementPlus)
Dynamic Components
<script setup>
import { shallowRef } from 'vue'
import ComponentA from './ComponentA.vue'
import ComponentB from './ComponentB.vue'
// ❌ String name without registration
const current = ref('ComponentA')
// ✅ Use actual component reference
const current = shallowRef(ComponentA)
</script>
<template>
<component :is="current" />
</template>
Async Components
import { defineAsyncComponent } from 'vue'
// ✅ Correctly define async component
const AsyncModal = defineAsyncComponent(() =>
import('./Modal.vue')
)
// Use in template
<template>
<AsyncModal v-if="showModal" />
</template>
Resolve Component at Runtime
import { resolveComponent, h } from 'vue'
export default {
setup() {
return () => {
// ✅ Resolve registered component by name
const MyButton = resolveComponent('MyButton')
return h(MyButton, { onClick: handleClick }, 'Click me')
}
}
}
For Directives
<!-- ❌ Directive not registered -->
<template>
<div v-tooltip="'Hello'">Hover me</div>
</template>
<!-- ✅ Register directive -->
<script setup>
// Local directive
const vTooltip = {
mounted(el, binding) {
el.title = binding.value
}
}
</script>
// Or globally
app.directive('tooltip', {
mounted(el, binding) {
el.title = binding.value
}
})
Ignoring Custom Elements
// For web components or custom elements you don't want Vue to process
app.config.compilerOptions.isCustomElement = (tag) => {
return tag.startsWith('custom-') || tag.includes('-')
}
// vite.config.js
import vue from '@vitejs/plugin-vue'
export default {
plugins: [
vue({
template: {
compilerOptions: {
isCustomElement: (tag) => tag.startsWith('ion-')
}
}
})
]
}
Debugging Tips
// Check what components are registered
console.log(app._context.components)
// Check what directives are registered
console.log(app._context.directives)
Quick Checklist
- Import the component in your script
- Check for case sensitivity issues
- Verify file path is correct
- Check if auto-import is configured properly
- For libraries, ensure proper installation and import
- Use
resolveComponent()for dynamic component names - Configure
isCustomElementfor web components