Components and auto-imports
Components in Nuxt are written just like in Vue, but you do not import them. Nuxt finds everything in the app/components/ folder itself and lets you use it in any template by its file name. This is called auto-importing.
A post card
Create a component with a command:
npx nuxi add component PostCardThe file app/components/PostCard.vue appears. Replace its content:
<!-- app/components/PostCard.vue -->
<script setup lang="ts">
defineProps<{
post: { id: number; title: string; text: string }
}>()
</script>
<template>
<article class="post-card">
<h3>
<NuxtLink :to="`/posts/${post.id}`">{{ post.title }}</NuxtLink>
</h3>
<p>{{ post.text }}</p>
</article>
</template>The component receives a post through the post prop and shows a title link and the text.
Using it
Replace the post markup in the list app/pages/posts/index.vue:
<!-- app/pages/posts/index.vue -->
<template>
<section>
<h2>Posts</h2>
<PostCard v-for="post in posts" :key="post.id" :post="post" />
</section>
</template>There is no import PostCard from ... line, yet the /posts page looks as before: Nuxt resolved the component by its file name. The editor knows about it too, so hints and type checking work.
Components in subfolders
Subfolders keep things tidy, and the component name is built from the path:
| File | Name in templates |
|---|---|
app/components/PostCard.vue | <PostCard> |
app/components/post/Comments.vue | <PostComments> |
app/components/post/CommentForm.vue | <PostCommentForm> |
app/components/admin/Menu.vue | <AdminMenu> |
Create app/components/post/Comments.vue for the future comments:
<!-- app/components/post/Comments.vue -->
<template>
<section>
<h3>Comments</h3>
<p>No comments yet.</p>
</section>
</template>On the post page it is used as <PostComments />.
Lazy loading
If you add the word Lazy to a component name, its code loads as a separate file only when the component is needed:
<!-- app/pages/posts/[id].vue -->
<script setup lang="ts">
const showComments = ref(false)
</script>
<template>
<article>
<button @click="showComments = true">Show comments</button>
<LazyPostComments v-if="showComments" />
</article>
</template>The comments code downloads after the button is clicked, so the first page load is lighter.
Browser only
A component that needs window or localStorage is wrapped in <ClientOnly>: the server skips it and it appears once the page loads in the browser.
Common mistake
The file app/components/post/Card.vue is not available as <Card>; its name is <PostCard>, because the folder name is added to the name. If a component "cannot be resolved", open Nuxt DevTools, the Components tab: it shows the real names of all components.