ContentNavigation

ページリンクを整理するためのアコーディオンスタイルのナビゲーションコンポーネント。
このコンポーネントは@nuxt/contentモジュールがインストールされている場合にのみ使用できます。

使用法

navigationプロパティには、アプリケーションのナビゲーションを取得するときに取得するnavigation値を指定して使用します。

<script setup lang="ts">
import type { ContentNavigationItem } from '@nuxt/content'

const navigation = inject<Ref<ContentNavigationItem[]>>('navigation')
</script>

<template>
  <UContentNavigation :navigation="navigation" highlight />
</template>
<script setup lang="ts">
import { inject } from 'vue'
import type { ContentNavigationItem } from '@nuxt/content'

const navigation = inject<Ref<ContentNavigationItem[]>>('navigation')
</script>

<template>
  <UContentNavigation :navigation="navigation" highlight />
</template>

Type

typeプロパティをsingleに設定すると、一度に1つのアイテムしか開くことができません。デフォルトはmultipleです。

<script setup lang="ts">
import type { ContentNavigationLink } from '@nuxt/ui'

const navigation = ref<ContentNavigationLink[]>([
  {
    title: 'Guide',
    icon: 'i-lucide-book-open',
    path: '#getting-started',
    children: [
      {
        title: 'Introduction',
        path: '#introduction',
        active: true
      },
      {
        title: 'Installation',
        path: '#installation'
      }
    ]
  },
  {
    title: 'Composables',
    icon: 'i-lucide-database',
    path: '#composables',
    children: [
      {
        title: 'defineShortcuts',
        path: '#defineshortcuts'
      },
      {
        title: 'useModal',
        path: '#usemodal'
      }
    ]
  }
])
</script>

<template>
  <UContentNavigation type="single" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { ContentNavigationLink } from '@nuxt/ui'

const navigation = ref<ContentNavigationLink[]>([
  {
    title: 'Guide',
    icon: 'i-lucide-book-open',
    path: '#getting-started',
    children: [
      {
        title: 'Introduction',
        path: '#introduction',
        active: true
      },
      {
        title: 'Installation',
        path: '#installation'
      }
    ]
  },
  {
    title: 'Composables',
    icon: 'i-lucide-database',
    path: '#composables',
    children: [
      {
        title: 'defineShortcuts',
        path: '#defineshortcuts'
      },
      {
        title: 'useModal',
        path: '#usemodal'
      }
    ]
  }
])
</script>

<template>
  <UContentNavigation type="single" />
</template>

Color

colorプロパティを使用して、ナビゲーションリンクの色を変更します。

<script setup lang="ts">
import type { ContentNavigationLink } from '@nuxt/ui'

const navigation = ref<ContentNavigationLink[]>([
  {
    title: 'Guide',
    icon: 'i-lucide-book-open',
    path: '#getting-started',
    children: [
      {
        title: 'Introduction',
        path: '#introduction',
        active: true
      },
      {
        title: 'Installation',
        path: '#installation'
      }
    ]
  },
  {
    title: 'Composables',
    icon: 'i-lucide-database',
    path: '#composables',
    children: [
      {
        title: 'defineShortcuts',
        path: '#defineshortcuts'
      },
      {
        title: 'useModal',
        path: '#usemodal'
      }
    ]
  }
])
</script>

<template>
  <UContentNavigation color="neutral" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { ContentNavigationLink } from '@nuxt/ui'

const navigation = ref<ContentNavigationLink[]>([
  {
    title: 'Guide',
    icon: 'i-lucide-book-open',
    path: '#getting-started',
    children: [
      {
        title: 'Introduction',
        path: '#introduction',
        active: true
      },
      {
        title: 'Installation',
        path: '#installation'
      }
    ]
  },
  {
    title: 'Composables',
    icon: 'i-lucide-database',
    path: '#composables',
    children: [
      {
        title: 'defineShortcuts',
        path: '#defineshortcuts'
      },
      {
        title: 'useModal',
        path: '#usemodal'
      }
    ]
  }
])
</script>

<template>
  <UContentNavigation color="neutral" />
</template>

Variant

variantプロパティを使用して、ナビゲーションリンクのバリアントを変更します。

<script setup lang="ts">
import type { ContentNavigationLink } from '@nuxt/ui'

const navigation = ref<ContentNavigationLink[]>([
  {
    title: 'Guide',
    icon: 'i-lucide-book-open',
    path: '#getting-started',
    children: [
      {
        title: 'Introduction',
        path: '#introduction',
        active: true
      },
      {
        title: 'Installation',
        path: '#installation'
      }
    ]
  },
  {
    title: 'Composables',
    icon: 'i-lucide-database',
    path: '#composables',
    children: [
      {
        title: 'defineShortcuts',
        path: '#defineshortcuts'
      },
      {
        title: 'useModal',
        path: '#usemodal'
      }
    ]
  }
])
</script>

