mrkdwn
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.
Mrkdwn and Text
<Mrkdwn> renders a raw mrkdwn string directly:
import { Mrkdwn } from "@nkootstra/block-kit";
<Mrkdwn text="*Hello* <@U0ADA>, check out <https://example.com|this>." />;
textstring
stringverbatim?boolean
Slack's verbatim flag. When false, bare URLs (https://... or www...) are auto-linked.
booleanfalseemojiSize?number
Pixel size for :emoji: images.
number22<Text> renders a full Block Kit text object, either kind, and is what block/element components use
internally:
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
*bold*?Bold
*text* → <b>text</b>
Bold_italic_?Italic
_text_ → <i>text</i>
Italic~strike~?Strike
~text~ → <s>text</s>
Strike`code`?Inline code
Monospace, no other formatting parsed inside.
Inline code```pre```?Preformatted block
Fenced block, shown verbatim; a single newline right after the opening fence or before the closing one is dropped, matching Slack.
Preformatted block> quote?Quote
One or more consecutive lines starting with >.
Quote>>> quote?Block quote
Everything after >>> is quoted, including following lines.
Block quote<url|label>?Link
Renders as label; falls back to showing the raw url with no |label part.
Linkbare url?Auto-link
Linked automatically unless verbatim is true.
Auto-link<@U123>?User mention
User mention<#C123>?Channel mention
<#C123|name> supplies a fallback label for when the channel can't be resolved.
Channel mention<!subteam^S123>?Usergroup mention
Usergroup mention<!here> / <!channel> / <!everyone>?Special mention
Broadcasts to online members, the channel, or everyone.
Special mention<!date^ts^fmt^url|fallback>?Date
See below.
Date:shortcode:?Emoji
See the emoji guide.
EmojiSpecial mentions
<!here>, <!channel> and <!everyone> render as Slack’s bold, highlighted broadcast pills rather
than a user/channel mention:
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:
{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:
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",
});
locale?string
BCP 47 locale.
string"en-US"timeZone?string
IANA zone. Defaults to the runtime's zone.
stringnow?number
Reference time (ms) for {ago} and the _pretty variants. Defaults to Date.now().
number<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
import { parse, decodeEntities, parsePlainTextEmoji } from "@nkootstra/block-kit/mrkdwn";
parse?(input: string, options?: { verbatim?: boolean }) => Root
Parses a mrkdwn string into an AST (MrkdwnNode[]). Never throws: malformed markup is kept as plain text.
(input: string, options?: { verbatim?: boolean }) => RootdecodeEntities?(text: string) => string
Decodes & < > the way Slack encodes them in mrkdwn.
(text: string) => stringparsePlainTextEmoji?(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.
(input: string) => Array<Text | Emoji>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.