The developer's guide to Slack's Markdown formatting
Tags: programming, webdev, beginners
Published: 2023-10-31 18:06:17

[Slack mrkdwn](https://api.slack.com/reference/surfaces/formatting) is Slack’s version of the Markdown language tailored for their platform. It allows developers to craft visually appealing and structured messages as well as emphasize critical information and add flair to their Slack messages.

In this guide, we’ll explore the nuances of mrkdwn, from its basic formatting capabilities to advanced features, coupled with practical examples to get you started and build the right Slack notifications for your application.

## mrkdwn isn’t Markdown

At first glance, Slack’s mrkdwn and the popular Markdown syntax appear remarkably similar.

Both Slack’s mrkdwn and John Gruber’s Markdown syntax offer a way to richly format text using simple, plaintext notations. However, the design and capabilities of each of the languages is different due to their different purposes.

Markdown was designed as a lightweight markup language to convert plaintext into structurally valid HTML. It allows writers to easily ‘markup’ their text to convert it cleanly into HTML. Most developers will be used to Markdown in Github. You can use Markdown in both the Readme of a repo and individual commit messages. Markdown is also a core component of the Notion platform.

Slack’s mrkdwn is a custom formatting syntax tailored specifically for the Slack platform. Its sole goal is to make it easier to write rich, visually appealing text within Slack and take advantage of the core features of the platform such as @-mentions and channels.

The different purpose leads to core differences in the syntax. Most obviously, Markdown supports multiple header levels using #. For instance, `### Header 3` would represent a `<h3>` tag in HTML. mrkdwn doesn’t support multiple header levels in the same way. When would you use a header in a Slack message? It’s more streamlined for shorter messages.

The same goes for tables or syntax highlighting. These are core for a full document, but less important in Slack messages. Conversely, mrkdwn has special link formats, like `<@U12345678>` for user mentions or `<!channel>` to notify all members of a channel. Markdown doesn’t have a native equivalent for these functionalities given how platform-specific they are.

There are also some design choices within mrkdwn that are different from Markdown, such as the use of underscores for italics rather than a single asterisk, or angle brackets for links instead of square brackets.

## Basic formatting: the foundations of mrkdwn

The core elements of mrkdwn help you convey your messages with clarity, emphasize key points, and make your text easy to scan and understand.

Three elements are commonly used with regular text:

- Wrapping your text with asterisks (`*`) characters bolds the text to emphasize a word or phrase.
- Wrapping your text with underscores (`_`) characters italicizes the text to emphasize subtly or indicate titles of works.
- Wrapping your text with tildes (`~`) characters strikes through the text to indicate corrections or highlight something that’s no longer relevant.

Then we have two ways to add code to Slack messages. This could be particularly useful if you are building alerts for an application monitoring platform and need to show code that has failed.

Inline code is good for highlighting code, commands, or special terminology. For this, you wrap your text with backticks (`` ` ``).

Multiline code blocks are ideal for sharing longer code snippets or preformatted text. To do this, you wrap your text with three backticks (` ``` `). To add a new line, you have to use `\n`.

Throughout, we are using the [Block Kit](https://api.slack.com/block-kit) to show how you build mrkdwn to use with the Slack API. Block Kit enables developers to build interactive and visually appealing messages in Slack. By incorporating mrkdwn within these blocks, you can achieve a fine balance between structure and textual presentation, ensuring your messages are not only interactive but also clear and captivating.

If you are writing these into your code for a notification app, here’s how they would look:

~~~jsx
{
  "blocks": [
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": "This is *bold* \n This is _italic_ \n This is ~strikethrough~ \n This is `code` \n ```This is a code block\nAnd it's multi-line```"
      }
    }
  ]
}
~~~

This message will read in Slack as:


![Slack Formatting](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/txhdu5bkmkn6ikk7ujce.png)



The primary goal of this formatting is to enhance comprehension and draw attention to essential information. Overuse might make messages harder to read. So, while it’s tempting to jazz up every message with formatting, always prioritize clarity.

