Document (dev.stxt.website): STXT: prose inside structure
Metadata:
Last modif: 2026-09-24
Description: STXT puts prose inside structure. The same lesson in Markdown with Frontmatter, MDX, Markdoc, YAML and STXT: where the structure goes and what each one validates.
Header: @STXT@, prose inside structure
Assert >>
Frontmatter, MDX and Markdoc embed the structure in the prose.
@STXT@ embeds the prose in the structure, so **the whole document can be validated**.
Subheader: CMS and structure validation
Content >>
When a document needs prose, Markdown is the usual choice. The problem appears
when it also needs a structure that must be validated. The usual solution is to
insert the structure **inside** Markdown, using another language. Most of the time
this allows a partial validation, but with solutions that look more like a hack
than a structural answer. The cost is this:
- More languages in play
- Harder writing for non-technical people
- Less readability overall
- Less uniform environments
- Text mixed with code
This article shows how @STXT@ inverts the solution: it inserts the prose inside
a structure that can be validated.
We show the same document, a `Lesson` with a specific structure, and how it is
validated with each of the current solutions. We also show it in YAML and in KDL,
two formats that do allow prose inside the structure, although they are not
usual in a CMS.
Subheader: @STXT@ with Markdown
Code >>
Lesson (com.example.school): What is STXT?
Authors:
Author: Joan Costa
Author: James Smith
Teacher: Sheila Jones
Difficulty: easy
Introduction >>
STXT is a **hierarchical text format**: easy for
people to read and trivial for machines to parse.
Content >>
A document is a tree of nodes. There are only two kinds:
- `Name: value`, for short inline values.
- `Name >>`, for a block of literal text, like this one.
Indentation *is* the structure: no closing tags, no quotes
and no escape characters.
Question: Do you know another similar format?
Answer: XML, for example
Content >>
Comments are all the lines that start with `#`.
Documents may have namespaces. You define them
with `Name (namespace.name)`.
Conclusion >>
With two kinds of node and indentation you can describe any document.
A template adds **validation** on top, without changing the syntax.
Quiz:
Question: How is the structure of a document expressed?
Answer >>
With indentation: a node is a child of the closest
previous node with one level less.
Question: What happens to the text inside a `>>` block?
Answer >>
It is kept literally. Nothing inside is interpreted.
It can be Markdown, code or any other text.
Content >>
And the template that validates structure and cardinality:
Code >>
Template (@stxt.template): com.example.school
Structure >>
Lesson:
Authors: (1)
Author: (+)
Teacher: (1)
Difficulty: (?) ENUM [easy, medium, hard]
Introduction: (?) MARKDOWN
Content: (*) MARKDOWN
Question: (*)
Answer: (1) MARKDOWN
Conclusion: (?) MARKDOWN
Quiz: (?) GROUP
Question: (+) @Question
Content >>
The whole document can be validated with the template: structure, cardinality and content.
In the prose, no escape characters are needed. A document with errors does not validate:
Code >>
# ERROR: this document does not validate
Lesson (com.example.school): What is STXT?
Authors:
Author: Joan Costa
# `Teacher` is missing
# `trivial` is not a difficulty from the list
Difficulty: trivial
Introduction >>
STXT is a **hierarchical text format**.
Subheader: Frontmatter
Markdown >>
---
type: lesson
title: What is STXT?
authors:
- Joan Costa
- James Smith
teacher: Sheila Jones
difficulty: easy
---
# Introduction
STXT is a **hierarchical text format**: easy for
people to read and trivial for machines to parse.
# Content
A document is a tree of nodes. There are only two kinds:
- `Name: value`, for short inline values.
- `Name >>`, for a block of literal text, like this one.
Indentation *is* the structure: no closing tags, no quotes
and no escape characters.
**Question**: Do you know another similar format?
**Answer**: XML, for example
# Content
Comments are all the lines that start with `#`.
Documents may have namespaces. You define them
with `Name (namespace.name)`.
# Conclusion
With two kinds of node and indentation you can describe any document.
A template adds **validation** on top, without changing the syntax.
# Quiz
## How is the structure of a document expressed?
With indentation: a node is a child of the closest
previous node with one level less.
## What happens to the text inside a `>>` block?
It is kept literally. Nothing inside is interpreted.
It can be Markdown, code or any other text.
Content >>
The question, the answer and the quiz are a convention,
and nothing checks that structure.
The Frontmatter can be validated with an external schema:
JSON Schema, or a Zod schema in Astro content collections.
Subheader: MDX
Markdown >>
---
type: lesson
title: What is STXT?
authors:
- Joan Costa
- James Smith
teacher: Sheila Jones
difficulty: easy
---
import { Question, Quiz } from '../components/Lesson'
# Introduction
STXT is a **hierarchical text format**: easy for
people to read and trivial for machines to parse.
# Content
A document is a tree of nodes. There are only two kinds:
- `Name: value`, for short inline values.
- `Name >>`, for a block of literal text, like this one.
Indentation *is* the structure: no closing tags, no quotes
and no escape characters.
XML, for example
# Content
Comments are all the lines that start with `#`.
Documents may have namespaces. You define them
with `Name (namespace.name)`.
# Conclusion
With two kinds of node and indentation you can describe any document.
A template adds **validation** on top, without changing the syntax.
With indentation: a node is a child of the closest
previous node with one level less.
It is kept literally. Nothing inside is interpreted.
It can be Markdown, code or any other text.
Content >>
`Question` and `Quiz` are JavaScript components defined in another file.
The document compiles to a JavaScript module, mixing the document with code.
In the prose, `<` and `{` open JSX and expressions, so they must be escaped.
Subheader: Markdoc
Markdown >>
---
type: lesson
title: What is STXT?
authors:
- Joan Costa
- James Smith
teacher: Sheila Jones
difficulty: easy
---
# Introduction
STXT is a **hierarchical text format**: easy for
people to read and trivial for machines to parse.
# Content
A document is a tree of nodes. There are only two kinds:
- `Name: value`, for short inline values.
- `Name >>`, for a block of literal text, like this one.
Indentation *is* the structure: no closing tags, no quotes
and no escape characters.
{% question text="Do you know another similar format?" %}
XML, for example
{% /question %}
# Content
Comments are all the lines that start with `#`.
Documents may have namespaces. You define them
with `Name (namespace.name)`.
# Conclusion
With two kinds of node and indentation you can describe any document.
A template adds **validation** on top, without changing the syntax.
{% quiz %}
{% question text="How is the structure of a document expressed?" %}
With indentation: a node is a child of the closest
previous node with one level less.
{% /question %}
{% question text="What happens to the text inside a `>>` block?" %}
It is kept literally. Nothing inside is interpreted.
It can be Markdown, code or any other text.
{% /question %}
{% /quiz %}
Content >>
The schema is a JavaScript object. It declares the tags, their attributes and which children they accept:
TypeScript >>
const config = {
tags: {
question: {
render: 'Question',
attributes: {
text: { type: String, required: true },
},
},
quiz: {
render: 'Quiz',
children: ['tag'],
},
},
};
const ast = Markdoc.parse(source);
const errors = Markdoc.validate(ast, config);
Content >>
Cardinality is not declarative, and the document is mixed with code in another language.
Subheader: YAML with Markdown
Yaml >>
type: lesson
title: What is STXT?
authors:
- Joan Costa
- James Smith
teacher: Sheila Jones
difficulty: easy
introduction: |
STXT is a **hierarchical text format**: easy for
people to read and trivial for machines to parse.
body:
- content: |
A document is a tree of nodes. There are only two kinds:
- `Name: value`, for short inline values.
- `Name >>`, for a block of literal text, like this one.
Indentation *is* the structure: no closing tags, no quotes
and no escape characters.
- question: Do you know another similar format?
answer: XML, for example
- content: |
Comments are all the lines that start with `#`.
Documents may have namespaces. You define them
with `Name (namespace.name)`.
conclusion: |
With two kinds of node and indentation you can describe any document.
A template adds **validation** on top, without changing the syntax.
quiz:
- question: How is the structure of a document expressed?
answer: |
With indentation: a node is a child of the closest
previous node with one level less.
- question: What happens to the text inside a `>>` block?
answer: |
It is kept literally. Nothing inside is interpreted.
It can be Markdown, code or any other text.
Content >>
Here the prose is inside the structure, as in @STXT@, with one important difference:
In **YAML** keys are unique, so repeated items have to go into an (artificial) list.
This makes it visually harder to tell whether a `-` character belongs to
the structure nodes or is part of the prose.
In @STXT@ repetition is natural and no list is needed: everything is a structure of text nodes.
Assert >>
The **mental model** of YAML and @STXT@ is very different when writing content in a CMS.
YAML is closer to JSON: there are maps and lists. @STXT@ is more like XML, with trees of text.
Subheader: KDL
Listing >>
lesson "What is STXT?" {
authors {
author "Joan Costa"
author "James Smith"
}
teacher "Sheila Jones"
difficulty "easy"
introduction """
STXT is a **hierarchical text format**: easy for
people to read and trivial for machines to parse.
"""
content """
A document is a tree of nodes. There are only two kinds:
- `Name: value`, for short inline values.
- `Name >>`, for a block of literal text, like this one.
Indentation *is* the structure: no closing tags, no quotes
and no escape characters.
"""
question "Do you know another similar format?" {
answer "XML, for example"
}
content """
Comments are all the lines that start with `#`.
Documents may have namespaces. You define them
with `Name (namespace.name)`.
"""
conclusion """
With two kinds of node and indentation you can describe any document.
A template adds **validation** on top, without changing the syntax.
"""
quiz {
question "How is the structure of a document expressed?" {
answer """
With indentation: a node is a child of the closest
previous node with one level less.
"""
}
question "What happens to the text inside a `>>` block?" {
answer """
It is kept literally. Nothing inside is interpreted.
It can be Markdown, code or any other text.
"""
}
}
}
Content >>
An excerpt of the schema, also written in KDL:
Listing >>
document {
node "lesson" {
min 1
max 1
value { type "string" }
children {
node "teacher" { min 1; max 1; value { type "string" } }
node "difficulty" { max 1; value { enum "easy" "medium" "hard" } }
node "content" { value { type "string" } }
node "question" {
value { type "string" }
children {
node "answer" { min 1; max 1; value { type "string" } }
}
}
}
}
}
Content >>
KDL is the closest format to @STXT@ on this page: named nodes, ordered,
repeatable and with children.
The differences are in the syntax. As with YAML, it is harder to tell
the different components apart visually. Values go between quotes, and in the prose
`\` is an escape character.
Subheader: This site
Content >>
Every page of `stxt.dev` is an @STXT@ document with its prose in Markdown.
The source of any page can be seen by adding `.stxt` to its address,
for example [stxt-vs-markdown.stxt](stxt-vs-markdown.stxt).