---
title: "MDC syntax"
description: "How pages are written: Markdown with blocks, their slots and options, nested blocks and inline components."
canonical_url: "http://localhost:3000/writing-pages/mdc-syntax"
---
# MDC syntax

> How pages are written: Markdown with blocks, their slots and options, nested blocks and inline components.

Pages are Markdown files in `content/` written in [MDC](https://content.nuxt.com/docs/files/markdown), Markdown with components. A page is plain Markdown (headings, paragraphs, lists, links, images) and **blocks**: the components of this library, written `::name` … `::`. Nuxt Studio reads and writes the same syntax, so a page written by hand, by an agent or in Studio is the same file.

## Blocks

A block opens with two colons and its name, and closes with two colons. What is between them is its content.

```mdc
::card
### A card

Its content is Markdown.
::
```

A block without content still closes: `::testimonial-carousel` then `::` on the next line.

## Options

Options go in braces after the name, in kebab-case, values in double quotes. They only configure the block (its look, a link, a number): text never goes in an option.

```mdc
::button-link{href="/membership/" icon="lucide:arrow-right" icon-position="after"}
Become a member
::
```

- **Booleans** are written bare to set them: `::card{href="/about/" new-tab}`; leave them out for `false`.
- **Numbers** are written as text: `count="3"`.
- **Many options** can go in a YAML block right after the opening line, between `---` lines (the same options, the same names):

```mdc
::button-link
---
href: /membership/
icon: lucide:arrow-right
icon-position: after
---
Become a member
::
```

The [Options](http://localhost:3000/writing-pages/slots-and-options) shared by blocks have the same name and values everywhere; each block's page lists its own. The options tables list them by their prop name (`iconPosition`): MDC accepts both spellings, and Studio writes inline options in kebab-case.

## Slots

A block's content is its **default slot**. Many blocks have **named slots** too: parts of the block with a place of their own (a title, buttons, an image). A named slot starts with `#name` on its own line, at the block's indentation, and runs until the next slot or the end of the block.

```mdc
::hero
The text below the title: the default slot.

#eyebrow
Join us

#title
A working group for open specifications

#actions
  :::button-link{href="/membership/"}
  Become a member
  :::
::
```

- Write the **default content first** and the named slots after it, as Studio does.
- Everything after `#name` belongs to that slot, blocks included: a block meant for the default slot goes before the first `#name`.
- `#default` names the default slot explicitly; it is needed when the default content comes after named slots (see the [rules](http://localhost:3000/writing-pages/rules)).
- A title, a label or a short text in a slot is inline: the block shows it without a paragraph around it.

## Nesting

A block inside a block has one more colon, and its lines are indented by 2 more spaces. Slot markers sit at the indentation of their block's fence.

```mdc
::page-section
  :::grid
    ::::card
    ### First

    A card in a grid in a section.
    ::::

    ::::card
    ### Second

    Cards in a row share its height.
    ::::
  :::

#title
Blocks in blocks
::
```

Levels: `::` for a block of the page, `:::` inside it, `::::` inside that, and so on. A block in a named slot is nested in the block that owns the slot:

```mdc
::call-to-action
Ready to take part?

#title
Join the working group

#actions
  :::button-link{href="/membership/"}
  Become a member
  :::
::
```

A few combinations of nested blocks and named slots don't survive a save in Studio: see [Nesting rules](http://localhost:3000/writing-pages/rules#nesting).

## Inline components

Some blocks also work inside a sentence or a title, with one colon: `:name`, then the words in brackets, then the options in braces. A space on each side of it.

```mdc
Write to us :icon{name="lucide:mail"} or read the :text-link[latest news]{href="/news/" icon="lucide:arrow-right"} first.

A title with :typography[a highlighted word]{color="primary"} and a :badge[New] badge.
```

The inline blocks are `icon`, `text-link`, `button-link`, `typography`, `badge`, and the live data mentions (`newsroom-event-mention`, `newsroom-news-mention`). The words in brackets are the block's default slot: write them, so search, feeds and summaries read them.

## Markdown in blocks

Inside a block, and in its slots, Markdown works as everywhere:

- **Headings**: `##` to `####`, no `#`: the page's title is its level-1 heading (the page header, or the hero's, shows it). A `card`'s first heading is its title, a `tab`'s first `###` its label.
- **Lists**, **links** (`[text](/path/)`), **bold** and *italic*, tables (in a `data-table` or `comparison-table`).
- **Images** are Markdown images, `![Description of the image](/path/to/image.jpg)`: in a block's `#media` slot they take the block's look; a `media` block around one gives it options (corners, crop, caption). Never an image in an option.
- **Line breaks** inside a paragraph: end the line with two spaces, or `:br` between words (with a space on each side next to a link).

```mdc
::media-split
## Text beside an image

A paragraph with a [link](/about/), **bold** text and a list:

- First point
- Second point

#media
![A landscape](/solstice-ui/landscape-1.svg)
::
```

## What isn't allowed

- No raw HTML, and no `class` or `style` attributes: a block's look is its options, and the site's theme styles them.
- No CSS, no scripts: a page is content only.
- Text goes in content and slots, never in options.

The full list, with examples: [Rules](http://localhost:3000/writing-pages/rules).


## Sitemap

See the full [sitemap](http://localhost:3000/sitemap.md) for all pages.