You can find all the special formatting for mrkdwn in the [Slack mrkdwn formatting docs](https://api.slack.com/reference/surfaces/formatting).

## Links and mentions: engaging directly with users and content

A foundational element of Slack is that you can use notifications to directly engage individuals and teams through mentions and direct those users to specific channels, applications, or sites through links.

We can split these into two types: internal Slack links and mentions and external links to sites and emails.

Internally, mrkdwn uses the @ symbol to mention a specific user (such as `@colin`) or user group, such as `@here`, `@everyone`, or `@channel`. As with when you are working directly in Slack, etiquette is important here. Don’t `@everyone` unless you really need everyone.

Internal to Slack you can also highlight and direct users to other channels, using the hash symbol (#).

To link away from Slack, you use hyperlinks. The format for these in mrkdwn is `<URL|Displayed Text>`. So `<https://knock.app|Knock>` will render as a clickable link titled “Knock” leading to [https://knock.app](https://knock.app/).

You can use this syntax to link to an email address as well, you just prepend the email address with the mailto protocol. So `<mailto:hello@knock.app|hello@knock.app>` will render as a clickable “hello@knock.app” link that opens a user’s default email client with hello@knock.app as the recipient.

Here are code examples of these:

~~~jsx
{
  "blocks": [
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": "This is a link to the <https://knock.app|Knock website> \n This is a mention of user @andrew \n This is an @channel mention \n This is a link to the #random channel \n This is an email link <mailto:hello@knock.app|hello@knock.app>"
      }
    }
  ]
}
~~~

This will show in Slack as:


![Slack Taggin](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0qsija9jrmuhm6cgks5d.png)



When leveraging special links and mentions, always remember to consider the context and the intended audience. While mentions are a powerful way to get someone’s attention, they can be disruptive if overused.

Likewise, linking to channels or external sites should be done judiciously to ensure the message remains clear and focused.

## Lists and blockquotes: structuring your message

Structuring messages lets you convey multiple points or highlight a specific piece of information. In mrkdwn, you can use lists and blockquotes to make your message more digestible.

There is no particular syntax for lists within mrkdwn, at least when sending messages via the API. Instead, you can use whichever symbol you want to specify an unordered list

~~~jsx
{
  "blocks": [
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": "- Item 1 \n - Item 2 \n - Item 3 \n - Item 4"
      }
    }
  ]
}
~~~

This renders to:


![Slack Unordered](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ozi7gjike0vw172l4fex.png)



Ordered lists are just numbers or letters as the symbol. For instance:

~~~jsx
{
"blocks": [
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": "1. Item 1 \n 2. Item 2 \n 3. Item 3 \n 4. Item 4"
      }
    }
  ]
}
~~~

This becomes:


![Slack Ordered](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/weht67lqw1io52e43xzl.png)



To add blockquotes to highlight or emphasize a particular section, like a quotation or important note, you start a line with `>` followed by a space.

~~~jsx
{
  "blocks": [
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": "> This is a blockquote. It can span multiple lines and is often used to highlight specific pieces of information or quotations."
      }
    }
  ]
}
~~~

This renders as:


![Slack Blockquote](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wrlnjx443k45f1y0j7nt.png)



While lists and blockquotes are excellent tools for enhancing readability, they should be used thoughtfully. Too many lists can confuse readers, and excessive blockquoting might dilute the emphasis you’re trying to create.

## Special formatting: elevating your Slack messages

There are a few other options with mrkdwn that you might need to use.

First, displaying dates in a consistent, readable manner with date formatting. Here, you use the timestamp in UNIX format with the syntax `<!date^timestamp^{date_format}|{fallback_text}>`, like this:

~~~jsx
{
  "blocks": [
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": "Today is: \n\n <!date^1697250654^{date_short}|Oct 13, 2023> \n <!date^1697250654^{date_short_pretty}|Oct 13, 2023> \n <!date^1697250654^{date_long}|Oct 13, 2023> \n <!date^1697250654^{date_long_pretty}|Oct 13, 2023> \n <!date^1697250654^{date_num}|Oct 13, 2023> \n <!date^1697250654^{date}|Oct 13, 2023>"
      }
    }
  ]
}
~~~