<template>
  <UContentNavigation variant="link" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { ContentNavigationLink } from '@nuxt/ui'

const navigation = ref<ContentNavigationLink[]>([
  {
    title: 'Guide',
    icon: 'i-lucide-book-open',
    path: '#getting-started',
    children: [
      {
        title: 'Introduction',
        path: '#introduction',
        active: true
      },
      {
        title: 'Installation',
        path: '#installation'
      }
    ]
  },
  {
    title: 'Composables',
    icon: 'i-lucide-database',
    path: '#composables',
    children: [
      {
        title: 'defineShortcuts',
        path: '#defineshortcuts'
      },
      {
        title: 'useModal',
        path: '#usemodal'
      }
    ]
  }
])
</script>

<template>
  <UContentNavigation variant="link" />
</template>

ハイライト

highlightプロパティを使用して、アクティブなリンクのハイライトされた境界線を表示します。

境界線の色を変更するにはhighlight-colorプロパティを使用します。デフォルトはcolorプロパティです。

<script setup lang="ts">
import type { ContentNavigationLink } from '@nuxt/ui'

const navigation = ref<ContentNavigationLink[]>([
  {
    title: 'Guide',
    icon: 'i-lucide-book-open',
    path: '#getting-started',
    children: [
      {
        title: 'Introduction',
        path: '#introduction',
        active: true
      },
      {
        title: 'Installation',
        path: '#installation'
      }
    ]
  },
  {
    title: 'Composables',
    icon: 'i-lucide-database',
    path: '#composables',
    children: [
      {
        title: 'defineShortcuts',
        path: '#defineshortcuts'
      },
      {
        title: 'useModal',
        path: '#usemodal'
      }
    ]
  }
])
</script>

<template>
  <UContentNavigation highlight highlight-color="primary" color="primary" variant="pill" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { ContentNavigationLink } from '@nuxt/ui'

const navigation = ref<ContentNavigationLink[]>([
  {
    title: 'Guide',
    icon: 'i-lucide-book-open',
    path: '#getting-started',
    children: [
      {
        title: 'Introduction',
        path: '#introduction',
        active: true
      },
      {
        title: 'Installation',
        path: '#installation'
      }
    ]
  },
  {
    title: 'Composables',
    icon: 'i-lucide-database',
    path: '#composables',
    children: [
      {
        title: 'defineShortcuts',
        path: '#defineshortcuts'
      },
      {
        title: 'useModal',
        path: '#usemodal'
      }
    ]
  }
])
</script>

<template>
  <UContentNavigation highlight highlight-color="primary" color="primary" variant="pill" />
</template>

Trailingアイコン

trailing-iconプロパティを使用して、子を持つアイテムの末尾のIconをカスタマイズします。デフォルトはi-lucide-chevron-downです。

<script setup lang="ts">
import type { ContentNavigationLink } from '@nuxt/ui'

const navigation = ref<ContentNavigationLink[]>([
  {
    title: 'Guide',
    icon: 'i-lucide-book-open',
    path: '#getting-started',
    children: [
      {
        title: 'Introduction',
        path: '#introduction',
        active: true
      },
      {
        title: 'Installation',
        path: '#installation'
      }
    ]
  },
  {
    title: 'Composables',
    icon: 'i-lucide-database',
    path: '#composables',
    children: [
      {
        title: 'defineShortcuts',
        path: '#defineshortcuts'
      },
      {
        title: 'useModal',
        path: '#usemodal'
      }
    ]
  }
])
</script>

<template>
  <UContentNavigation trailing-icon="i-lucide-arrow-up" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { ContentNavigationLink } from '@nuxt/ui'

const navigation = ref<ContentNavigationLink[]>([
  {
    title: 'Guide',
    icon: 'i-lucide-book-open',
    path: '#getting-started',
    children: [
      {
        title: 'Introduction',
        path: '#introduction',
        active: true
      },
      {
        title: 'Installation',
        path: '#installation'
      }
    ]
  },
  {
    title: 'Composables',
    icon: 'i-lucide-database',
    path: '#composables',
    children: [
      {
        title: 'defineShortcuts',
        path: '#defineshortcuts'
      },
      {
        title: 'useModal',
        path: '#usemodal'
      }
    ]
  }
])
</script>

<template>
  <UContentNavigation trailing-icon="i-lucide-arrow-up" />
