---
title: mrkdwn
description: Slack's mrkdwn syntax, the parser and formatting helpers in @nkootstra/block-kit/mrkdwn, and the Mrkdwn and Text components.
---

Mrkdwn is Slack's own text format (not quite Markdown) used in `mrkdwn` text objects throughout
Block Kit. `@nkootstra/block-kit` ships a parser for it, usable on its own (no React, no DOM) through
`@nkootstra/block-kit/mrkdwn`, and the `<Mrkdwn>`/`<Text>` components that render its output.

<Preview
  payload={{
    blocks: [
      {
        type: "section",
        text: {
          type: "mrkdwn",
          text: "*Bold*, _italic_, ~strike~, `code`, and a <https://example.com|link>.\n> A quoted line.\n<@U0ADA> mentioned <#C0GENERAL> and <!subteam^S0ENG|@engineering>.",
        },
      },
    ],
  }}
/>

## Mrkdwn and Text

`<Mrkdwn>` renders a raw mrkdwn string directly:

```tsx
import { Mrkdwn } from "@nkootstra/block-kit";

<Mrkdwn text="*Hello* <@U0ADA>, check out <https://example.com|this>." />;
```

| Prop | Type | Default | Description |
| - | - | - | - |
| `text` | `string` | - | |
| `verbatim?` | `boolean` | `false` | Slack's verbatim flag. When false, bare URLs (https://... or www...) are auto-linked. |
| `emojiSize?` | `number` | `22` | Pixel size for :emoji: images. |

`<Text>` renders a full Block Kit text object, either kind, and is what block/element components use
internally:

```tsx
import { Text } from "@nkootstra/block-kit";

<Text text={{ type: "mrkdwn", text: "*Hello*" }} />;
<Text text={{ type: "plain_text", text: "Hello :wave:" }} />;
```

A `plain_text` object has no formatting beyond emoji shortcodes: no bold, links or mentions, since
that's what Slack itself restricts it to.

## Supported syntax

| Prop | Type | Default | Description |
| - | - | - | - |
| `*bold*?` | `Bold` | - | *text* → <b>text</b> |
| `_italic_?` | `Italic` | - | _text_ → <i>text</i> |
| `~strike~?` | `Strike` | - | ~text~ → <s>text</s> |
| `code`? | `Inline code` | - | Monospace, no other formatting parsed inside. |
| ```pre```? | `Preformatted block` | - | Fenced block, shown verbatim; a single newline right after the opening fence or before the closing one is dropped, matching Slack. |
| `> quote?` | `Quote` | - | One or more consecutive lines starting with >. |
| `>>> quote?` | `Block quote` | - | Everything after >>> is quoted, including following lines. |
| `<url\|label>?` | `Link` | - | Renders as label; falls back to showing the raw url with no \|label part. |
| `bare url?` | `Auto-link` | - | Linked automatically unless verbatim is true. |
| `<@U123>?` | `User mention` | - | |
| `<#C123>?` | `Channel mention` | - | <#C123\|name> supplies a fallback label for when the channel can't be resolved. |
| `<!subteam^S123>?` | `Usergroup mention` | - | |
| `<!here> / <!channel> / <!everyone>?` | `Special mention` | - | Broadcasts to online members, the channel, or everyone. |
| `<!date^ts^fmt^url\|fallback>?` | `Date` | - | See below. |
| `:shortcode:?` | `Emoji` | - | See the emoji guide. |

## Special mentions

`<!here>`, `<!channel>` and `<!everyone>` render as Slack's bold, highlighted broadcast pills rather
than a user/channel mention:

<Preview
  payload={{
    blocks: [
      { type: "section", text: { type: "mrkdwn", text: "<!channel> heads up, deploying now." } },
    ],
  }}
/>

## Dates

`<!date^1392734382^{date_short} at {time}^https://example.com|Feb 18, 2014>` formats a Unix timestamp
in the viewer's own locale and time zone, with an optional link and a `|fallback` shown only when the
format can't be rendered:

<Preview
  payload={{
    blocks: [
      {
        type: "section",
        text: {
          type: "mrkdwn",
          text: "Deployed <!date^1392734382^{date_short_pretty} at {time}|Feb 18, 2014 at 6:39 AM>.",
        },
      },
    ],
  }}
/>

`{token}` placeholders inside the format string: `{date}`, `{date_short}`, `{date_long}`,
`{date_long_full}`, `{date_num}`, `{date_slash}`, `{date_pretty}`, `{date_short_pretty}`,
`{date_long_pretty}` (the `_pretty` variants show "Today"/"Yesterday"/"Tomorrow" when applicable),
`{time}`, `{time_secs}`, and `{ago}` (a relative time like "in 3 hours"). Unknown tokens are left as-is.

`formatSlackDate` does the same formatting outside of parsed mrkdwn, useful when you have a raw
timestamp and format string from elsewhere:

```ts
import { formatSlackDate } from "@nkootstra/block-kit/mrkdwn";

formatSlackDate(1392734382, "{date_short} at {time}");
// → "Feb 18, 2014 at 6:39 AM"

formatSlackDate(1392734382, "{date_long_pretty}", {
  timeZone: "America/New_York",
  locale: "en-US",
});
```

| Prop | Type | Default | Description |
| - | - | - | - |
| `locale?` | `string` | `"en-US"` | BCP 47 locale. |
| `timeZone?` | `string` | - | IANA zone. Defaults to the runtime's zone. |
| `now?` | `number` | - | Reference time (ms) for {ago} and the _pretty variants. Defaults to Date.now(). |

`<BlockKitProvider timeZone="...">` sets the zone used for dates parsed inline within `<Mrkdwn>`. Pass
`timeZone` to `formatSlackDate` directly when formatting outside of that context.

## Other exports

```ts
import { parse, decodeEntities, parsePlainTextEmoji } from "@nkootstra/block-kit/mrkdwn";
```

| Prop | Type | Default | Description |
| - | - | - | - |
| `parse?` | `(input: string, options?: { verbatim?: boolean }) => Root` | - | Parses a mrkdwn string into an AST (MrkdwnNode[]). Never throws: malformed markup is kept as plain text. |
| `decodeEntities?` | `(text: string) => string` | - | Decodes &amp; &lt; &gt; the way Slack encodes them in mrkdwn. |
| `parsePlainTextEmoji?` | `(input: string) => Array<Text \| Emoji>` | - | Splits a plain_text string into text and emoji nodes, with no other mrkdwn parsing. This is what `Text` uses for plain_text objects. |

`parse` is what powers `<Mrkdwn>`; reach for it directly when you want the structured AST instead of
React output, for example to render mrkdwn somewhere other than the DOM, or to extract just the plain
text.

## Related

**[Emoji](/guides/emoji)**

Shortcodes, custom emoji, and skin tones.

**[Mentions and resolvers](/guides/mentions-and-resolvers)**

Turning `<@U0ADA>` and `<#C0GENERAL>` into names.

**[Blocks: Markdown](/blocks/markdown)**

A block for standard Markdown, such as an LLM's output.