This renders as:


![Slack Time](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vpa7w9yafyobz1e0dbhi.png)



Tip: In JavaScript or TypeScript, use `const unixTimestamp = Math.floor(Date.now() / 1000)` to get the current date in UNIX format.

You can also combine some of the mrkdwn above. For example, to bold a link, you can use:

~~~jsx
{
  "blocks": [
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": "Here is a *bolded* link to <https://knock.app|*Knock*>"
      }
    }
  ]
}
~~~

Which will render a bolded link:


![Slack Bold Link](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4deyfprsk6ee8gfwwpk6.png)



And, last but definitely not least, you have emojis:

~~~jsx
{
  "blocks": [
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": ":earth_americas: :rocket: :star: :alien: :moon: :sun_with_face: :zap: :fire: :cloud: :umbrella: :rainbow: :cat: :dog: :mouse: :elephant: :tiger: :rooster: :snake:"
      }
    }
  ]
}
~~~

This gives us:


![Slack Emoji](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4je0bb53g5g2x9ywdc30.png)



Remember, you can never have enough emojis.

## Putting it all together: A mrkdwn alert

Let’s put all this together into an alert that an application monitoring platform might send through Slack. Some elements we might use are:

- **Notifying a specific individual or team**. The application might get this information from a database of SREs or on-call individuals. Here we will use `@-mentions`.
- **A concise description of the alert**. Here we will use basic formatting to highlight the issue.
- **Links to dashboards and pertinent information**. So the team can go deeper into the issue
- **A list of steps to be taken**. These can be predefined and added to the Block Kit
- **Date and time information**. Then anyone seeing the alert will know when the alert happened.
- **Emojis**. This can add visual appeal to the alert and draw attention to it.

Altogether, the mrkdwn for this alert would be:

~~~jsx
{
  "blocks": [
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": "@colin \n @sres \n\n *<!date^1697250654^{date_num}|Oct 13, 2023>* \n\n *[APM ALERT]: Elevated Error Rates Detected!* :red_circle: \n - Service: `User Authentication API` \n - Environment: `Production` \n\n :chart_with_upwards_trend: Metrics \n\n *Error Rate*: _15%_ (Threshold: _5%_) \n *Response Time*: _900ms_ (Average: _200ms_) \n *Throughput*: _1200 rpm_ (Requests Per Minute) \n :world_map: Geographical Impact: _US East, Europe Central_ \n  \n :sos: Related Incidents: \n <https://example.com|Database Latency Spike> \n <https://example.com|Redis Connection Failures> \n  \n :link: *Dashboard Link*: <https://example.com|APM Dashboard> \n  \n :speech_balloon: Recommended Actions: \n 1. Verify backend database health and connection. \n 2. Check Redis server and related metrics. \n 3. Assess recent deployments for potential issues."
      }
    }
  ]
}
~~~

This code looks complicated, but most of this information will be added dynamically from the APM. This creates a well-formatted, clear message for the team:


![Slack Full Notification](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xbab9pa1r9c6534ig54n.png)



## Use mrkdwn for clear communication

Slack’s mrkdwn is a powerful tool. Using mrkdwn enhances the readability and emphasis of critical pieces of information. The above example alert shows this, highlighting the crucial data for a team and making sure they can act on that information quickly.

Integrating mrkdwn into your Slack notifications not only beautifies the message but, more importantly, makes it exponentially more user-friendly. When time is of the essence, and clarity is paramount, leveraging the full potential of mrkdwn ensures that your alerts are not just noticed but acted upon effectively.

At Knock, we’ve taken mrkdwn further by integrating it into our [templating engine](https://docs.knock.app/integrations/chat/slack/designing-slack-templates) and enhancing it with liquid tags for templating and an easy-to-use JSON editor. This allows you to design your Slack notifications exactly how you want them.

Check out some [Slack notification examples](https://docs.knock.app/integrations/chat/slack/slack-examples) for inspiration and sign up [here](https://dashboard.knock.app/signup) to get started for free.