Vue.js course Β· Module 6: Components

Component Registration and Import

5 min read
In this lesson4

Dr. Nova explains: "At NOVA LAB, every habitat module must be officially registered in the station system before it can function. Similarly, Vue components must be imported or registered before they can be used in a template."

What happens when you write <StatusBar /> in a template but don't tell Vue where to get this component? Vue won't guess the path to the file. The console shows the warning "Failed to resolve component: StatusBar", and the page is left with an empty element the browser doesn't know. Registration is exactly this piece of information: which component hides behind a given name.

Import in <script setup>

The most common and recommended approach is local import in the <script setup> block. An imported component is automatically available in the template - no need to register it anywhere! Look at a command panel made of three modules:

1<!-- MissionControl.vue -->
2<template>
3  <div class="control-panel">
4    <ModuleCard />
5    <StatusBar />
6    <AlertPanel />
7  </div>
8</template>
9
10<script setup>
11// Just import - the component is immediately available in template!
12import ModuleCard from './components/ModuleCard.vue'
13import StatusBar from './components/StatusBar.vue'
14import AlertPanel from './components/AlertPanel.vue'
15</script>

A .vue file exposes its component as the default export, which is why we import it without curly braces, and the name given in the import becomes the tag name in the template. The path starts with ./, so it is relative. You could just as well use the alias from the Vite configuration: @/components/StatusBar.vue.

Note: in Options API (without <script setup>) we would need to additionally register components in the components: {} option. In Composition API with <script setup> this step is unnecessary - Vue automatically recognizes imported components. Compare both versions:

1<!-- Options API - requires manual registration -->
2<script>
3import ModuleCard from './components/ModuleCard.vue'
4
5export default {
6  components: {
7    ModuleCard  // Registration required!
8  }
9}
10</script>
11
12<!-- Composition API <script setup> - auto-registration -->
13<script setup>
14import ModuleCard from './components/ModuleCard.vue'
15// Done! Nothing more needed.
16</script>

The import looks identical in both versions - the difference lies in what happens after it. The <script setup> compiler notices on its own that ModuleCard is used in the template and wires it up for you. You'll meet the older form in the documentation and in existing projects, so it's worth recognizing.

Global Registration

If a component is used in many places throughout the application (e.g., button, icon), you can register it globally in the main.js file, in the same ignition sequence you learned in the Launch Zone:

1// main.js
2import { createApp } from 'vue'
3import App from './App.vue'
4import BaseButton from './components/common/BaseButton.vue'
5import BaseIcon from './components/common/BaseIcon.vue'
6
7const app = createApp(App)
8
9// Global registration - available everywhere without import
10app.component('BaseButton', BaseButton)
11app.component('BaseIcon', BaseIcon)
12
13app.mount('#app')

The app.component() method takes a name and a component, and its calls stand before mount(), just like the app.use() calls. After global registration, the component is available in every template without needing to import:

1<!-- Any component in the application -->
2<template>
3  <BaseButton>Launch module</BaseButton>
4  <BaseIcon name="rocket" />
5</template>
6
7<script setup>
8// No need to import BaseButton or BaseIcon!
9</script>

The template looks the same as with a local import - only the import line is gone. But the convenience has a price, which the table shows.

Local vs Global - When to Use Which?

FeatureLocal importGlobal registration
AvailabilityOnly in the importing componentEverywhere in the app
Tree-shakingYes - unused components removed from buildNo - always in bundle
ReadabilityDependencies visible in <script setup>Hidden dependencies
Use caseMost componentsBase, frequently used (Base*, App*)

The Vue documentation points out two drawbacks of global registration: the build tool won't remove an unused component from the bundle, and in a large application it's harder to trace where a component comes from. That's why you should treat local import as the default. Register globally only base components that are used really often - that's my recommendation for the whole base.

PascalCase vs kebab-case in Templates

Vue allows both naming conventions in templates. A component imported as ModuleCard can also be written as module-card:

1<script setup>
2import ModuleCard from './ModuleCard.vue'
3import StatusBar from './StatusBar.vue'
4</script>
5
6<template>
7  <!-- PascalCase (recommended in SFC) -->
8  <ModuleCard />
9  <StatusBar />
10
11  <!-- kebab-case (also works) -->
12  <module-card />
13  <status-bar />
14</template>