</template>
このアイコンはapp.config.tsのui.icons.chevronDownキーでグローバルにカスタマイズできます。

サンプル

レイアウト内

レイアウト内のPageAsideコンポーネント内のContentNavigationコンポーネントを使用して、ページのナビゲーションを表示します。

layouts/docs.vue
<script setup lang="ts">
import type { ContentNavigationItem } from '@nuxt/content'

const navigation = inject<Ref<ContentNavigationItem[]>>('navigation')
</script>

<template>
  <UPage>
    <template #left>
      <UPageAside>
        <UContentNavigation :navigation="navigation" highlight />
      </UPageAside>
    </template>

    <slot />
  </UPage>
</template>

ヘッダー内

モバイルでページのナビゲーションを表示するには、Headerコンポーネントのcontentスロット内のContentNavigationコンポーネントを使用します。

components/Header.vue
<script setup lang="ts">
import type { ContentNavigationItem } from '@nuxt/content'

const navigation = inject<Ref<ContentNavigationItem[]>>('navigation')
</script>

<template>
  <UHeader>
    <template #body>
      <UContentNavigation :navigation="navigation" highlight />
    </template>
  </UHeader>
</template>

API

Props

Prop Default Type
as
'nav'
any

The element or component this component should render as.

defaultOpen
undefined
boolean

When true, the tree will be opened based on the current route. When false, the tree will be closed. When undefined (default), the first item will be opened with type="single" and the first level will be opened with type="multiple".

trailingIcon
appConfig.ui.icons.chevronDown
any

The icon displayed to toggle the accordion.

color
'primary'
"primary" | "secondary" | "success" | "info" | "warning" | "error" | "neutral"
variant
'pill'
"pill" | "link"
highlight
false
boolean

Display a line next to the active link.

highlightColor
'primary'
"primary" | "secondary" | "success" | "info" | "warning" | "error" | "neutral"
collapsible
true
boolean

When type is "single", prevents closing the open item when clicking its trigger. When type is "multiple", disables the collapsible behavior.

level
0
number
navigation
T[]
disabled
false
boolean

When true, prevents the user from interacting with the accordion and all its items

type
'multiple'
"single" | "multiple"

Determines whether a "single" or "multiple" items can be selected at a time.

This prop will overwrite the inferred type from modelValue and defaultValue.

unmountOnHide
true
boolean

When true, the element will be unmounted on closed state.

ui
{ root?: SlotClass; content?: SlotClass; list?: SlotClass; item?: SlotClass; listWithChildren?: SlotClass; itemWithChildren?: SlotClass; trigger?: SlotClass; link?: SlotClass; linkLeadingIcon?: SlotClass; linkTrailing?: SlotClass; linkTrailingBadge?: SlotClass; linkTrailingBadgeSize?: SlotClass; linkTrailingIcon?: SlotClass; linkTitle?: SlotClass; linkTitleExternalIcon?: SlotClass; }

Slot

Slot Type
link
{ link: T; active: boolean; ui: object; }
link-leading
{ link: T; active: boolean; ui: object; }
link-title
{ link: T; active: boolean; ui: object; }
link-trailing
{ link: T; active: boolean; ui: object; }

Emits

Event Type
update:modelValue
[value: string | string[] | undefined]

Theme

