What's Actually Happening
Vue.js component is not appearing on the page. The component should render but nothing displays or errors appear.
The Error You'll See
// Console error:
[Vue warn]: Unknown custom element: <my-component> - did you register the component correctly?Template compilation error:
[Vue warn]: Error compiling template:Component not found:
Failed to mount component: template or render function not defined.No output:
<!-- Component tag in DOM but no rendered content -->
<my-component></my-component>
<!-- Empty -->Why This Happens
- 1.Component not registered - Missing local or global registration
- 2.Template syntax error - Invalid HTML or Vue template syntax
- 3.Wrong import path - Component file not found
- 4.Data not reactive - Properties added after initialization
- 5.v-if/v-show conditions - Condition preventing render
- 6.CSS hiding content - Styles hiding component
Step 1: Check Component Registration
```javascript // Vue 3 - Local registration:
// ChildComponent.vue export default { name: 'ChildComponent', template: '<div>Child</div>' }
// Parent.vue import ChildComponent from './ChildComponent.vue'
export default { components: { ChildComponent // Short for ChildComponent: ChildComponent }, template: '<ChildComponent />' }
// Vue 3 - Global registration: // main.js import { createApp } from 'vue' import App from './App.vue' import MyComponent from './MyComponent.vue'
const app = createApp(App) app.component('MyComponent', MyComponent) app.mount('#app')
// Vue 2 - Global registration: import Vue from 'vue' import MyComponent from './MyComponent.vue'
Vue.component('MyComponent', MyComponent) ```
Step 2: Verify Import Path
```javascript // Check file exists: // Wrong path: import MyComponent from './MyComponent' // Missing .vue
// Correct: import MyComponent from './MyComponent.vue'
// Check relative path: import MyComponent from '../components/MyComponent.vue'
// For TypeScript: import MyComponent from '@/components/MyComponent.vue' // With @ alias
// Check if file exports correctly: // MyComponent.vue export default { name: 'MyComponent' // Must have default export }
// Named export: export const MyComponent = { /* ... */ } // Import: import { MyComponent } from './MyComponent.vue' ```
Step 3: Check Template Syntax
```vue <template> <!-- Common errors: -->
<!-- Error: Multiple root elements (Vue 2) --> <div>One</div> <div>Two</div> <!-- Error in Vue 2 -->
<!-- Fix: Single root in Vue 2 --> <div> <div>One</div> <div>Two</div> </div>
<!-- Vue 3 supports multiple roots with fragments --> <div>One</div> <div>Two</div>
<!-- Error: Unclosed tags --> <div> <!-- Missing </div> -->
<!-- Error: Invalid v-for key --> <div v-for="item in items"> <!-- Missing :key -->
<!-- Fix: --> <div v-for="item in items" :key="item.id">
<!-- Error: Wrong v-model --> <input v-model="username"> <!-- username not in data -->
<!-- Fix: --> <input v-model="username"> <!-- username in data --> </template> ```
Step 4: Debug with Vue DevTools
```bash # Install Vue DevTools browser extension: # Chrome: https://chrome.google.com/webstore # Firefox: https://addons.mozilla.org
# Open DevTools -> Vue tab
# Check: # 1. Component appears in component tree # 2. Props values # 3. Data values # 4. Computed properties # 5. Events
# If component not in tree: # - Not mounted # - Registration issue # - Parent not rendering
# Check component state: # Click on component in tree # View all reactive data ```
Step 5: Check Reactivity Issues
```javascript // Vue 3 - Composition API: import { ref, reactive } from 'vue'
export default { setup() { // Reactive with ref: const count = ref(0)
// Reactive with reactive: const state = reactive({ name: 'Vue' })
return { count, state } } }
// Vue 2 - Reactivity pitfalls:
export default { data() { return { items: [] } }, mounted() { // BAD: Adding property after initialization this.newProperty = 'value' // Not reactive!
// FIX: Use Vue.set or this.$set this.$set(this, 'newProperty', 'value')
// Or define in data: data() { return { newProperty: null // Now reactive } }
// BAD: Array index assignment this.items[0] = 'new' // Not reactive!
// FIX: Use splice or $set this.$set(this.items, 0, 'new') // Or: this.items.splice(0, 1, 'new') } } ```
Step 6: Check v-if and v-show
```vue <template> <!-- v-if completely removes element from DOM --> <div v-if="showComponent"> This won't render if showComponent is false </div>
<!-- v-show just hides with CSS --> <div v-show="showComponent"> This renders but hidden with display: none </div>
<!-- Check condition --> <div v-if="items.length > 0"> Items: {{ items.length }} </div>
<!-- Debug condition --> <div>Condition value: {{ showComponent }}</div>
<!-- Common issue: async data --> <div v-if="user"> {{ user.name }} <!-- user is null initially --> </div>
<!-- FIX: Check if loaded --> <div v-if="user && user.name"> {{ user.name }} </div> </template>
<script> export default { data() { return { showComponent: true, // Check this value items: [], user: null // Will be loaded async } }, async mounted() { this.user = await fetchUser() } } </script> ```
Step 7: Check Props and Events
```vue <!-- Parent --> <template> <ChildComponent :title="pageTitle" @update="handleUpdate" /> </template>
<script> import ChildComponent from './ChildComponent.vue'
export default { components: { ChildComponent }, data() { return { pageTitle: 'Hello' } }, methods: { handleUpdate(value) { console.log('Updated:', value) } } } </script>
<!-- ChildComponent.vue --> <template> <div> <h1>{{ title }}</h1> <button @click="$emit('update', 'new value')">Update</button> </div> </template>
<script> export default { props: { title: { type: String, required: true } } } </script> ```
Step 8: Check CSS Issues
```vue <template> <!-- Content exists but hidden by CSS --> <div class="hidden-content"> This content might be hidden </div> </template>
<style> /* Check these issues: */
/* Display none */ .hidden-content { display: none; /* Content won't show */ }
/* Visibility hidden */ .hidden-content { visibility: hidden; /* Content takes space but invisible */ }
/* Opacity 0 */ .hidden-content { opacity: 0; /* Transparent but takes space */ }
/* Zero dimensions */ .hidden-content { height: 0; width: 0; overflow: hidden; /* Content clipped */ }
/* z-index issues */ .behind { z-index: -1; /* Behind other elements */ }
/* Position off screen */ .offscreen { position: absolute; left: -9999px; } </style>
<!-- Debug by adding visible styles temporarily --> <style> .debug { border: 2px solid red !important; background: yellow !important; } </style> ```
Step 9: Check Lifecycle Hooks
```javascript export default { data() { return { mounted: false, data: null } },
// Check these hooks for issues:
beforeCreate() { // Component initializing // Can't access this.data yet console.log('beforeCreate') },
created() { // Component created // Can access data, but not DOM console.log('created', this.data) },
beforeMount() { // Before DOM insertion console.log('beforeMount') },
mounted() { // DOM ready // Use this for DOM operations console.log('mounted', this.$el) this.mounted = true },
beforeUpdate() { // Before data change re-render console.log('beforeUpdate') },
updated() { // After re-render console.log('updated') },
beforeUnmount() { // Before component removed console.log('beforeUnmount') },
unmounted() { // Component removed console.log('unmounted') } } ```
Step 10: Vue.js Component Verification Script
```javascript // Add to component for debugging:
export default { name: 'MyComponent',
mounted() { console.log('=== Component Debug ===') console.log('Component mounted:', this.$options.name) console.log('Props:', this.$props) console.log('Data:', this.$data) console.log('Slots:', this.$slots) console.log('Attrs:', this.$attrs) console.log('Root element:', this.$el)
// Check if rendered if (this.$el) { console.log('Element HTML:', this.$el.outerHTML) } },
// Add error handler errorCaptured(err, vm, info) { console.error('Component error:', err) console.error('Component:', vm) console.error('Info:', info) return false } }
// Global error handler (main.js): app.config.errorHandler = (err, vm, info) => { console.error('Vue error:', err) console.error('Component:', vm) console.error('Info:', info) }
// Render function debug: render() { console.log('Rendering with state:', this.$data) return h('div', 'Content') } ```
Vue.js Component Checklist
| Check | Expected |
|---|---|
| Component registered | Listed in components |
| Import path correct | File exists |
| Template valid | No compile errors |
| Props passed | Values in DevTools |
| Data reactive | Updates reflected |
| No CSS hiding | Element visible |
Verify the Fix
```javascript // After fixing component rendering
// 1. Check in DevTools // Vue tab shows component // Props and data correct
// 2. Console no errors // No Vue warnings
// 3. Element in DOM document.querySelector('my-component') // Returns element
// 4. Update triggers re-render // Change data, see update
// 5. Events work // Click handlers fire
// 6. Slots render // Transcluded content appears ```
Related Issues
- [Fix React Component Not Rendering](/articles/fix-react-component-not-rendering)
- [Fix Vue.js Props Undefined](/articles/fix-vuejs-props-undefined)
- [Fix Angular Component Not Loading](/articles/fix-angular-component-not-loading)