TS-28: AsciiDoc
AsciiDoc is RECOMMENDED for technical documentation. AsciiDoc is preferred over other lightweight human-editable markup languages such as Markdown as it is specifically designed for technical writing, it supports embedded diagrams and lots of other valuable features, and it has great tooling for publishing content to different formats.
This technical standard offers tips and best practices for writing AsciiDoc, and for using tools such as AsciiDoctor and Antora to process AsciiDoc files.
For a complete language reference, see the [Asciidoctor Documentation](https://asciidoctor.org/docs/). The AsciiDoctor website also has a useful [AsciiDoc Syntax Quick Reference](https://docs.asciidoctor.org/asciidoc/latest/syntax-quick-reference/) guide.
- Markdown syntax
- File extensions
- Attributes
- Include directive
- Table of contents (TOC)
- Code blocks
- Literal text and blocks
- Images
- Admonitions
- Air quotes
- Preserving line breaks
- Unbreakable blocks
- Links
- Sections, headers, and titles
- Level 1 section title
- Lists
- Tables
- Keyboard shortcuts and UI button text
- Menu selections
- Conditional rendering
- Comments
- Asciidoctor extensions
- Line length and wrapping
Markdown syntax
Asiidoctor supports a subset of Markdown syntax as an alternative to some standard AsciiDoc syntax. In general, prefer to use native Asciidoc syntax, not Markdown styles that happen to be supported by AsciiDoctor.
File extensions
AsciiDoc files SHOULD use the .adoc extension. .asciidoc MAY be used as an
alternative.
The extensions .ad and .asc MUST NOT be used.
Attributes
Attributes are a way of creating a variable whose value can be used throughout the document. Using attributes is encouraged as it increases readability and makes it easy to change content in one place for all locations where it is used.
Attributes are written in the document header and have the following form:
:name-of-an-attribute: value
All attributes MUST be defined in a contiguous block in the document header. The document header is terminated by the first blank line in the document.
To reference an attribute in the document body, use curly braces {} around the
attribute name.
Lorem ipsum {name-of-an-attribute} ...Include directive
The include directive is used to include the content from another file in the current document.
It is RECOMMENDED to use include directive extensively. This helps to keep AsciiDoc files small and modular. Documentation sites and technical books are thus composed from lots of files being included in one main file. Includes directives also allow reusing of content – such as code examples – in multiple places.
An include directive is written in the following form:
include::<path>/file[<attrlist>]
The attrlist is OPTIONAL and can contain one or more comma-separated
attributes that modify the behavior of the include directive. For exampke,
leveloffset=+1 will adjust the section levels of the included file; heading
level 1 (=) will become level 2 (==), level 2 will become level 3, and so
on.
Antora
Antora is a documentation generation tool. It creates documentation websites from structured hierarchies of AsciiDoc files and other assets. Antora imposes some additional constraints on how files can be included in AsciiDoc source files. The following conventions MUST be followed:
- All documents are saved in the
modules/<module-name>/pages/<path>directory. - All images are saved in
modules/<module-name>/assets/images/<path>. - All examples are saved in
modules/<module-name>/examples/<path>.
When using paths to include something , you might need to use the
<module-name> component when linking to another module, but you MUST NOT use
pages, assets/image, or examples in the path component – only the <path>
bit.
If you include a standard page – a page that is stored in the pages directory
– into another page, you MUST set the page-partial AsciiDoc attribute in the
document header of the page being included.
= The Page Header :page-partial: Page contents.
Table of contents (TOC)
AsciiDoc specifies a macro that will automatically generate a table of contents from sections and subsections within the document.
The easiest way to add a TOC is to add the following directive:
= The Page Header :toc:
The TOC will be automatically placed within the rendered document. To control
the position of the TOC, use the toc::[] macro:
= The Page Header :toc: macro Introductory text… toc::[]
Other directives, such as toc-title and toclevels, can be used to configure
the TOC.
It is strongly RECOMMENDED to use an auto-generated table of contents, rather than manually maintaining a list of internal links.
Code blocks
A code block is written using the following syntax.
[source,<language>] ---- text text ----
The <language> is optional. Example:
[source,bash] ---- subscription-manager repos --enable rhel-server-rhscl-7-rpms ----
It is RECOMMENDED to write "plaintext" as the language attribute, for code examples that do not belong to any particular language. This will disable syntax highlighting in the code block when rendered.
For shell examples, you need to distinguish between console and bash as the
source language:
- Use
consoleif a prompt is included in the code snippet. Any of the characters>,%,$, and#may be used for the prompt. Prompts such as[test@ubuntu~]$may also be supported by some rendering tools. Syntax highlighting will be applied only to the commands written after the prompt. - Use
bashfor standalone shell commands and scripts.
For conventions on formatting placeholders and CLI prompts within code blocks, see TS-26: Technical Writing Style Guide.
Literal text and blocks
Literal paragraphs and blocks display the text you write exactly as you enter it. Literal text is treated as pre-formatted text.
Example:
.... Checking system health. - file permissions are ok. ....
Images
Image files are embedded using either the image: (inline) or image::
(block-level) syntax.
image:<path>/image_name[Alternative Image Text, <options>]
All images SHOULD have alternative text. Wrap this in single quotes – NOT double quotes, this can break the Asciidoctor PDF generator – if the alternative text includes any commas.
The <options> part is optional. This is used to do things like adjust the size
of the rendered image, eg. width=40%.
The inline image syntax is useful for embedding small icons within text.
Block-level images MUST be used for large graphics that need to be accompanied
by a caption. Block-level images are centered by default, but you can adjust
this on a case-by-case basis using the align="center|left|right" option.
Admonitions
AsciiDoc admonitions are callout boxes for rendering things like tips, important information, warnings, and errors. There are actually five supported admonition types:
NOTETIPIMPORTANTCAUTIONWARNING
Simple admonitions can be written using the following syntax, where <label> is
one of the above admonition types (written full upper case).
<label>: Text...
But the complex admonition syntax is RECOMMENDED. This helps admonitions to stand-out in the plain text AsciiDoc files themselves. Complex admonitions also support nesting of other block-level markup such as tables, lists, and literal text blocks.
[<label>] ==== Text... ====
Example:
[TIP] ==== We strongly encourage you to put your server in single user mode before setting up encryption. To do so, run the following command: .... sudo -u www-data occ maintenance:singleuser --on .... ====
For guidance on when to use each admonition type, and how sparingly, see TS-26: Technical Writing Style Guide.
Air quotes
If you want to quote sentences or statements, but not using an admonition, you can use air quotes. Air quotes are two double quotes on each line, emulating the gesture of making quote marks with two fingers on each hand.
Example:
"" Not everything that is faced can be changed. But nothing can be changed until it is faced. ""
Preserving line breaks
In AsciiDoc markup, adjacent lines of text are combined into a single paragraph. This means that line breaks in the source text are ignored in the rendered output.
If you want the line breaks preserved, use a space followed by the plus sign +
immediately before the line break. This syntax can be used in paragraphs, lists,
and tables.
This is the first line, + This is the next line separated by a line break.
Unbreakable blocks
Use the %unbreakable attribute to prevent page breaks in a block. The
attribute MUST be applied to an open block that encapsulates the block-level
content that you want to prevent page breaks in.
This does not work:
[%unbreakable, verse, William Blake, Songs of Innocence] ____ Tiger, tiger, burning bright In the forests of the night, What immortal hand or eye Could frame thy fearful symmetry? ____
But this does:
[%unbreakable] -- [verse, William Blake, Songs of Innocence] ____ Tiger, tiger, burning bright In the forests of the night, What immortal hand or eye Could frame thy fearful symmetry? ____ --
The following example could still have page breaks injected in the middle of it,
even though the content is short. To avoid this, always use quoted blocks nested
within %unbreakable open blocks, as above.
[quote, Winston Churchill] The best argument against democracy is a five-minute conversation with the average voter.
Links
In AsciiDoc, links can be either external or internal.
- External links reference content outside the documentation, such as a web page.
- Internal links reference content inside the documentation, such as another page or a section within a document.
A link macro MUST NOT be broken across lines. The whole macro — the target, the square brackets, and the link text between them — MUST sit on a single source line, even where that takes the line past the usual line length limit.
External links
An external link SHOULD be written using the following syntax:
http(s)://domain/path?query#anchor[Hyperlinked text]
The [Hyperlinked text] part is optional. If it is omitted, the URL itself will
be used as the hyperlink text.
For external links, the link: prefix is required only when the target is not a
URI. AsciiDoc recognizes http: and https: as URI protocols and handles them
as implicit link: macros.
If you want to prevent a link from being automatically hyperlinked, prepend it
with a backslash (\). The text will be rendered verbatim as normal
(non-clickable) text.
\https://www.example.com/
A URL may not display correctly when it contains characters such as underscores
(_), carets (^), or double quotes ("). The following is an example of a
URL containing characters that need special treatment. See
Asciidoctor: Troubleshooting URLs
for help solving this.
https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)
For long URLs, it is RECOMMENDED to use an attribute to define the URL and then reference the attribute in the link. This makes the AsciiDoc source more readable.
= The Page Header
:link-name: https://example.com/content/link_can_be_very_long
Text {link-name}[highlighted text] text.For clarity, it is RECOMMENDED to prefix the names of link attributes with
link-.
Internal Links
Internal links are used to create cross-referenced to:
- an in-page reference;
- a documentation file;
- a section title or anchor name inside a documentation file.
In Antora, all referenced content MUST be inside the modules directory. Antora
has particular conventions for referencing content in other modules – refer to
Antora’s documentation for more details.
In-page cross-references
An in-page cross-reference points to a specific location within the same
document. The target MUST be given an explicit anchor using the [[<id>]] block
attribute syntax, placed directly above the element it labels:
[[worse-is-better]] == Worse is Better The "worse is better" philosophy...
The cross-reference MUST then refer to the anchor by its ID, not by the section title:
See <<worse-is-better>> for details.
Relying on Asciidoctor’s auto-generated anchor IDs — which are derived from
section titles — is NOT RECOMMENDED. Auto-generated IDs change whenever a
section is renamed, silently breaking references. Explicit anchor IDs are
stable, decoupled from prose, and make it straightforward to mechanically verify
that every <<…>> reference resolves to a defined [[…]] anchor.
Tip
Use a link checker to audit for broken links.
For guidance on writing effective link text, see TS-26: Technical Writing Style Guide.
Bold Links
To make linked text bold, two syntaxes are supported:
https://domain/path[*Hyperlinked text*] *https://domain/path[Hyperlinked text]*
Same for internal links:
link:../path[*Hyperlinked text*] *link:../path[Hyperlinked text]*
Both produce the expected result, however the internal bold style is less
reliable in preview mode in some AsciiDoc-compatible text editors. For this
reason, the outer * characters are recommended for internal links.
Bold is what distinguishes an internal link from an external one, so it MUST be applied consistently: internal links MUST be bold, and external links MUST NOT be. A reader can then tell from the styling alone whether a link keeps them inside the documentation or takes them out of it.
Sections, headers, and titles
Document titles SHOULD be written using title case: "The Quick Brown Fox Jumps Over the Lazy Dog".
Chapter names and headings SHOULD NOT be written in title case, but in sentence case (with no termination punctuation): "The quick brown fox jumps over the lazy dog".
Document title
The document title, which is written at the top of the document header,
resembles a level-0 section title. It is written as a single equal sign (=)
followed by at least one space, then the text of the title.
Sections
Sections are used to partition the content of a document into a hierarchy. A section title represents the heading for that section.
Section title levels are specified using two to six equals signs (=). The
number of equals signs in front of the title represents the nesting level (using
a 0-based index) of the section.
= Document Title (Level 0) … == Level 1 section title … === Level 2 section title …
Section numbering MUST be in single steps. You will get a warning when jumping
from = to ===, for example.
Sections automatically create a reference-able anchor, and they are
automatically added to tables of content. In the rare case that you want to
exclude a section from the TOC, but keep its anchor for cross-reference, add
[discrete] above the section.
[discrete] === Level 2 section title
Block titles
You can assign a title to any paragraph, list, delimited block, or block macro. In most cases, the title is displayed immediately above the content. If the content is a figure or image, the title is displayed below the content.
A block title is defined on a line above the element. The line must begin with a dot (.) and be followed immediately by the title text.
.Title for this paragraph Text or lists or...
Level 1 section title
Lists
To create a list, prefix each item in the list with the * sign followed by a
single space.
To created nested lists, use multiple * signs according to the nesting level.
* level 1 ** level 2 *** level 3 **** level 4 ***** level 5 * level 1
AsciiDoctor also supports the hyphen (-) as a Markdown-style list marker.
However, this syntax does not support nested lists. Markdown-style
indentation-style nesting will produce a flat list in AsciiDoctor output. For
this reason, Markdown-style syntax SHOULD NOT be used for lists in AsciiDoc.
When list items contain more than one line of text, indent the subsequent lines by at least one space to make it clear that they belong to the same list item. In addition, leave a blank line before the next item.
* This is the first line of the item. This is a continuation of the same item. * This is a separate item. * This is another item in the same list.
A common pattern is to bold a short lead-in term at the start of each item, followed by a full sentence explaining it. Use the following syntax. The lead-in term is terminated by a full-stop, rather than by a colon or hyphen, for the best accessibility.
under normal load. - **Reliability.** The system continues to operate correctly in the presence of hardware or software faults. - **Scalability.** The system handles growth in data volume, traffic, or complexity without a redesign. - **Maintainability.** The system is easy for engineers to understand, modify, and extend over time.
Another pattern supported by Markdown is to inject a newline after the lead-in text, and then indent subsequent lines. This has the visual effect of better differentiating the lead-in text, so it is rendered more like a heading.
- **Performance.** \ The system responds to user input within 100ms under normal load. - **Reliability.** \ The system continues to operate correctly in the presence of hardware or software faults. - **Scalability.** \ The system handles growth in data volume, traffic, or complexity without a redesign. - **Maintainability.** \ The system is easy for engineers to understand, modify, and extend over time.
For lists of key-value pairs, place the colon inside the bold marker.
- **Status:** Active - **Owner:** Platform team - **Region:** eu-west-1 - **Version:** 2.4.0
For guidance on when to use numbered versus bulleted lists, and on punctuation and parallelism within list items, see TS-26: Technical Writing Style Guide.
Tables
Tables are delimited by |=== and made up of cells. Cells are separated by a
vertical bar |.
[width="80%",cols="30%,70%",options="header"] |=== | Header of column 1 | Header of column 2 | Cell in column 1, row 1 | long Cell in column 2, row 1 | Cell in column 1, row 2 | long Cell in column 2, row 2 | Cell in column 1, row 3 | long Cell in column 2, row 3 |===
This example shows that columns can also be written underneath:
[width="90%",cols="20%,80%",options="header",] |=== | Directory | Description | `data/<user>/files_encryption` | Users' private keys and all other keys necessary to decrypt the users' files. | `data/files_encryption` | Private keys and all other keys necessary to decrypt the files stored on a system wide external storage. |===
Keyboard shortcuts and UI button text
You can style snippets of inline text like buttons. This convention is typically used to represent computer keyboard input.
The syntax for UI button text is: btn:[text].
The syntax for keyboard shortcuts is: kbd:[key(+key)*].
Examples:
kbd:[F11] kbd:[Ctrl+T] kbd:[Ctrl+Shift+N] kbd:[Show disabled apps] btn:[OK] btn:[Open]
Menu selections
Important
You MUST set the :experimental: attribute to enable the UI macros.
The syntax for this is: menu:start[next > next > *]
Example:
Go to menu:Settings[Admin > Apps] and click on kbd:[Show disabled apps]
Conditional rendering
Conditional rendering is handy to do things like hide some content from PDF output but show it in HTML output. You use a conditional render directive to achieve this.
or
Comments
Use comments to leave information for other maintainers of the documentation.
Single-line comment notation is preferred:
// Needs revision as a new release will change the parameter.
If you want to comment a block, put the block between four slashes ////
//// Needs revision as a new release will change the parameter. Maybe complex to do but lets see. ////
Asciidoctor extensions
AsciiDoc syntax can be extended by developing your own Asciidoctor extensions. Extensions are written in Ruby.
Use of extensions is generally discouraged as they can make it harder to process the AsciiDoc files with different tools, and source files become less portable.
Line length and wrapping
Lines SHOULD NOT exceed 80 characters. Content longer than this SHOULD be "soft wrapped" — that is, continued on the next line without any special line-break syntax. Adjacent lines within an AsciiDoc paragraph are combined into a single line in the rendered output, so soft wrapping does not affect how the document renders.
See Preserving line breaks for how to force an actual line break where one is needed.
The purpose of this constraint is to ensure that files render identically in every editor, regardless of the editor’s own line-wrapping width or settings.
Lines MUST NOT exceed 160 characters, except in very special circumstances where this cannot be achieved — for example, in tables or long URLs that cannot themselves be broken across lines.
A soft wrap MUST NOT be inserted within an inline formatting unit, such as bold
or italic text, so as to preserve the formatting markers (eg. * or _)
alongside the text they format.
The same applies to link macros, which MUST NOT be broken across lines. Where keeping a link intact takes a line past 80 characters, the link wins.