Directives and custom UI elements in [#technical-documentation]

Most documentation at LinkORB is written in Markdown. While its minimal syntax is sufficient for most use cases, adding elaborate, custom UI elements to Markdown is often achieved by embedding complex HTML elements. To get around such complexity, we leverage remark-directive to add custom UI elements and reusable components to Markdown.

Use cases

remark-directive extends Markdown to render HTML elements that do not have Markdown counterparts. It has the following syntax for:

  1. Rendering a standard HTML element:

    :::div
    A paragraph within a `div`. The paragraph contains one **bold** word.
    :::
  2. Adding custom classes and/or IDs to a rendered element:

    :::div{.divClassName#divID}
    A paragraph within a `div` element that has been assigned a class name and an ID.
    
    This second paragraph contains a :span[span element with red font color]{.text-danger}.
    :::
  3. Nesting rendered HTML elements:

    :::parentElement
    :::childElement
    A paragraph within a block level `childElement` that is itself a child of the `parentElement`.
    :::
    
    ::childElement[An inline child element within `parentElement`.]
    :::

Building custom layouts with directives

For example, the directive on the left (below) renders the HTML form on the right.

:::form{.width-400.border.p-4.mb-4}
::p[Sign in]{.form-name.text-center.mb-5}
:::div{.form-group}
::label[Email address]
::input{.form-control.mb-3#email-field.p-3}
::button[Continue]{.btn.btn-primary.d-block.w-100.p-3}
:::

Sign in

The last line (i.e., ::: in the above example) of a directive terminates it. This is similar to how you open and close HTML tags, except you only have to close a directive if it is:

  • The outermost parent (e.g., form in the above example).
  • A block level element that has descendant elements.
  • A standalone element element (e.g. :::button).

Each directive element’s class name or ID is enclosed in the braces ({}) next to its name. Class name(s) or ID may be used to apply custom CSS rules to an element.

Managing a directive tree

Similar to HTML element nodes, a directive can have children, grandchildren, etc. A directive must meet the following requirements in order to render correctly on this site:

  • The top-level element (e.g., the form in the above example) must be prefixed by at least three (:::) colons. You may increase the number of colons in the prefix if the directive contains block-level child elements of the same type.

    For example, the ::::tabs directive makes use of four colons (::::) because it contains multiple :::div elements.

    A directive won’t render correctly if it contains two or more block-level children directives that are of the same element type (e.g., div, column) unless its prefix is 1 count higher than the prefix of the child directive with the highest number of prefixes. Each child directive must also be closed off.

  • A non-Markdown block-level element within a directive must be prefixed by at least three colons (:::) in order to serve as the parent of Markdown elements and directives written between its opening and closing tags (colons).

    In the example below, the element on each (except the last) line of the Markdown directive block on the left renders as a child of the element in the line directly above it. After it is processed, the directive on the left would look like the HTML code on the right.

    :::div
    :::form
    :::section
    A paragraph with a :mark[highlighted phrase] as its child
    :::
    <div>
      <form>
        <section>
          <p>A paragraph with a <mark>highlighted phrase</mark> as its child</p>
        </section>
      </form>
    </div>

    Child directives in the above example are not closed off like their top-level ancestor (:::div). They’re not closed because each directive is a child of the directive on the line above it. If you’re trying to create two or more block-level sibling directives (e.g., two :::div, :::section) as child directives, you must close them off. Sibling directives for inline elements such as ::button, ::img may be left unclosed.

    For example, if you’re trying to add two section elements to a form that is wrapped in a div element, the directive may look like the below:

    :::::div
    ::::form
    :::section
    The paragraph with a :mark[highlighted phrase] as its child
    :::
    :::section
    A second paragraph
    :::
    ::::
    :::::
    <div>
      <form>
        <section>
          <p>The paragraph with a <mark>highlighted phrase</mark> as its child</p>
        </section>
        <section>
          <p>A second paragraph</p>
        </section>
      </form>
    </div>
  • Inline-level elements such as mark, span, or strong must be prefixed by a single colon (:) and their text content enclosed in brackets ([]) when used in a directive.

    For example, the following directive italicizes the word “HTML” using the em element and sets its font color to green using the text-success class.

    :::div
    Emphasis (`em`) is an :em[HTML]{.text-success} element that italicizes a word.
    :::
  • Attributes of an element are seperated by a single space. For example, an image that’s been assigned an ID and multiple class names will look like the below:

    :::img{.class_1.class_2.class_3#id_1 src="/img/code.webp" alt="PHP code"}
    :::
  • A block-level directive that has children must start and terminate with at least three colons. It must terminate with the same number of colons as its prefix.

All Markdown tags render inside a directive without additional work.

Pre-defined directives

For your convenience, this site offers pre-defined directives that make it easier to embed custom HTML in Markdown without knowing the element’s name or class. Below are some of the available custom directives.

Important notes and callouts

When an exception, common point of confusion, potentially destructive action, or otherwise important note/callout is warranted in a document, consider using a (tip, warning, danger, or info) directive.

For example, the directive below displays the info (blue) level alert shown below it.

:::info
An **info** level alert is suitable for highlighting important information and clarifying a common point of confusion on a subject or an exception to a rule.
:::

An info level alert is suitable for highlighting important information and clarifying a common point of confusion on a subject or an exception to a rule.

danger alerts are suitable for highlighting potentially destructive actions such as formatting a storage device.

A warning alert may, for example, suggest protective/preventive measures a user should take before performing a potentially destructive action.

A tip can, for example, suggest additional configurations that readers should make to improve their user experience after installing a new operating system.

When documentation resides in a GitHub repository directly and alert classes are not supported, consider using this beta feature.

> **Note**
> This is a note

> **Warning**
> This is a warning

Use the good and bad custom directives to highlight good and bad practices such as incorrect title case in a writing guide or insecure coding practices such as the following:

:::bad
Docker exposes port 3306 of your computer to everyone on your local network and the public Internet by default when run this way.

```shell
docker run -dp 3306:3306 mariadb
```

:::
:::good
Binding the exposed port to `localhost`, for example, ensures only applications and services on your computer can access your Docker container in a development environment.

```shell
docker run -dp 127.0.0.1:3306:3306 mariadb
```
:::

The above good/bad directives render the alerts shown below.

Docker exposes port 3306 of your computer to everyone on your local network and the public Internet by default when run this way.

docker run -dp 3306:3306 mariadb

Binding the exposed port to localhost for example, ensures only applications and services on your computer can access your Docker container in a development environment.

docker run -dp 127.0.0.1:3306:3306 mariadb

Tabs

A tabbed layout improves readability and simplifies guidance in situations where documentation presents two or more methods of completing a task. When documenting multiple methods of performing a task, use the predefined ::::tabs directive.

For example, the ::::tabs directive below shows how to install Git through the command line interface on Windows, Linux, and MacOS.

::::tabs
::button[Windows (Powershell)]
::button[Linux]
::button[MacOS]

:::div

1. Press :kbd[&plusb; Win] + :kbd[R].
2. Type **powershell** and press :kbd[Enter].
3. Copy the following commmand into **Powershell** and press :kbd[Enter].

```powershell
winget install --id Git.Git -e --source winget
```

:::

:::div

1. Open the terminal (usually by pressing :kbd[Ctrl] + :kbd[Alt] + :kbd[T]).
2. Install git from your distribution's package manager:

- **Debian/Ubuntu:**

  ```shell
  sudo apt-get install git
  ```

- **Arch:**

  ```shell
  sudo pacman -S git
  ```

- **Alpine:**

  ```shell
  sudo apk add git
  ```

- **Fedora/RHEL**

      ```shell
      sudo dnf install git
      ```

:::

:::div
1. Press :kbd[&#8984; Command] + :kbd[Space] or press :kbd[F4] and search for **Terminal**.
2. Enter the following command into the terminal and press :kbd[Enter].

  ```zsh
   brew install git
   ```

:::
::::

The directive above renders the tabbed HTML layout shown below.

  1. Press ⊞ Win + R.
  2. Type powershell and press Enter.
  3. Copy the following commmand into Powershell and press Enter.
winget install --id Git.Git -e --source winget
  1. Open the terminal (usually by pressing Ctrl + Alt + T).
  2. Install git from your distribution’s package manager:
  • Debian/Ubuntu:

    sudo apt-get install git
  • Arch:

    sudo pacman -S git
  • Alpine:

    sudo apk add git
  • Fedora/RHEL

    sudo dnf install git
  1. Press ⌘ Command + Space or press F4 and search for Terminal.

  2. Enter the following command into the terminal and press Enter.

    brew install git

Collapsible lists

Use collapsible lists to present F.A.Q-style content that allows readers to skim and only engage with relevant topics without scrolling (too much 👨‍💻).

The following is the syntax for adding collapsible list items to this site.

:::collapsed
::summary[Collapsible item #1]
A paragraph that is hidden by default and shown only if one clicks the heading.

This is **paragraph 2** of the same collapsible list item.
:::

:::collapsed
::summary[Collapsible item #2]
A _second_ paragraph that is hidden by default and shown only if one clicks the heading.

This is **paragraph 2** of the **second** collapsible list item.
:::

The example directive above renders the following collapsible list items:

Collapsible item #1

A paragraph that is hidden by default and shown only if one clicks the heading.

This is paragraph 2 of the same collapsible list item.

Collapsible item #2

A second paragraph that is hidden by default and shown only if one clicks the heading.

This is paragraph 2 of the second collapsible list item.



Multi-column layouts

Use multi-column layout directives to display side by side comparisions of 2 to 4 elements on a page. The available multi-layout directives are :::columns2, columns3, and columns4.

Multi-column layouts are useful for rendering things such as the expected output of a piece of code. For example, the following directive renders the two-column layout (directive and HTML sample code) displayed side by side below it.

:::::columns2
::::column
**Directive**

```markdown
:::div
:::form
:::section
A paragraph with a :mark[highlighted phrase] as its child
:::
```

::::

::::column
**HTML**

```html
<div>
  <form>
    <section>
      <p>A paragraph with a <mark>highlighted phrase</mark> as its child</p>
    </section>
  </form>
</div>
```

::::
:::::

Directive

:::div
:::form
:::section
A paragraph with a :mark[highlighted phrase] as its child
:::

HTML

<div>
  <form>
    <section>
      <p>A paragraph with a <mark>highlighted phrase</mark> as its child</p>
    </section>
  </form>
</div>
About Technical Documentation
  • Name: Technical Documentation (#technical-documentation)