DFM and Markdown extensions

Markdown is a lightweight markup language with plain text formatting syntax. You can convert it to HTML and many other formats by using a tool of the same name. Markdown forms the basis of our documentation's conceptual authoring language. Creating new articles is as easy as writing a simple text file by using your favorite text editor.

Markdown supported by OPS

DocFX, used by OPS, supports DocFX Flavored Markdown (DFM). DFM is highly compatible with GitHub Flavored Markdown (GFM) and adds some functionality, including cross-reference and file inclusion. There are differences between DFM and GFM that can affect content preview in GitHub, Visual Studio Team Services, or your editor.

Markdown tutorials

Here are two great tutorials for Markdown and GitHub Flavored Markdown:

Choosing an editor

To edit Markdown, you can use any Markdown editor that you like. Some suggestions: MarkdownPad, Visual Studio Code, Markdown Mode.

Most of them provide live preview functionality so that you can get a simple preview when writing the article. The preview will differ from the final rendering for extensions and places where DFM differs from GFM.

Markdown extensions supported by Open Publishing

The following sections describe supported extensions in Open Publishing.

File includes

You can include other files in the current file. Included files must be located in a folder called /includes within your docset. Ensure that you include the folder as a resource in docfx.json file. The included files should also be configured in DFM syntax.


A YAML header is not supported when the file is an include.

There are three types of file includes: inline, block, and image.

Inline includes

Inline file inclusion is in the following syntax, in which <title> stands for the title of the included file, and <filepath> stands for the file path of the included file. The file path must be a relative file path. Absolute paths are not supported. The <filepath> part can be wrapped by ' or ". Note that for inline file inclusion, the included file will be considered as containing only inline tags. For example, ###header inside the file will not be transformed because <h3> is a block tag. But [a](b) will be transformed to <a href='b'>a</a> because <a> is an inline tag.

...Other inline content... [!include[<title>](<filepath>)]

Block includes

