ContentNavigation

GitHub
An accordion-style navigation component for organizing page links.
This component is only available when the @nuxt/content module is installed.

Usage

Use the navigation prop with the navigation value you get when fetching the navigation of your app.

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

const navigation = inject<Ref<Array<ContentNavigationItem>>>('navigation');
</script>

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

Type

Set the type prop to single to only allow one item to be open at a time. Defaults to multiple.

<script setup lang="ts">
const navigation = ref([
  {
    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>
  <PContentNavigation type="single" />
</template>

Color

Use the color prop to change the color of the navigation links.

<script setup lang="ts">
const navigation = ref([
  {
    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>
  <PContentNavigation color="neutral" />
</template>

Variant

Use the variant prop to change the variant of the navigation links.

<script setup lang="ts">
const navigation = ref([
  {
    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>
  <PContentNavigation variant="link" />
</template>

Highlight

Use the highlight prop to display a highlighted border for the active link.

Use the highlight-color prop to change the color of the border. It defaults to the color prop.

<script setup lang="ts">
const navigation = ref([
  {
    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>
  <PContentNavigation highlight highlight-color="primary" color="primary" variant="pill" />
</template>

Trailing Icon

<script setup lang="ts">
const navigation = ref([
  {
    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>
  <PContentNavigation trailing-icon="i-lucide:arrow-up" />
</template>

Examples

Within a layout

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

const navigation = inject<Ref<Array<ContentNavigationItem>>>('navigation');
</script>

<template>
  <ExampleLayout>
    <template #left>
      <div>
        <PContentNavigation
          :navigation="navigation"
          highlight
        />
      </div>
    </template>

    <slot />
  </ExampleLayout>
</template>

Within a header

Use the ContentNavigation component inside the content slot of a Header component to display the navigation of the page on mobile:

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

const navigation = inject<Ref<Array<ContentNavigationItem>>>('navigation');
</script>

<template>
  <PHeader>
    <template #body>
      <PContentNavigation
        :navigation="navigation"
        highlight
      />
    </template>
  </PHeader>
</template>

API

Props

Prop Default Type
as'nav'any

The element or component this component should render as.

defaultOpenundefinedboolean

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

trailingIconappConfig.pohon.icons.chevronDown string | object

The icon displayed to toggle the accordion.

color'primary' "primary" | "secondary" | "success" | "info" | "warning" | "error" | "neutral"
variant'pill' "pill" | "link"
highlightfalseboolean

Display a line next to the active link.

highlightColor'primary' "primary" | "secondary" | "success" | "info" | "warning" | "error" | "neutral"
collapsibletrueboolean

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

level0 number
navigation T[]
disabledfalseboolean

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

type'multiple' "multiple" | "single"

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

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

unmountOnHidetrueboolean

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

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

Slots

Slot Type
link{ link: T; active?: boolean | undefined; pohon: object; }
link-leading{ link: T; active?: boolean | undefined; pohon: object; }
link-title{ link: T; active?: boolean | undefined; pohon: object; }
link-trailing{ link: T; active?: boolean | undefined; pohon: object; }

Emits

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

Theme

We use unocss-variants to customize the theme. Read more about it in the theming guide.

Below is the theme configuration skeleton for the PContentNavigation. Since the component is provided unstyled by default, you will need to fill in these values to apply your own custom look and feel. If you prefer to use our pre-built, opinionated styling, you can instead use our UnoCSS preset, this docs is using it as well.

app.config.ts
export default defineAppConfig({
  pohon: {
    contentNavigation: {
      slots: {
        root: '',
        content: '',
        list: '',
        item: '',
        listWithChildren: '',
        itemWithChildren: '',
        trigger: '',
        link: '',
        linkLeadingIcon: '',
        linkTrailing: '',
        linkTrailingBadge: '',
        linkTrailingBadgeSize: '',
        linkTrailingIcon: '',
        linkTitle: '',
        linkTitleExternalIcon: ''
      },
      variants: {
        color: {
          primary: {
            trigger: '',
            link: ''
          },
          secondary: {
            trigger: '',
            link: ''
          },
          success: {
            trigger: '',
            link: ''
          },
          info: {
            trigger: '',
            link: ''
          },
          warning: {
            trigger: '',
            link: ''
          },
          error: {
            trigger: '',
            link: ''
          },
          neutral: {
            trigger: '',
            link: ''
          }
        },
        highlightColor: {
          primary: '',
          secondary: '',
          success: '',
          info: '',
          warning: '',
          error: '',
          neutral: ''
        },
        variant: {
          pill: '',
          link: ''
        },
        active: {
          true: {
            link: ''
          },
          false: {
            link: '',
            linkLeadingIcon: ''
          }
        },
        disabled: {
          true: {
            trigger: ''
          }
        },
        highlight: {
          true: {}
        },
        level: {
          true: {
            item: '',
            itemWithChildren: ''
          }
        }
      },
      defaultVariants: {
        color: 'primary',
        highlightColor: 'primary',
        variant: 'pill'
      }
    }
  }
};
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import pohon from 'pohon-ui/vite'

export default defineAppConfig({
  pohon: {
    contentNavigation: {
      slots: {
        root: '',
        content: '',
        list: '',
        item: '',
        listWithChildren: '',
        itemWithChildren: '',
        trigger: '',
        link: '',
        linkLeadingIcon: '',
        linkTrailing: '',
        linkTrailingBadge: '',
        linkTrailingBadgeSize: '',
        linkTrailingIcon: '',
        linkTitle: '',
        linkTitleExternalIcon: ''
      },
      variants: {
        color: {
          primary: {
            trigger: '',
            link: ''
          },
          secondary: {
            trigger: '',
            link: ''
          },
          success: {
            trigger: '',
            link: ''
          },
          info: {
            trigger: '',
            link: ''
          },
          warning: {
            trigger: '',
            link: ''
          },
          error: {
            trigger: '',
            link: ''
          },
          neutral: {
            trigger: '',
            link: ''
          }
        },
        highlightColor: {
          primary: '',
          secondary: '',
          success: '',
          info: '',
          warning: '',
          error: '',
          neutral: ''
        },
        variant: {
          pill: '',
          link: ''
        },
        active: {
          true: {
            link: ''
          },
          false: {
            link: '',
            linkLeadingIcon: ''
          }
        },
        disabled: {
          true: {
            trigger: ''
          }
        },
        highlight: {
          true: {}
        },
        level: {
          true: {
            item: '',
            itemWithChildren: ''
          }
        }
      },
      defaultVariants: {
        color: 'primary',
        highlightColor: 'primary',
        variant: 'pill'
      }
    }
  }
};

Changelog

No recent changes