Both forms insert the same components. PascalCase is recommended in Single File Components (.vue) because:

  • Easier to distinguish Vue components from native HTML elements
  • <ModuleCard /> is a component, <div> is HTML
  • Better readability and consistency with the filename

The exception concerns templates written directly in an HTML file: the browser ignores letter case there, so you have to use kebab-case and a full closing tag. In .vue files this trap doesn't exist, and a self-closing <ModuleCard /> works without problems.

In the editor below, App.vue imports three components: StatusPanel, ControlBar and InfoCard. Remove one of the imports and see its part of the panel disappear from the preview.

Remember: a component is like a module in the station registry - a local import enters it for one panel, app.component() for the whole base, so reach for global registration only when a module really works everywhere.

Code for this lesson: App.vue
1<script setup>
2import StatusPanel from './StatusPanel.vue'
3import ControlBar from './ControlBar.vue'
4import InfoCard from './InfoCard.vue'
5
6// In <script setup> imported components are automatically registered
7// No need to add them to components: {} - Vue does it for us!
8</script>
9
10<template>
11  <div class="registration-lab">
12    <div class="header">
13      <h1>Component Registration - NOVA LAB</h1>
14      <p class="subtitle">Import and auto-registration in script setup</p>
15    </div>
16
17    <div class="info-panel">
18      <h3>Importing components</h3>
19      <p>In <strong>script setup</strong> you just import a component - Vue registers it automatically</p>
20      <p>Each component is a separate <strong>.vue</strong> file with its own template, script and style</p>
21    </div>
22
23    <div class="components-grid">
24      <StatusPanel />
25      <ControlBar />
26      <InfoCard />
27    </div>
28
29    <div class="code-note">
30      <h3>How does it work?</h3>
31      <p>1. We create a component file (e.g. StatusPanel.vue)</p>
32      <p>2. We import it: import StatusPanel from './StatusPanel.vue'</p>
33      <p>3. We use it in the template: &lt;StatusPanel /&gt;</p>
34      <p>That's all! No additional registration needed.</p>
35    </div>
36  </div>
37</template>
38
39<style scoped>
40.registration-lab {
41  background: linear-gradient(135deg, #0a0e27 0%, #1a1e3f 100%);
42  min-height: 100vh;
43  padding: 2rem;
44  color: #ffffff;
45  font-family: 'Courier New', monospace;
46}
47
48.header {
49  text-align: center;
50  margin-bottom: 2rem;
51  padding-bottom: 1rem;
52  border-bottom: 2px solid #00ff88;
53}
54
55.header h1 {
56  font-size: 2rem;
57  color: #00ff88;
58  text-shadow: 0 0 20px rgba(0, 255, 136, 0.5);
59  margin: 0;
60}
61
62.subtitle {
63  color: #00b4d8;
64  font-size: 1.1rem;
65  margin-top: 0.5rem;
66}
67
68.info-panel {
69  background: rgba(0, 180, 216, 0.1);
70  border: 2px solid #00b4d8;
71  border-radius: 10px;
72  padding: 1.5rem;
73  margin-bottom: 2rem;
74}
75
76.info-panel h3 {
77  color: #00b4d8;
78  margin-top: 0;
79}
80
81.info-panel strong {
82  color: #00ff88;
83}
84
85.components-grid {
86  display: grid;
87  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
88  gap: 1.5rem;
89  margin-bottom: 2rem;
90}
91
92.code-note {
93  background: rgba(0, 0, 0, 0.4);
94  border-left: 4px solid #00ff88;
95  padding: 1.5rem;
96  border-radius: 8px;
97}
98
99.code-note h3 {
100  color: #00ff88;
101  margin-top: 0;
102}
103
104.code-note p {
105  color: #00b4d8;
106  margin: 0.5rem 0;
107}
108</style>

Spotted a mistake in this lesson?

Check yourself

Answer the questions from this lesson. Pick an answer to see right away whether it is correct.

  1. 1. How do you import a component in <script setup>?

  2. 2. How do you use an imported component in the template?

These are 2 of 3 questions for this lesson. Solve the rest in the game.

Hands-on tasks in the game

  • Code editor

    Import MarsModule and use it in App.vue.

  • Vertical ordering

    Arrange the steps to import a component in script setup:

Useful articles