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

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 console if 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 bash for 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:

  • NOTE
  • TIP
  • IMPORTANT
  • CAUTION
  • WARNING

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.

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.

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 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.

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.