Markdoc tag syntax specification
Version: | 0.1.0 Draft |
---|---|
Author: | Ryan Paul |
Markdoc is a Markdown-based document format and a framework for content publishing. Markdoc extends Markdown with a custom syntax for tags and annotations, providing a way to tailor content to individual users and introduce interactive elements. This specification describes the syntax of Markdoc tags and how to parse them within Markdown content.
1Tags
A Markdoc Tag is a piece of markup that applies custom behavior or formatting in a Markdoc document. Tags can be nested, making it possible to express hierarchy or apply custom formatting to enclosed children. Matched pairs of opening tags and closing tags signify the beginning and end of a tag element that encloses children.
Example № 1{% example %}
This paragraph is nested within a Markdoc tag.
{% /example %}
Tags can also be self-closing, containing no nested content:
Example № 2{% example /%}
The tag delimiters (TagStart and TagEnd) indicate the presence of a Markdoc tag within Markdown content. Characters within the delimiters are treated as the TagInterior. When a TagStart delimiter is detected in a Markdown document, the parser should scan forward until it finds the first TagEnd delimiter that is not enclosed within a ValueString in order to determine where the tag ends.
Determining what behavior and formatting is applied by a given Markdoc tag and its attributes is left to individual Markdoc implementations.
1.1Opening tag
An opening tag indicates the start of a Markdoc tag element that contains nested children. An opening tag’s TagInterior must include the name of the tag and can include zero or more tag attributes.
A tag may optionally have an unnamed PrimaryAttribute value following the Identifier:
Example № 3{% if $foo %}
This is a paragraph in an `if` tag.
{% /if %}
1.2Self-closing tag
A self-closing tag, indicated by a forward-slash at the end of the TagInterior, indicates a Markdoc tag element that does not contain nested children. A self-closing tag’s TagInterior must include the name of the tag and can include zero or more tag attributes.
1.3Closing tag
A closing tag, indicated by a forward-slash at the start of the TagInterior, indicates the end of a Markdoc tag element that contains nested children. A closing tag’s TagInterior may include include the name of the tag and optional trailing whitespace. A closing tag corresponds to the most recent opening tag that has the same tag name.
1.4Tag forms
Markdoc tags can be used as either block or inline elements in a Markdown document.
1.4.1Block form
A tag should be parsed as a block-level element when its opening and closing markers each appear on a line by themselves with no other characters except whitespace. In the following example, the tag foo
should be parsed as a block-level element that contains a single paragraph:
Example № 4{% foo %}
This is content inside of a block-level tag
{% /foo %}
1.4.2Inline form
When the opening tag and closing tag appear on the same line within a paragrah, the tag should be treated as an inline document elmement nested inside of the block-level paragraph element:
Example № 5This is a paragraph {% foo %}that contains a tag{% /foo %}
When the opening tag and closing tag appear on the same line with no other surrounding content, the tag should still be treated as an inline document element, nested within an implied block-level paragraph element:
Example № 6{% foo %}This is content inside of an inline tag{% /foo %}
1.5Annotation
An Annotation applies Attributes to the enclosing Markdown block. The attributes within the annotation are treated as though they are attributes on the document node itself. For example, an annotation can be used to add a CSS class to a heading node:
Example № 7# Heading {% .example %}
An Annotation may only be used as an inline document node. When an annotation appears on a line by itself, it is treated as though it is nested in a block-level paragraph element. Within an Annotation, each Attribute is separated by a space.
1.6Attributes
There are two types of attributes: full attributes (AttributeFull) and shorthand attributes (AttributeShorthand).
A full Attribute is a key-value pair that consists of an Identifier and a Value separated by an = sign. The Identifier serves as the Attribute‘s key. No whitespace is permitted between the tokens that make up an Attribute.
Example № 8{% foo="bar" baz=[1, 2, 3] %}
1.6.1Shorthand attribute
A shorthand attribute consists of a ShorthandSigil followed by an Identifier. The sigil represents the attribute’s key. The following table describes the attribute key represented by each sigil:
Sigil | Key |
---|---|
# | id |
. | class |
A shorthand attribute is equivalent to a full attribute that uses the key represented by the sigil. The following examples produce the same output:
Example № 9{% #foo .bar %}
Example № 10{% id="foo" class="bar" %}
When there are multiple shorthand attributes that use the class sigil (.), the parser combines them into a single class
attribute. The following examples are equivalent:
Example № 11{% .foo .bar .baz %}
Example № 12{% class="foo bar baz" %}
2Interpolation
Interpolation is used to insert a Markdoc variable or the return value of a Markdoc function into the text of the Markdown document. Interpolation can only be used inside of an inline document node. When an interpolation appears on a line by itself, it is implicitly nested as inline content within a paragraph.
Example № 13Hello {% $username %}
3Values
3.1Primitive values
3.1.1Null
A null value is represented with the keyword null.
3.1.2Boolean
true |
false |
3.1.3Number
3.1.4String
" | \ | n | r | t |
3.2Compound values
3.2.1Array
An array value (ValueArray) consists of a matched pair of square brackets containing a comma-delimited sequence of Values. A matched pair of square brackets that contains nothing or only whitespace is parsed as an empty array value. An optional trailing comma is permitted within non-empty arrays. Arrays may be nested to an infinite level of depth and may contain Markdoc Variables or Function invocations.
Example № 14{% foo=[1, false, ["bar", $baz]] %}
3.2.2Hash
Identifier |
String |
A hash value (ValueHash) consists of a matched pair of curly braces containing a comma-delimited sequence of key-value pairs (HashKeyValue). A matched pair of curly braces that contains nothing or only whitespace is parsed as an empty hash value. An optional trailing comma is permitted within non-empty hashes. Hashes may be nested to an infinite level of depth and may contain Markdoc Variables or Function invocations as values. The HashKey may consist of either a bare identifier or a string surrounded by double quotes.
Example № 15{% foo={key: "example value", "quoted key": $variable} %}
3.3Variable
A Variable allows Markdoc content to incorporate an external value. Variables may be used for Interpolation or in place of a value in tag attributes. Variables consist of multiple segments, which are intended to support accessing a value that is deeply nested in a complex data structure. A Variable segment can be an identifier or a square-bracket enclosed value. Determining how to resolve a Variable into a value is left up to individual Markdoc implementations.
Example № 16{% foo=$bar.baz[10].qux %}
$
and @
sigils. Presently, the $
sigil should be treated as a conventional variable and the @
sigil is reserved for future use.3.4Function
A function consists of an Identifier followed by FunctionParameters enclosed in parentheses. Functions are used to incorporate external logic in a Markdoc document.
A FunctionParameter may be either a Value or a key-value pair separated by an equals sign. Functions may be used for Interpolation or in place of a value in tag attributes. Function parameters may be any valid Value, including a Variable or another Function. Determining how to evaluate a Function is left up to individual Markdoc implementations.
4Space
Space (U+0020) |
Horizontal Tab (U+0009) |
New Line (U+000A) |
5Identifier
§Index
- Annotation
- ArrayItem
- ArrayItemWithOptionalComma
- Attribute
- AttributeFull
- AttributeItem
- AttributeShorthand
- closing tag
- CompoundValue
- Digit
- Fraction
- Function
- FunctionParameter
- FunctionParameterNamed
- FunctionParameters
- FunctionParameterTail
- HashItem
- HashItemWithOptionalComma
- HashKey
- HashKeyValue
- Identifier
- IdentifierTail
- Interpolation
- InterpolationValue
- opening tag
- PrimaryAttribute
- PrimitiveValue
- self-closing tag
- ShorthandSigil
- Space
- StringCharacter
- StringElement
- StringEscapeCharacter
- StringEscapeSequence
- Tag
- tag delimiters
- TagClose
- TagEnd
- TagInterior
- TagOpen
- TagSelfClosing
- TagStart
- Value
- ValueArray
- ValueBoolean
- ValueHash
- ValueNull
- ValueNumber
- ValueString
- Variable
- VariableSegmentValue
- VariableSigil
- VariableTail