2021-10-11 12:57:54 +00:00
---
2022-10-06 09:15:30 +00:00
navigation.icon: IconDirectory
title: "components"
2023-06-05 15:03:06 +00:00
description: "The components/ directory is where you put all your Vue components."
2022-11-21 15:51:39 +00:00
head.title: "components/"
2021-10-11 12:57:54 +00:00
---
2022-08-13 07:27:04 +00:00
# Components Directory
2021-10-11 12:57:54 +00:00
2023-06-05 15:03:06 +00:00
The `components/` directory is where you put all your Vue components which can then be imported inside your pages or other components ([learn more](https://vuejs.org/guide/essentials/component-basics.html#components-basics)).
2021-10-14 15:21:54 +00:00
Nuxt automatically imports any components in your `components/` directory (along with components that are registered by any modules you may be using).
```bash
| components/
--| TheHeader.vue
--| TheFooter.vue
```
2023-03-23 13:47:21 +00:00
```html [layouts/default.vue]
2021-10-14 15:21:54 +00:00
< template >
< div >
< TheHeader / >
2021-11-19 11:36:25 +00:00
< slot / >
2021-10-14 15:21:54 +00:00
< TheFooter / >
< / div >
< / template >
```
2023-02-15 16:22:30 +00:00
## Custom directories
By default, only the `~/components` directory is scanned. If you want to add other directories, or change how the components are scanned within a subfolder of this directory, you can add additional directories to the configuration:
2023-03-23 13:47:21 +00:00
```ts [nuxt.config.ts]
2023-02-15 16:22:30 +00:00
export default defineNuxtConfig({
components: [
2023-02-20 09:53:40 +00:00
{ path: '~/components/special-components', prefix: 'Special' },
'~/components'
2023-02-15 16:22:30 +00:00
]
})
```
::alert
Any nested directories need to be added first as they are scanned in order.
::
2023-01-19 13:06:13 +00:00
## Component extensions
2023-03-09 11:34:41 +00:00
By default, any file with an extension specified in the [extensions key of `nuxt.config.ts` ](/docs/api/configuration/nuxt-config#extensions ) is treated as a component.
2023-01-19 13:06:13 +00:00
If you need to restrict the file extensions that should be registered as components, you can use the extended form of the components directory declaration and its `extensions` key:
```diff
2023-02-15 16:22:30 +00:00
export default defineNuxtConfig({
2023-01-19 13:06:13 +00:00
components: [
{
path: '~/components',
+ extensions: ['.vue'],
}
]
})
```
2021-10-14 15:21:54 +00:00
## Component Names
2021-11-21 12:31:44 +00:00
If you have a component in nested directories such as:
2021-10-14 15:21:54 +00:00
```bash
| components/
--| base/
----| foo/
------| Button.vue
```
2021-11-21 12:31:44 +00:00
... then the component's name will be based on its own path directory and filename, with duplicate segments being removed. Therefore, the component's name will be:
2021-10-14 15:21:54 +00:00
```html
< BaseFooButton / >
```
::alert
2022-04-16 13:53:36 +00:00
For clarity, we recommend that the component's filename matches its name. (So, in the example above, you could rename `Button.vue` to be `BaseFooButton.vue` .)
2021-10-14 15:21:54 +00:00
::
2023-01-19 13:06:13 +00:00
If you want to auto-import components based only on its name, not path, then you need to set `pathPrefix` option to `false` using extended form of the configuration object:
```diff
export default defineNuxtConfig({
components: [
{
2023-02-15 16:22:30 +00:00
path: '~/components',
2023-01-19 13:06:13 +00:00
+ pathPrefix: false,
},
],
});
```
This registers the components using the same strategy as used in Nuxt 2. For example, `~/components/Some/MyComponent.vue` will be usable as `<MyComponent>` and not `<SomeMyComponent>` .
2022-08-13 07:27:04 +00:00
## Dynamic Components
2022-03-22 17:04:31 +00:00
If you want to use the Vue `<component :is="someComputedComponent">` syntax, then you will need to use the `resolveComponent` helper provided by Vue.
For example:
```vue
< template >
< component :is = "clickable ? MyButton : 'div'" / >
< / template >
< script setup >
const MyButton = resolveComponent('MyButton')
< / script >
```
2022-06-12 21:22:15 +00:00
::alert{type=warning}
If you are using `resolveComponent` to handle dynamic components, make sure not to insert anything but the name of the component, which must be a string and not a variable.
::
2022-03-22 17:04:31 +00:00
Alternatively, though not recommended, you can register all your components globally, which will create async chunks for all your components and make them available throughout your application.
```diff
export default defineNuxtConfig({
components: {
+ global: true,
+ dirs: ['~/components']
},
})
```
2022-07-27 13:05:34 +00:00
You can also selectively register some components globally by placing them in a `~/components/global` directory.
2022-03-22 17:04:31 +00:00
::alert{type=info}
The `global` option can also be set per component directory.
::
2021-10-14 15:21:54 +00:00
## Dynamic Imports
2021-11-21 12:31:44 +00:00
To dynamically import a component (also known as lazy-loading a component) all you need to do is add the `Lazy` prefix to the component's name.
2021-10-14 15:21:54 +00:00
2023-03-23 13:47:21 +00:00
```html [layouts/default.vue]
2021-10-14 15:21:54 +00:00
< template >
< div >
< TheHeader / >
2021-11-19 11:36:25 +00:00
< slot / >
2021-10-14 15:21:54 +00:00
< LazyTheFooter / >
< / div >
< / template >
```
This is particularly useful if the component is not always needed. By using the `Lazy` prefix you can delay loading the component code until the right moment, which can be helpful for optimizing your JavaScript bundle size.
2023-03-23 13:47:21 +00:00
```html [pages/index.vue]
2021-10-14 15:21:54 +00:00
< template >
< div >
< h1 > Mountains< / h1 >
< LazyMountainsList v-if = "show" / >
< button v-if = "!show" @click =" show = true" > Show List</ button >
< / div >
< / template >
< script >
export default {
data() {
return {
show: false
}
}
}
< / script >
```
2022-08-13 07:27:04 +00:00
## Direct Imports
2022-04-07 11:03:37 +00:00
You can also explicitly import components from `#components` if you want or need to bypass Nuxt's auto-importing functionality.
2023-03-23 13:47:21 +00:00
```html [pages/index.vue]
2022-04-07 11:03:37 +00:00
< template >
< div >
< h1 > Mountains< / h1 >
< LazyMountainsList v-if = "show" / >
< button v-if = "!show" @click =" show = true" > Show List</ button >
< NuxtLink to = "/" > Home< / NuxtLink >
< / div >
< / template >
< script setup >
import { NuxtLink, LazyMountainsList } from '#components'
const show = ref(false)
< / script >
```
2021-11-15 12:00:14 +00:00
## `<ClientOnly>` Component
2021-11-21 12:31:44 +00:00
Nuxt provides the `<ClientOnly>` component for purposely rendering a component only on client side. To import a component only on the client, register the component in a client-side only plugin.
2021-11-15 12:00:14 +00:00
2023-03-23 13:47:21 +00:00
```html [pages/example.vue]
2021-11-15 12:00:14 +00:00
< template >
< div >
< Sidebar / >
< ClientOnly >
<!-- this component will only be rendered on client - side -->
< Comments / >
< / ClientOnly >
< / div >
< / template >
```
2021-11-21 12:31:44 +00:00
Use a slot as fallback until `<ClientOnly>` is mounted on client side.
2021-11-15 12:00:14 +00:00
2023-03-23 13:47:21 +00:00
```html [pages/example.vue]
2021-11-15 12:00:14 +00:00
< template >
< div >
< Sidebar / >
2022-08-13 07:32:42 +00:00
<!-- This renders the "span" element on the server side -->
< ClientOnly fallbackTag = "span" >
2021-11-21 12:31:44 +00:00
<!-- this component will only be rendered on client side -->
2021-11-15 12:00:14 +00:00
< Comments / >
< template #fallback >
2021-11-21 12:31:44 +00:00
<!-- this will be rendered on server side -->
2021-11-15 12:00:14 +00:00
< p > Loading comments...< / p >
< / template >
< / ClientOnly >
< / div >
< / template >
```
2022-07-17 13:13:04 +00:00
<!-- TODO: Add back after passing treeshakeClientOnly experiment -->
<!-- ::alert{type=warning}
2022-07-14 17:46:12 +00:00
Make sure not to _nest_ `<ClientOnly>` components or other client-only components. Nuxt performs an optimization to remove the contents of these components from the server-side render, which can break in this case.
2022-07-17 13:13:04 +00:00
:: -->
2022-07-14 17:46:12 +00:00
2022-09-03 13:26:43 +00:00
## .client Components
If a component is meant to be rendered only client-side, you can add the `.client` suffix to your component.
```bash
2022-09-14 17:26:43 +00:00
| components/
2022-09-03 13:26:43 +00:00
--| Comments.client.vue
```
2023-03-23 13:47:21 +00:00
```html [pages/example.vue]
2022-09-03 13:26:43 +00:00
< template >
< div >
<!-- this component will only be rendered on client side -->
< Comments / >
< / div >
< / template >
```
::alert{type=warning}
2022-10-11 15:26:03 +00:00
This feature only works with Nuxt auto-imports and `#components` imports. Explicitly importing these components from their real paths does not convert them into client-only components.
2022-09-03 13:26:43 +00:00
::
2022-11-24 11:15:33 +00:00
::alert{type=warning}
`.client` components are rendered only after being mounted. To access the rendered template using `onMounted()` , add `await nextTick()` in the callback of the `onMounted()` hook.
::
2022-09-03 13:26:43 +00:00
## .server Components
2023-01-09 11:20:33 +00:00
`.server` components can either be used on their own or paired with a `.client` component.
### Standalone server components
Standalone server components will always be rendered on the server. When their props update, this will result in a network request that will update the rendered HTML in-place.
2023-03-23 13:47:21 +00:00
:video-player{src="https://www.youtube.com/watch?v=u1yyXe86xJM"}
> A video made by [LearnVue](https://go.learnvue.co) for the Nuxt documentation.
2023-01-09 11:20:33 +00:00
Server components are currently experimental and in order to use them, you need to enable the 'component islands' feature in your nuxt.config:
```ts [nuxt.config.ts]
export default defineNuxtConfig({
experimental: {
componentIslands: true
}
})
```
Now you can register server-only components with the `.server` suffix and use them anywhere in your application automatically.
```bash
| components/
--| HighlightedMarkdown.server.vue
```
2023-03-23 13:47:21 +00:00
```html [pages/example.vue]
2023-01-09 11:20:33 +00:00
< template >
< div >
<!--
this will automatically be rendered on the server, meaning your markdown parsing + highlighting
libraries are not included in your client bundle.
-->
< HighlightedMarkdown markdown = "# Headline" / >
< / div >
< / template >
```
2023-05-15 22:43:53 +00:00
::alert{type=info}
Slots can be interactive and are wrapped within a `<div>` with `display: contents;`
2023-02-07 10:09:36 +00:00
::
2023-01-09 11:20:33 +00:00
### Paired with a `.client` component
In this case, the `.server` + `.client` components are two 'halves' of a component and can be used in advanced use cases for separate implementations of a component on server and client side.
2022-09-03 13:26:43 +00:00
```bash
2022-09-14 17:26:43 +00:00
| components/
2022-09-03 13:26:43 +00:00
--| Comments.client.vue
--| Comments.server.vue
```
2023-03-23 13:47:21 +00:00
```html [pages/example.vue]
2022-09-03 13:26:43 +00:00
< template >
2022-09-14 17:26:43 +00:00
< div >
2022-09-03 13:26:43 +00:00
<!-- this component will render Comments.server server - side then Comments.client once mounted in client - side -->
< Comments / >
< / div >
< / template >
```
2023-01-09 11:20:33 +00:00
::alert{type=warning}
It is essential that the client half of the component can 'hydrate' the server-rendered HTML. That is, it should render the same HTML on initial load, or you will experience a hydration mismatch.
::
2022-10-26 12:43:37 +00:00
## `<DevOnly>` Component
Nuxt provides the `<DevOnly>` component to render a component only during development.
The content will not be included in production builds and tree-shaken.
2023-03-23 13:47:21 +00:00
```html [pages/example.vue]
2022-10-26 12:43:37 +00:00
< template >
< div >
< Sidebar / >
< DevOnly >
<!-- this component will only be rendered during development -->
< LazyDebugBar / >
2023-05-13 22:32:31 +00:00
<!-- if you ever require to have a replacement during production -->
2023-05-15 12:33:46 +00:00
<!-- be sure to test these using `nuxt preview` -->
2023-05-13 22:32:31 +00:00
< template #fallback >
< div > <!-- empty div for flex.justify - between --> < / div >
< / template >
2022-10-26 12:43:37 +00:00
< / DevOnly >
< / div >
< / template >
```
2023-03-10 19:53:01 +00:00
## `<NuxtClientFallback>` Component
2023-03-08 21:13:06 +00:00
Nuxt provides the `<NuxtClientFallback>` component to render its content on the client if any of its children trigger an error in SSR.
You can specify a `fallbackTag` to make it render a specific tag if it fails to render on the server.
2023-03-23 13:47:21 +00:00
```html [pages/example.vue]
2023-03-08 21:13:06 +00:00
< template >
< div >
< Sidebar / >
<!-- this component will be rendered on client - side -->
< NuxtClientFallback fallback-tag = "span" >
< Comments / >
< BrokeInSSR / >
< / NuxtClientFallback >
< / div >
< / template >
```
2021-10-14 15:21:54 +00:00
## Library Authors
Making Vue component libraries with automatic tree-shaking and component registration is super easy ✨
2022-03-16 11:16:05 +00:00
You can use the `components:dirs` hook to extend the directory list without requiring user configuration in your Nuxt module.
2021-10-14 15:21:54 +00:00
Imagine a directory structure like this:
```bash
| node_modules/
---| awesome-ui/
------| components/
---------| Alert.vue
---------| Button.vue
------| nuxt.js
| pages/
---| index.vue
| nuxt.config.js
```
Then in `awesome-ui/nuxt.js` you can use the `components:dirs` hook:
2023-03-23 13:47:21 +00:00
```ts
import { defineNuxtModule, createResolver } from '@nuxt/kit'
2021-10-14 15:21:54 +00:00
export default defineNuxtModule({
hooks: {
2023-03-23 13:47:21 +00:00
'components:dirs': (dirs) => {
const { resolve } = createResolver(import.meta.url)
2021-10-14 15:21:54 +00:00
// Add ./components dir to the list
dirs.push({
2023-03-23 13:47:21 +00:00
path: fileURLToPath(resolve('./components')),
2021-10-14 15:21:54 +00:00
prefix: 'awesome'
})
}
}
})
```
2022-04-16 13:53:36 +00:00
That's it! Now in your project, you can import your UI library as a Nuxt module in your `nuxt.config` file:
2021-10-14 15:21:54 +00:00
2023-03-23 13:47:21 +00:00
```ts [nuxt.config.ts]
export default defineNuxtConfig({
2022-03-22 11:33:30 +00:00
modules: ['awesome-ui/nuxt']
2023-03-23 13:47:21 +00:00
})
2021-10-14 15:21:54 +00:00
```
2021-11-21 12:31:44 +00:00
... and directly use the module components (prefixed with `awesome-` ) in our `pages/index.vue` :
2021-10-14 15:21:54 +00:00
```vue
< template >
< div >
My < AwesomeButton > UI button< / AwesomeButton > !
< awesome-alert > Here's an alert!< / awesome-alert >
< / div >
< / template >
```
It will automatically import the components only if used and also support HMR when updating your components in `node_modules/awesome-ui/components/` .
2022-04-09 09:25:13 +00:00
2023-06-27 11:27:11 +00:00
:LinkExample{link="/docs/examples/features/auto-imports"}