Files
agent-skills/skills/nuxt/references/features-components-autoimport.md
Jason Woltje f5792c40be feat: Complete fleet — 94 skills across 10+ domains
Pulled ALL skills from 15 source repositories:
- anthropics/skills: 16 (docs, design, MCP, testing)
- obra/superpowers: 14 (TDD, debugging, agents, planning)
- coreyhaines31/marketingskills: 25 (marketing, CRO, SEO, growth)
- better-auth/skills: 5 (auth patterns)
- vercel-labs/agent-skills: 5 (React, design, Vercel)
- antfu/skills: 16 (Vue, Vite, Vitest, pnpm, Turborepo)
- Plus 13 individual skills from various repos

Mosaic Stack is not limited to coding — the Orchestrator and
subagents serve coding, business, design, marketing, writing,
logistics, analysis, and more.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 16:27:42 -06:00

5.4 KiB

name, description
name description
components-auto-imports Auto-imported components, lazy loading, and hydration strategies

Components Auto-imports

Nuxt automatically imports Vue components from app/components/ directory.

Basic Auto-imports

components/
├── Button.vue         → <Button />
├── Card.vue           → <Card />
└── AppHeader.vue      → <AppHeader />
<template>
  <!-- No imports needed -->
  <AppHeader />
  <Card>
    <Button>Click me</Button>
  </Card>
</template>

Naming Conventions

Nested Directory Names

Component names include directory path:

components/
├── base/
│   └── Button.vue       → <BaseButton />
├── form/
│   ├── Input.vue        → <FormInput />
│   └── Select.vue       → <FormSelect />
└── ui/
    └── modal/
        └── Dialog.vue   → <UiModalDialog />

Disable Path Prefix

// nuxt.config.ts
export default defineNuxtConfig({
  components: [
    {
      path: '~/components',
      pathPrefix: false, // Use filename only
    },
  ],
})

With pathPrefix: false:

components/base/Button.vue → <Button />

Lazy Loading

Prefix with Lazy for dynamic imports:

<script setup lang="ts">
const showChart = ref(false)
</script>

<template>
  <!-- Component code loaded only when rendered -->
  <LazyHeavyChart v-if="showChart" />
  <button @click="showChart = true">Show Chart</button>
</template>

Benefits:

  • Reduces initial bundle size
  • Code-splits component into separate chunk
  • Loads on-demand

Lazy Hydration Strategies

Control when lazy components become interactive:

hydrate-on-visible

Hydrate when component enters viewport:

<template>
  <LazyComments hydrate-on-visible />
</template>

hydrate-on-idle

Hydrate when browser is idle:

<template>
  <LazyAnalytics hydrate-on-idle />
</template>

hydrate-on-interaction

Hydrate on user interaction:

<template>
  <!-- Hydrates on click, focus, or pointerenter -->
  <LazyDropdown hydrate-on-interaction />

  <!-- Specific event -->
  <LazyTooltip hydrate-on-interaction="mouseover" />
</template>

hydrate-on-media-query

Hydrate when media query matches:

<template>
  <LazyMobileMenu hydrate-on-media-query="(max-width: 768px)" />
</template>

hydrate-after

Hydrate after delay (milliseconds):

<template>
  <LazyAds :hydrate-after="3000" />
</template>

hydrate-when

Hydrate on condition:

<script setup lang="ts">
const isReady = ref(false)
</script>

<template>
  <LazyEditor :hydrate-when="isReady" />
</template>

hydrate-never

Never hydrate (static only):

<template>
  <LazyStaticFooter hydrate-never />
</template>

Hydration Event

<template>
  <LazyChart hydrate-on-visible @hydrated="onChartReady" />
</template>

<script setup>
function onChartReady() {
  console.log('Chart is now interactive')
}
</script>

Client/Server Components

Client-only (.client.vue)

components/
└── BrowserChart.client.vue
<template>
  <!-- Only rendered in browser -->
  <BrowserChart />
</template>

Server-only (.server.vue)

components/
└── ServerMarkdown.server.vue
<template>
  <!-- Rendered on server, not hydrated -->
  <ServerMarkdown :content="markdown" />
</template>

Requires experimental flag:

// nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    componentIslands: true,
  },
})

Paired Components

components/
├── Comments.client.vue  # Browser version
└── Comments.server.vue  # SSR version

Server version renders during SSR, client version takes over after hydration.

Dynamic Components

<script setup lang="ts">
import { SomeComponent } from '#components'

const dynamicComponent = resolveComponent('MyButton')
</script>

<template>
  <component :is="dynamicComponent" />
  <component :is="SomeComponent" />
</template>

Direct Imports

Bypass auto-imports when needed:

<script setup lang="ts">
import { LazyMountainsList, NuxtLink } from '#components'
</script>

Custom Directories

// nuxt.config.ts
export default defineNuxtConfig({
  components: [
    { path: '~/components/ui', prefix: 'Ui' },
    { path: '~/components/forms', prefix: 'Form' },
    '~/components', // Default, should come last
  ],
})

Global Components

Register globally (creates async chunks):

// nuxt.config.ts
export default defineNuxtConfig({
  components: {
    global: true,
    dirs: ['~/components'],
  },
})

Or use .global.vue suffix:

components/
└── Icon.global.vue  → Available globally

Disabling Component Auto-imports

// nuxt.config.ts
export default defineNuxtConfig({
  components: {
    dirs: [], // Disable auto-imports
  },
})

Library Authors

Register components from npm package:

// my-ui-lib/nuxt.ts
import { addComponentsDir, createResolver, defineNuxtModule } from '@nuxt/kit'

export default defineNuxtModule({
  setup() {
    const resolver = createResolver(import.meta.url)

    addComponentsDir({
      path: resolver.resolve('./components'),
      prefix: 'MyUi',
    })
  },
})