How to Solve "Unknown Custom Element" in Vue

You've created this amazing Vue component, and you're trying to use it within another component.

Then you get this terrible error:

Vue warn: Unknown custom element: - did you register the component correctly? For recursive components, make sure to provide the "name" option.

Don't worry, I'll show you exactly how to fix this.

You need to make sure that your component is being properly registered.

But why does this happen, and how do you properly register your shiny component?

Registering components correctly

In Vue, you need to register custom components before you can use them.

Regular HTML tags like <div>, <p>, or <h1> don't need to be registered. Every browser knows how to render these, so Vue doesn't have to do anything special to get them to work.

However, when you write your own custom Vue component, Vue needs to know about it first. You need to tell Vue which component it needs to render when you use <MyComponent> in your template.

You do this through registering the component.

But there are 2 different ways you can register a component — global and local registration.

Let's take a look at each of them, and figure out which one you should be using when.

Global registration

You can make your component available to your whole app using global registration:

Vue.component('my-component', MyComponent);

This line needs to be placed where you do all of your Vue setup. This is where you import vue and create the Vue app using new Vue(). It's likely in a file called main.js or something similar.

If you're using Vue CLI, then you would modify the file main.js to look like this:

import Vue from "vue";
import App from "./App.vue";
// Import your component
import MyComponent from './MyComponent.vue';
Vue.config.productionTip = false;
// Globally register your component
Vue.component('my-component', MyComponent);
new Vue({
render: h => h(App)
}).$mount("#app");

Now, inside of any other Vue component you can just write out the component name in the template and it will work!

<template>
<!-- You can use CamelCase -->
<MyComponent />
<!-- You can also use kebab-case if you prefer -->
<my-component />
</template>

But this method isn't the best.

It's not clear where components are coming from, and it's also possible that you'll have conflicting components.

This method is best reserved for components that are used all over the place. Components like a Button or Input, for example. You only need to register the component one time, which can make things easier.

As you'll see, local registration requires a little more typing, but it's worth it.

Local registration

Vue also gives you the ability to register components for a specific component:

import MyComponent from './MyComponent.vue';
export default {
name: 'AnotherComponent',
components: {
MyComponent,
}
};

Now that the component is registered, we can use it in the template:

<template>
<MyComponent />
</template>

But only in this component.

Child components, or any other component will not have access to MyComponent. We have to do the same thing on every single component that wants to use MyComponent.

Why is local registration better?

First, you're making it very clear where each component is coming from. There's no confusion about what file MyComponent is getting pulled from, and where you'd need to go if you need to modify it.

If you use global registration this can be a lot more complicated (and frustrating!) to figure out.

Secondly, by scoping your components you prevent any weird errors from happening if components end up overriding each other.

For example, if you globally registered a RedButton component, it's possible to register a different component somewhere else, but also call it RedButton. Now when you go to use RedButton somewhere, which one ends up being rendered?

The answer isn't clear, and that's why you should try to avoid using global registration.