ContentSurround

A pair of prev and next links to navigate between pages.
This component is only available when the @nuxt/content module is installed.

Usage

Use the surround prop with the surround value you get when fetching a page surround.

<script setup lang="ts">
const route = useRoute()

const { data: surround } = await useAsyncData(`${route.path}-surround`, () => {
  return queryCollectionItemSurroundings('content', route.path, {
    fields: ['description']
  })
})
</script>

<template>
  <UContentSurround :surround="(surround as any)" />
</template>

Prev / Next

Use the prev-icon and next-icon props to customize the buttons Icon.

<script setup lang="ts">
const surround = ref([
  {
    title: 'ContentSearchButton',
    path: '/components/content-search-button',
    stem: '3.components/content-search-button',
    description: 'A pre-styled Button to open the ContentSearch modal.'
  },
  {
    title: 'ContentToc',
    path: '/components/content-toc',
    stem: '3.components/content-toc',
    description: 'A sticky Table of Contents with customizable slots.'
  }
])
</script>

<template>
  <UContentSurround
    prev-icon="i-lucide-chevron-left"
    next-icon="i-lucide-chevron-right"
    :surround="surround"
  />
</template>

Examples

Within a page

Use the ContentSurround component in a page to display the prev and next links:

pages/[...slug].vue
<script setup lang="ts">
const route = useRoute()

const { data: page } = await useAsyncData(route.path, () => queryCollection('content').path(route.path).first())
if (!page.value) {
  throw createError({ statusCode: 404, statusMessage: 'Page not found', fatal: true })
}
</script>

<template>
  <UPage v-if="page">
    <UPageHeader :title="page.title" />

    <UPageBody>
      <ContentRenderer v-if="page.body" :value="page" />

      <USeparator v-if="surround?.filter(Boolean).length" />

      <UContentSurround :surround="(surround as any)" />
    </UPageBody>

    <template v-if="page?.body?.toc?.links?.length" #right>
      <UContentToc :links="page.body.toc.links" />
    </template>
  </UPage>
</template>

API

Props

Prop Default Type
as

'div'

any

The element or component this component should render as.

prevIcon

appConfig.ui.icons.arrowLeft

string

The icon displayed in the prev link.

nextIcon

appConfig.ui.icons.arrowRight

string

The icon displayed in the next link.

surround

ContentSurroundLink[]

ui

PartialString<{ root: string; link: string[]; linkLeading: string[]; linkLeadingIcon: string[]; linkTitle: string; linkDescription: string; }>

Slots

Slot Type
link

{ link: ContentSurroundLink; }

link-leading

{ link: ContentSurroundLink; }

link-title

{ link: ContentSurroundLink; }

link-description

{ link: ContentSurroundLink; }

Theme

app.config.ts
export default defineAppConfig({
  uiPro: {
    contentSurround: {
      slots: {
        root: 'grid sm:grid-cols-2 gap-8',
        link: [
          'group block px-6 py-8 rounded-[calc(var(--ui-radius)*2)] border border-(--ui-border) hover:bg-(--ui-bg-elevated)/50 focus-visible:outline-(--ui-primary)',
          'transition-colors'
        ],
        linkLeading: [
          'inline-flex items-center rounded-full p-1.5 bg-(--ui-bg-elevated) group-hover:bg-(--ui-primary)/10 ring ring-(--ui-border-accented) mb-4 group-hover:ring-(--ui-primary)/50',
          'transition'
        ],
        linkLeadingIcon: [
          'size-5 shrink-0 text-(--ui-text-highlighted) group-hover:text-(--ui-primary)',
          'transition-[color,translate]'
        ],
        linkTitle: 'font-medium text-[15px] text-(--ui-text-highlighted) mb-1 truncate',
        linkDescription: 'text-sm text-(--ui-text-muted) line-clamp-2'
      },
      variants: {
        direction: {
          left: {
            linkLeadingIcon: [
              'group-active:-translate-x-0.5'
            ]
          },
          right: {
            link: 'text-right',
            linkLeadingIcon: [
              'group-active:translate-x-0.5'
            ]
          }
        }
      }
    }
  }
})
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({
      uiPro: {
        contentSurround: {
          slots: {
            root: 'grid sm:grid-cols-2 gap-8',
            link: [
              'group block px-6 py-8 rounded-[calc(var(--ui-radius)*2)] border border-(--ui-border) hover:bg-(--ui-bg-elevated)/50 focus-visible:outline-(--ui-primary)',
              'transition-colors'
            ],
            linkLeading: [
              'inline-flex items-center rounded-full p-1.5 bg-(--ui-bg-elevated) group-hover:bg-(--ui-primary)/10 ring ring-(--ui-border-accented) mb-4 group-hover:ring-(--ui-primary)/50',
              'transition'
            ],
            linkLeadingIcon: [
              'size-5 shrink-0 text-(--ui-text-highlighted) group-hover:text-(--ui-primary)',
              'transition-[color,translate]'
            ],
            linkTitle: 'font-medium text-[15px] text-(--ui-text-highlighted) mb-1 truncate',
            linkDescription: 'text-sm text-(--ui-text-muted) line-clamp-2'
          },
          variants: {
            direction: {
              left: {
                linkLeadingIcon: [
                  'group-active:-translate-x-0.5'
                ]
              },
              right: {
                link: 'text-right',
                linkLeadingIcon: [
                  'group-active:translate-x-0.5'
                ]
              }
            }
          }
        }
      }
    })
  ]
})