Nuxt Content
Learn how to make your website editable through Studio.
What is Nuxt Content?
@nuxt/content is a Nuxt module that allows developers to integrate Markdown content into their Nuxt applications. This enables developers to focus on the website's structure and design, while allowing editors to manage content using our powerful Markdown syntax.
To build a custom application, it's essential to understand how this module works. Don't hesitate to consult the documentation for detailed information.
Nuxt Studio leverages this module to provide a seamless way to create and edit content with a live preview, all without leaving your browser.
@nuxt/content
v2, your website is already compatible with Nuxt Studio.Demo
Let's create a demo where developers can focus on website structure and design, leaving content editing to the experts.
Minimal Starter
Nuxt Content offers a minimal starter that you can clone directly from Studio. Below is what it looks like when deployed in Studio.
Customize Everything
Not quite appealing, is it? Let's clone it from GitHub and enhance its visual appeal.
As a developer, I prioritize efficiency, and because I love Nuxt and Tailwind, I'll use Nuxt UI Pro to save time. You can, of course, use any library or CSS framework of your choice.
The first thing we should do is to improve the basic app.vue
of our starter. Here's how it currently looks:
<template>
<div>
<NuxtPage />
</div>
</template>
Let's add a header, a footer, and encapsulate everything in the appropriate components.
<template>
<div>
<UHeader>
<template #logo>
<span>
Demo Studio
</span>
</template>
<template #right>
<UColorModeButton />
</template>
</UHeader>
<UMain>
<NuxtPage />
</UMain>
<UFooter>
<template #right>
<div class="flex items-center justify-center gap-4">
<UButton
icon="i-mdi-github"
:to="`https://github.com/larbish`"
color="gray"
variant="ghost"
target="_blank"
:padded="false"
/>
<UButton
icon="i-mdi-twitter"
:to="`https://twitter.com/_larbish`"
color="gray"
variant="ghost"
target="_blank"
:padded="false"
/>
</div>
</template>
</UFooter>
</div>
</template>
The starter is built with a simple catch-all page [...slug].vue
. It uses the ContentDoc
component, which, based on your current path, fetches the appropriate content file in your content folder (/about
will fetch and display content/about.md
).
<template>
<main>
<ContentDoc />
</main>
</template>
To make this page more appealing, we'll utilize the ContentRenderer
component. To do this, we need to fetch the page ourselves using the queryContent
composable. Now we have access to our page's front-matter
data, and we can create a page header based on it. Finally we can add a navigation using the fetchContentNavigation
composable.
<template>
<UMain>
<UContainer>
<UPage>
<UPageHeader :title="page.title" :description="page.description" />
<template #left>
<UAside>
<UNavigationTree :links="mapContentNavigation(navigation)" />
</UAside>
</template>
<UPageBody prose>
<ContentRenderer v-if="page.body" :value="page" />
</UPageBody>
</UPage>
</UContainer>
</UMain>
</template>
<script setup lang="ts">
const route = useRoute()
const { data: page } = await useAsyncData(route.path, () => queryContent(route.path).findOne())
if (!page.value) {
throw createError({ statusCode: 404, statusMessage: 'Page not found' })
}
const { data: navigation } = await useAsyncData('navigation', () => fetchContentNavigation())
</script>
Once you're satisfied with your design and structure, simply push your work, wait for the deployment, and it should be available on Studio.
Edit From Studio
It already looks much better! Now, let's edit the content directly from Studio.
MDC syntax
How about incorporating custom components directly into your page from the Markdown editor? You could create the component you want and give ability from Studio to add it and customise it on any page.
To achieve this, a developer needs to create a Vue component in the components/content
folder. Here's an example with a PictureCard.vue
component:
<template>
<UCard :ui="{ ring: `ring-2 ring-${color}-200 dark:ring-${color}-800`}">
<template #header>
<div class="flex justify-center text-2xl font-bold">
<ContentSlot name="title" unwrap="p" />
</div>
</template>
<slot />
<template #footer>
<div class="flex justify-center text-gray-500">
<ContentSlot name="description" unwrap="p" />
</div>
</template>
</UCard>
</template>
<script setup lang="ts">
defineProps({
color: {
type: String,
default: null
}
})
</script>
That's an easy one, a custom card based on UCard
with a title, a description, a default slot where I can put a picture and color prop you can play with.
Once it's deployed, editors can easily work with it inside any Markdown file, thanks to the MDC syntax.