Block file inclusion must be in a single line and with no prefix characters before the starting [. Content inside the included file will be transformed through DFM syntax.



The syntax to include an image is ![[alt text]]({folderPath})

Example: ![alt text for image](../images/Introduction.png)

Provide descriptive alternative text for an image. We even support animated GIFs!

Example, following the same syntax: ![Responsive design](../images/responsivedesign.gif)

Responsive design

Note, warning, tip, important

Use specific syntax inside a block quote to indicate that the content is a type of note.

> [!NOTE]
> This is a note.

> This is a warning.

> [!TIP]
> This is a tip.

> This is important.

And it will be rendered like this:


This is a note.


This is a warning.


This is a tip.


This is important.

Checked lists


This feature is available only on docs.microsoft.com.

A custom style is available for bulleted lists. You can render lists with check marks. Here's an example:

  • Sign in to Azure
  • Create a resource group
  • Prepare the configuration
  • Create a virtual machine
  • Configure the firewall
  • Snapshot the virtual machine
  • Run management tasks

To render the preceding list, you would write the following Markdown:

> [!div class="checklist"]
> * Sign in to Azure
> * Create a resource group
> * Prepare the configuration
> * Create a virtual machine
> * Configure the firewall
> * Snapshot the virtual machine
> * Run management tasks

This Markdown extension can be used anywhere. But we recommend that you target it toward the "What will you learn" (at the top of an article) or "What have you learned" (at the end of an article) scenarios, where you want to vividly show key points in an article or tutorial. Please refrain from adding random or ad hoc checked lists throughout your articles.

Next step action


This feature is available only on docs.microsoft.com.

One extension provides a consistent way to show a next step action at the end of your articles. Here's an example:

To render the preceding action, you would write the following Markdown:

> [!div class="nextstepaction"]
> [Create and manage VM disks](https://docs.microsoft.com/en-us/azure/virtual-machines/linux/tutorial-manage-disks)

Use this Markdown extension only at the end of an article, with the explicit intent to guide readers to a next article that they should read after the current one. Please do not use this extension in any other way.

Adding links to other content in OPS is a very common use case. OPS can resolve and validate the links in the following situations.

Reference content within a docset

In OPS, the build system treat docsets as the boundary for reference validation. So for any link reference within a docset, the build service can resolve and validate that link in common GFM syntax. You can use a relative path, as shown in the following example, to create a link reference within the same docset.

[My link text](../active-directory/active-directory-article-name.md)

Reference content in external docsets

OPS currently doesn't support resolving and validating logic for cross-docset references. If you want to reference a file in another docset, you need to add a cross-docset reference by using an absolute path reference. For example:

[My link text](/active-directory/active-directory-article-name)

The "/active-directory/active-directory-article-name" text is part of the URL without the domain. It creates a link to https://{Domain}/active-directory/active-directory-article-name.

You can use an anchor link to go to a specific section of an article.

Markdown headings H2 (##) through H6 (######) are automatically anchors. The anchor ID is the full text of the heading, all lowercase, with punctuation removed and dashes instead of spaces. For example, the ID for the heading ## 2. Getting started with Markdown is 2-getting-started-with-markdown.

To link to this heading in the current file, use:

[getting started](#2-getting-started-with-markdown)

It's rendered like this:

getting started

To link to a heading from another article, use the relative link to the current article, plus # followed by the anchor ID, such as:

[getting started with GFM](../gfm.md##2-getting-started-with-markdown)

Explicit anchors that use <a> are not required except in hub and landing pages:

## <a id="AnchorText"> </a>Header text or ## <a name="AnchorText"> </a>Header text

And the following for the link to it:

  • Go to [text](#AnchorText) to go to the section on the same page.
  • Go to [text](FileName.md#AnchorText) to go to the section on another page.

To link to an API topic by uid, use an xref link:


Such as: <xref:System.String> or <xref:microsoft.azure.keyvault.keyidentifier.iskeyidentifier>

To link to an overload overview page, add 2%a:


To link to a specific overload, include the parameters in the uid:


To render the full API name in the link, such as System.String instead of String, add ?displayProperty=fullName:


Target API docs must be in the same repo or in a cross-reference map in the repo. For more information, see DocFx: Links and Cross References.

Section definition

You might need to define a section. This syntax is mostly used for code tables. See the following example:

> [!div class="tabbedCodeSnippets" data-resources="OutlookServices.Calendar"]
> ```cs
> <cs code text>
> ```
> ```javascript
> <js code text>
> ```

The preceding blockquote markdown text will be rendered as:

<cs code text>
<js code text>

Code snippets

See Code snippets.


See Metadata.


You can use a selector when you want to connect different pages for the same article and allow readers to switch between those pages.


This extension works differently between docs.microsoft.com and MSDN.

Single selector

> [!div class="op_single_selector"]
> - [Universal Windows](../articles/notification-hubs-windows-store-dotnet-get-started/)
> - [Windows Phone](../articles/notification-hubs-windows-phone-get-started/)
> - [iOS](../articles/notification-hubs-ios-get-started/)
> - [Android](../articles/notification-hubs-android-get-started/)
> - [Kindle](../articles/notification-hubs-kindle-get-started/)
> - [Baidu](../articles/notification-hubs-baidu-get-started/)
> - [Xamarin.iOS](../articles/partner-xamarin-notification-hubs-ios-get-started/)
> - [Xamarin.Android](../articles/partner-xamarin-notification-hubs-android-get-started/)

And it will be rendered like this:


> [!div class="op_multi_selector" title1="Platform" title2="Backend"]
> - [(iOS | .NET)](./mobile-services-dotnet-backend-ios-get-started-push.md)
> - [(iOS | JavaScript)](./mobile-services-javascript-backend-ios-get-started-push.md)
> - [(Windows universal C# | .NET)](./mobile-services-dotnet-backend-windows-universal-dotnet-get-started-push.md)
> - [(Windows universal C# | Javascript)](./mobile-services-javascript-backend-windows-universal-dotnet-get-started-push.md)
> - [(Windows Phone | .NET)](./mobile-services-dotnet-backend-windows-phone-get-started-push.md)
> - [(Windows Phone | Javascript)](./mobile-services-javascript-backend-windows-phone-get-started-push.md)
> - [(Android | .NET)](./mobile-services-dotnet-backend-android-get-started-push.md)
> - [(Android | Javascript)](./mobile-services-javascript-backend-android-get-started-push.md)
> - [(Xamarin iOS | Javascript)](./partner-xamarin-mobile-services-ios-get-started-push.md)
> - [(Xamarin Android | Javascript)](./partner-xamarin-mobile-services-android-get-started-push.md)

And it will be rendered like this:

Video syntax

Currently, OPS can support video syntax for Channel 9 (CH9) and YouTube videos. You can embed a video with the following syntax, and OPS will render it.

> [!VIDEO <channel9_video_link>]
> [!VIDEO <youtube_video_link>]


> [!VIDEO https://channel9.msdn.com/Series/Youve-Got-Key-Values-A-Redis-Jump-Start/03/player]
> [!Video https://www.youtube.com/embed/iAtwVM-Z7rY]

It will be rendered as:

<iframe src="https://channel9.msdn.com/Series/Youve-Got-Key-Values-A-Redis-Jump-Start/03/player" width="640" height="320" allowFullScreen="true" frameBorder="0"></iframe>
<iframe src="https://www.youtube.com/embed/iAtwVM-Z7rY" width="640" height="320" allowFullScreen="true" frameBorder="0"></iframe>

And it will be displayed like this on published pages:


The CH9 video URL should start with https and end with /player. Otherwise, it will embed the whole page instead of the video only.

Resolving file paths

  • A relative path (path like foo/bar.md) is the path relative to the file where this path is written. In the case of an include, it’s relative to the included file. For example, if article A.md includes B.md, B.md has a relative path in it. Then that path is relative to B.md instead of A.md.
  • The relative path will be resolved during the build (including removal of the .md extension) and will generate a build warning if the target file doesn’t exist.
  • You can use "../" to link to a file in the parent folder, but that file has to be in the same docset. You cannot use "../" to link to a file in another docset folder.
  • We also support a special form of relative path that starts with "~" (for example, ~/foo/bar.md)--which means a file relative to the root folder of a docset. This kind of path is also validated and resolved during the build.
  • Besides markdown links and images, you can use a relative path in an HTML link (<a>) and an image (<img>).
  • An absolute path (a path that starts with "/") is a path in the output website. We don’t process absolute paths; we leave them as is in the output HTML. If you use an absolute path, you need to add the base URL and remove the .md extension by yourself.

HTML whitelist

You can embed HTML code in your content, as long as it's on the GitHub whitelist. We also enable iframe elements for video embedding, even though it is not on the GFM whitelist. HTML rendered by the various markup language processors is passed through an HTML sanitization filter for security reasons. HTML elements not on the whitelist are removed. HTML attributes not on the whitelist are removed from the preserved elements.

The following HTML elements, organized by category, are whitelisted:

Type Elements
Headings h1, h2, h3, h4, h5, h6
Prose p, div, blockquote
Formatted pre
Inline b, i, strong, em, tt, code, ins, del, sup, sub, kbd, samp, q, var
Lists ol, ul, li, dl, dt, dd
Tables table, thead, tbody, tfoot, tr, td, th
Breaks br, hr
Ruby (East Asian) ruby, rt, rp
Video (not in GFM whitelist) iframe
Comments Comments

The following attributes, organized by element, are whitelisted:

Element Attributes
a href (http://, https://, mailto://, github-windows://, and github-mac:// URI schemes and relative paths only)
iframe src, allowFullScreen, frameBorder, scrolling
img src (http:// and https:// URI schemes and relative paths only)
div itemscope, itemtype
All abbr, accept, accept-charset, accesskey, action, align, alt, axis, border, cellpadding, cellspacing, char, charoff, charset, checked, cite, clear, cols, colspan, color, compact, coords, datetime, dir, disabled, enctype, for, frame, headers, height, hreflang, hspace, ismap, label, lang, longdesc, maxlength, media, method, multiple, name, nohref, noshade, nowrap, prompt, readonly, rel, rev, rows, rowspan, rules, scope, selected, shape, size, span, start, summary, tabindex, target, title, type, usemap, valign, value, vspace, width, itemprop

Note that the id attribute is not whitelisted.


The simplest way to create a table in markdown is to use pipes and lines.

You can align the columns by using colons:

|-----:| - this is right aligned
|:-----| -  this is left aligned
|:-----:| - this is centered

You can create a table without a header. For example, to create a multiple-column list:

|   |   |
| - | - |
| This | table |
| has no | header |

If you use HTML tables and your Markdown is not being rendered between the two tables, you need to add a closing br tag after the closing table tag.

For more information about how to create tables in markdown, see:

Table wrapping


These classes work only on the docs.microsoft.com site.


If you create a table in Markdown, the table might expand to the right navigation and become unreadable. You can solve that by allowing Docs rendering to break the table when needed. Just wrap up the table with the custom class [!div class="mx-tdBreakAll"].

Here is a Markdown sample of a table with three rows that will be wrapped by a div with the class name mx-tdBreakAll.

> [!div class="mx-tdBreakAll"]
> |Name|Syntax|Mandatory for silent installation?|Description|
> |-------------|----------|---------|---------|
> |Quiet|/quiet|Yes|Runs the installer, displaying no UI and no prompts.|
> |NoRestart|/norestart|No|Suppresses any attempts to restart. By default, the UI will prompt before restart.|
> |Help|/help|No|Provides help and quick reference. Displays the correct use of the setup command, including a list of all options and behaviors.|

It will be rendered like this:

Name Syntax Mandatory for silent installation? Description
Quiet /quiet Yes Runs the installer, displaying no UI and no prompts.
NoRestart /norestart No Suppresses any attempts to restart. By default, the UI will prompt before restart.
Help /help No Provides help and quick reference. Displays the correct use of the setup command, including a list of all options and behaviors.


From time to time, you might have very long words in the second column of a table. To ensure that long words (like paths) are broken apart nicely, you can apply the class mx-tdCol2BreakAll by using the div wrapper syntax as shown earlier.