Nuxt Content v3-alpha has been released!

Try it out
Usage

Markdown

Nuxt Content uses the Markdown syntax and conventions to provide a rich-text editing experience.

Introduction

We created the MDC syntax to supercharge Markdown and give you the ability to leverage the power of Vue components with slots and props.

Install the MDC VS Code extension to get proper syntax highlighting for your MDC components.

Front-matter

Front-matter is a convention of Markdown-based CMS to provide meta-data to pages, like description or title. In Nuxt Content, the front-matter uses the YAML syntax with key: value pairs.

These data are available when rendering the content and can hold any information that you would need.

Syntax

You can declare a front-matter block at the top of the Markdown files in the content/ directory with the --- identifier.

content/index.md
---
title: 'Title of the page'
description: 'meta description of the page'
---

<!-- Content of the page -->

Native parameters

KeyTypeDefaultDescription
titlestringFirst <h1> of the pageTitle of the page, will also be injected in metas
descriptionstringFirst <p> of the pageDescription of the page, will be shown below the title and injected into the metas
draftbooleanfalseMark the page as draft (and only display it in development mode).
navigationbooleantrueDefine if the page is included in fetchContentNavigation return value.
headobjecttrueEasy access to useContentHead

When used together with <ContentDoc> or the document-driven mode to display the current page, the useContentHead() composable will be used to set the page's metadata.

Excerpt

Content excerpt or summary can be extracted from the content using <!--more--> as a divider.

---
title: Introduction
---

Learn how to use @nuxt/content.
<!--more-->
Full amount of content beyond the more divider.

Description property will contain the excerpt content unless defined within the Front Matter props.

If there is no <!--more--> divider in the text then excerpt is undefined.

Example variables will be injected into the document:

{
  "_id": "content:index.md"
  "excerpt": Object
  "body": Object
  // ... other keys
}

Code Highlighting

Nuxt Content uses Shiki, that colors tokens with VSCode themes.

Code highlighting works both on ProsePre and ProseCodeInline.

Each line of a code block gets its line number in the line attribute so lines can be labeled or individually styled.

Images

You can add images to your public directory:

content/
  index.md
public/
  img/
    image.png
nuxt.config.ts
package.json
tsconfig.json

And then use them in your markdown files in the content directory as such:

content/index.md
![my image](/img/image.png)

Vue Components

Every Vue component created inside the components/content/ directory will be available in Markdown files.

Components that are used in Markdown has to be marked as global in your Nuxt app if you don't use the components/content/ directory, visit Nuxt 3 docs to learn more about it.

Block Components

Block components are components that accept Markdown content or another component as a slot.

The component must contain either:

  • A <slot /> to accept raw text or another component.
  • The <ContentSlot /> component to accept formatted text.

In a markdown file, use the component with the :: identifier.

::card
The content of the card
::

Slots

A component's slots can accept content or another components.

  • The default slot renders the top-level content inside the block component.
  • named slots use the # identifier to render the corresponding content.
::hero
Default slot text

#description
This will be rendered inside the `description` slot.
::

Nesting

MDC supports nested components inside slots by indenting them.

::hero
  :::card
    A nested card
    ::card
      A super nested card
    ::
  :::
::
You can add more :::: when nesting components as a visual reminder.

Markdown rendering

The <ContentSlot /> component is auto-imported by Nuxt Content. It acts as a special slot that accepts rich text rendered by Markdown.

The unwrap prop accepts an HTML tag that will be used to unwrap the content, useful when using tags such as title tags (<h1>, <h2>, ...) or inline tags (<button>, <a>, ...).

<!-- components/content/TheTitle.vue -->
<template>
  <h1 class="text-4xl">
    <ContentSlot :use="$slots.default" unwrap="p" />
  </h1>
</template>

The <ContentSlot /> component can act as a named slot with the use property:

<ContentSlot :use="$slots.description" unwrap="p">

Inline components

Inline components are components without slots or <ContentSlot />.

They can be used with the : identifier.

# Title

:banner

If you want to use an inline component followed by specific characters like -, _ or :, you can use a dummy props specifier after it.

:hello{}-world

In this example, :hello{} will search for the <Hello /> component, and -world will be plain text.

Props

There are two ways to pass props to components using MDC.

Inline method

The {} identifier passes props to components in a terse way by using a key=value syntax.

::alert{type="warning"}
The **alert** component.
::

Multiple props can be separated with a space:

::alert{type="warning" icon="exclamation-circle"}
Oops! An error occurred
::

The v-bind shorthand : can be also be used to bind a prop to a value in the front matter.

---
type: "warning"
---

::alert{:type="type"}
Your warning
::

If you want to pass arrays or objects as props to components you can pass them as JSON string and prefix the prop key with a colon to automatically decode the JSON string. Note that in this case you should use single quotes for the value string so you can use double quotes to pass a valid JSON string:

::dropdown{:items='["Nuxt", "Vue", "React"]'}
::

YAML method

The YAML method uses the --- identifier to declare one prop per line, that can be useful for readability.

::icon-card
---
icon: IconNuxt
description: Harness the full power of Nuxt and the Nuxt ecosystem.
title: Nuxt Architecture.
---
::

Span Text

To create inline spans in your text you can use the [] identifier.

Hello [World]{style="background-color: var(--color-primary-500)"}!

Attributes

Attributes are useful for highlighting and modifying part of paragraph. The syntax is nearly similar to inline components and markdown links syntax.

Possible values ​​are all named attributes, classes with the notation .class-name and an ID with #id-name.

Hello [World]{style="color: green;" .custom-class #custom-id}!

In addition to mdc components and span, attribute syntax will work on images, links, inline code, bold and italic text.

Attributes work on:

- ![](/favicon.ico){style="display: inline; margin: 0;"} image,
- [link](#attributes){style="background-color: pink;"}, `code`{style="color: cyan;"},
- _italic_{style="background-color: yellow; color:black;"} and **bold**{style="background-color: lightgreen;"} texts.

Binding Data in Markdown

You can bind data within your Markdown document using the {{ $doc.variable || 'defaultValue' }} syntax. These values can be defined in the YAML front matter at the top of the document, within each MDC component, or injected using the data prop of the <ContentRendererMarkdown> component.

Example 1: Define in YAML

---
title: 'Title of the page'
description: 'meta description of the page'
customVariable: 'Custom Value'
---

# The Title is {{ $doc.title }} and customVariable is {{ $doc.customVariable || 'defaultValue' }}

Example 2: Define in external with <ContentRendererMarkdown>

<template>
  <div>
    <ContentRendererMarkdown :value="data" :data="mdcVars"/>
    <button type="button" v-on:click="mdcVars.name = 'Hugo'">Change name</button>
  </div>
</template>

<script setup lang="ts">
const { data } = await useAsyncData(() => queryContent('test').findOne());
const mdcVars = ref({ name: 'Maxime'});
</script>

# Hello {{ $doc.name || 'World' }}

Prose Components

In Nuxt Content, the prose represents HTML tags generated by the Markdown syntax, such as title levels and links.

For each HTML tag, a Vue component is used, allowing you to override them if needed, for example <p> becomes <ProseP>.

If you want to customize a Prose component, here are the recommended steps:

  • Checkout the original component sources.
  • Use the exact same props.
  • In your components/content/ directory, give it the same name.
  • Make it yours πŸš€.
Read the complete Prose reference in the Prose Components section.