app.config.ts
export default defineAppConfig({
  ui: {
    contentNavigation: {
      slots: {
        root: '',
        content: 'data-[state=open]:animate-[accordion-down_200ms_var(--ease-out)] data-[state=closed]:animate-[accordion-up_200ms_var(--ease-out)] data-[state=closed]:overflow-hidden focus:outline-none',
        list: 'isolate -mx-2.5 -mt-1.5',
        item: '',
        listWithChildren: 'ms-5 border-s border-default',
        itemWithChildren: 'flex flex-col data-[state=open]:mb-1.5',
        trigger: 'font-semibold',
        link: 'group relative w-full px-2.5 py-1.5 before:inset-y-px before:inset-x-0 flex items-center gap-1.5 text-sm before:absolute before:z-[-1] before:rounded-md focus:outline-none focus-visible:outline-none focus-visible:before:outline-3',
        linkLeadingIcon: 'shrink-0 size-5',
        linkTrailing: 'ms-auto inline-flex gap-1.5 items-center',
        linkTrailingBadge: 'shrink-0',
        linkTrailingBadgeSize: 'sm',
        linkTrailingIcon: 'size-5 transform transition-transform duration-200 ease-out motion-reduce:transition-none shrink-0 group-data-[state=open]:rotate-180',
        linkTitle: 'truncate',
        linkTitleExternalIcon: 'size-3 align-top text-dimmed'
      },
      variants: {
        color: {
          primary: {
            link: 'before:outline-primary/25'
          },
          secondary: {
            link: 'before:outline-secondary/25'
          },
          success: {
            link: 'before:outline-success/25'
          },
          info: {
            link: 'before:outline-info/25'
          },
          warning: {
            link: 'before:outline-warning/25'
          },
          error: {
            link: 'before:outline-error/25'
          },
          neutral: {
            link: 'before:outline-inverted/25'
          }
        },
        highlightColor: {
          primary: '',
          secondary: '',
          success: '',
          info: '',
          warning: '',
          error: '',
          neutral: ''
        },
        variant: {
          pill: '',
          link: ''
        },
        active: {
          true: {
            link: 'font-medium'
          },
          false: {
            link: 'text-muted',
            linkLeadingIcon: 'text-dimmed'
          }
        },
        disabled: {
          true: {
            trigger: 'data-[state=open]:text-highlighted'
          }
        },
        highlight: {
          true: {}
        },
        level: {
          true: {
            item: 'ps-1.5 -ms-px',
            itemWithChildren: 'ps-1.5 -ms-px'
          }
        }
      },
      compoundVariants: [
        {
          highlight: true,
          level: true,
          class: {
            link: [
              'after:absolute after:-start-1.5 after:inset-y-0.5 after:block after:w-px after:rounded-full',
              'after:transition-colors'
            ]
          }
        },
        {
          disabled: false,
          active: false,
          variant: 'pill',
          class: {
            link: [
              'hover:text-highlighted hover:before:bg-elevated/50 data-[state=open]:text-highlighted',
              'transition-colors before:transition-colors'
            ],
            linkLeadingIcon: [
              'group-hover:text-default group-data-[state=open]:text-default',
              'transition-colors'
            ]
          }
        },
        {
          color: 'primary',
          variant: 'pill',
          active: true,
          class: {
            link: 'text-primary',
            linkLeadingIcon: 'text-primary group-data-[state=open]:text-primary'
          }
        },
        {
          color: 'neutral',
          variant: 'pill',
          active: true,
          class: {
            link: 'text-highlighted',
            linkLeadingIcon: 'text-highlighted group-data-[state=open]:text-highlighted'
          }
        },
        {
          variant: 'pill',
          active: true,
          highlight: false,
          class: {
            link: 'before:bg-elevated'
          }
        },
        {
          variant: 'pill',
          active: true,
          highlight: true,
          disabled: false,
          class: {
            link: [
              'hover:before:bg-elevated/50',
              'before:transition-colors'
            ]
          }
        },
        {
          disabled: false,
          active: false,
          variant: 'link',
          class: {
            link: [
              'hover:text-highlighted data-[state=open]:text-highlighted',
              'transition-colors'
            ],
            linkLeadingIcon: [
              'group-hover:text-default group-data-[state=open]:text-default',
              'transition-colors'
            ]
          }
        },
        {
          color: 'primary',
          variant: 'link',
          active: true,
          class: {
            link: 'text-primary',
            linkLeadingIcon: 'text-primary group-data-[state=open]:text-primary'
          }
        },
        {
          color: 'neutral',
          variant: 'link',
          active: true,
          class: {
            link: 'text-highlighted',
            linkLeadingIcon: 'text-highlighted group-data-[state=open]:text-highlighted'
          }
        },
        {
          highlightColor: 'primary',
          highlight: true,
          level: true,
          active: true,
          class: {
            link: 'after:bg-primary'
          }
        },
        {
          highlightColor: 'neutral',
          highlight: true,
          level: true,
          active: true,
          class: {
            link: 'after:bg-inverted'
          }
        }
      ],
      defaultVariants: {
        color: 'primary',
        highlightColor: 'primary',
        variant: 'pill'
      }
    }
  }
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'

export default defineConfig({
  plugins: [
    vue(),
    ui({
      ui: {
        contentNavigation: {
          slots: {
            root: '',
            content: 'data-[state=open]:animate-[accordion-down_200ms_var(--ease-out)] data-[state=closed]:animate-[accordion-up_200ms_var(--ease-out)] data-[state=closed]:overflow-hidden focus:outline-none',
            list: 'isolate -mx-2.5 -mt-1.5',
            item: '',
            listWithChildren: 'ms-5 border-s border-default',
            itemWithChildren: 'flex flex-col data-[state=open]:mb-1.5',
            trigger: 'font-semibold',
            link: 'group relative w-full px-2.5 py-1.5 before:inset-y-px before:inset-x-0 flex items-center gap-1.5 text-sm before:absolute before:z-[-1] before:rounded-md focus:outline-none focus-visible:outline-none focus-visible:before:outline-3',
            linkLeadingIcon: 'shrink-0 size-5',
            linkTrailing: 'ms-auto inline-flex gap-1.5 items-center',
            linkTrailingBadge: 'shrink-0',
            linkTrailingBadgeSize: 'sm',
            linkTrailingIcon: 'size-5 transform transition-transform duration-200 ease-out motion-reduce:transition-none shrink-0 group-data-[state=open]:rotate-180',
            linkTitle: 'truncate',
            linkTitleExternalIcon: 'size-3 align-top text-dimmed'
          },
          variants: {
            color: {
              primary: {
                link: 'before:outline-primary/25'
              },
              secondary: {
                link: 'before:outline-secondary/25'
              },
              success: {
                link: 'before:outline-success/25'
              },
              info: {
                link: 'before:outline-info/25'
              },
              warning: {
                link: 'before:outline-warning/25'
              },
              error: {
                link: 'before:outline-error/25'
              },
              neutral: {
                link: 'before:outline-inverted/25'
              }
            },
            highlightColor: {
              primary: '',
              secondary: '',
              success: '',
              info: '',
              warning: '',
              error: '',
              neutral: ''
            },
            variant: {
              pill: '',
              link: ''
            },
            active: {
              true: {
                link: 'font-medium'
              },
              false: {
                link: 'text-muted',
                linkLeadingIcon: 'text-dimmed'
              }
            },
            disabled: {
              true: {
                trigger: 'data-[state=open]:text-highlighted'
              }
            },
            highlight: {
              true: {}
            },
            level: {
              true: {
                item: 'ps-1.5 -ms-px',
                itemWithChildren: 'ps-1.5 -ms-px'
              }
            }
          },
          compoundVariants: [
            {
              highlight: true,
              level: true,
              class: {
                link: [
                  'after:absolute after:-start-1.5 after:inset-y-0.5 after:block after:w-px after:rounded-full',
                  'after:transition-colors'
                ]
              }
            },
            {
              disabled: false,
              active: false,
              variant: 'pill',
              class: {
                link: [
                  'hover:text-highlighted hover:before:bg-elevated/50 data-[state=open]:text-highlighted',
                  'transition-colors before:transition-colors'
                ],
                linkLeadingIcon: [
                  'group-hover:text-default group-data-[state=open]:text-default',
                  'transition-colors'
                ]
              }
            },
            {
              color: 'primary',
              variant: 'pill',
              active: true,
              class: {
                link: 'text-primary',
                linkLeadingIcon: 'text-primary group-data-[state=open]:text-primary'
              }
            },
            {
              color: 'neutral',
              variant: 'pill',
              active: true,
              class: {
                link: 'text-highlighted',
                linkLeadingIcon: 'text-highlighted group-data-[state=open]:text-highlighted'
              }
            },
            {
              variant: 'pill',
              active: true,
              highlight: false,
              class: {
                link: 'before:bg-elevated'
              }
            },
            {
              variant: 'pill',
              active: true,
              highlight: true,
              disabled: false,
              class: {
                link: [
                  'hover:before:bg-elevated/50',
                  'before:transition-colors'
                ]
              }
            },
            {
              disabled: false,
              active: false,
              variant: 'link',
              class: {
                link: [
                  'hover:text-highlighted data-[state=open]:text-highlighted',
                  'transition-colors'
                ],
                linkLeadingIcon: [
                  'group-hover:text-default group-data-[state=open]:text-default',
                  'transition-colors'
                ]
              }
            },
            {
              color: 'primary',
              variant: 'link',
              active: true,
              class: {
                link: 'text-primary',
                linkLeadingIcon: 'text-primary group-data-[state=open]:text-primary'
              }
            },
            {
              color: 'neutral',
              variant: 'link',
              active: true,
              class: {
                link: 'text-highlighted',
                linkLeadingIcon: 'text-highlighted group-data-[state=open]:text-highlighted'
              }
            },
            {
              highlightColor: 'primary',
              highlight: true,
              level: true,
              active: true,
              class: {
                link: 'after:bg-primary'
              }
            },
            {
              highlightColor: 'neutral',
              highlight: true,
              level: true,
              active: true,
              class: {
                link: 'after:bg-inverted'
              }
            }
          ],
          defaultVariants: {
            color: 'primary',
            highlightColor: 'primary',
            variant: 'pill'
          }
        }
      }
    })
  ]
})
Some colors in compoundVariants are omitted for readability. Check out the source code on GitHub.

Changelog

No recent changes