Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

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 PostCard

The 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:

FileName 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.

Thanks for reading!

Donate to the site — we work hard for you.