Skip to content
Block Kit for React
Esc
↑↓navigate↵open⌘Jpreview
On this page

Surfaces

Render blocks as a Slack message, a modal or a Home tab.

Slack shows blocks on three surfaces: messages, modals and the App Home tab. Each has its own component, and each lays the same blocks out the way Slack does on that surface.

Component Slack surface Takes
<Message> A message in a channel blocks, or a whole message object
<Modal> A modal opened with views.open A modal view
<HomeTab> The App Home tab, published with views.publish A home view
<View> Either of the two above Any view; picks <Modal> or <HomeTab> from its type

Message

<Message> draws the message chrome (app avatar, name, APP badge and time) around its blocks.

import { Message } from "@nkootstra/block-kit";

<Message
  app={{ name: "Deploy Bot", iconUrl: "/deploy-bot.png" }}
  blocks={[{ type: "section", text: { type: "mrkdwn", text: "Deployed *api@4.2.0* :rocket:" } }]}
/>;
Your AppAPP
Deployed api@4.2.0 :rocket:
PropType
blocks?AnyBlock[]

The blocks to render.

TypeAnyBlock[]
text?string

Fallback text. Slack shows it only when the message has no blocks, and so does this.

Typestring
app?{ name: string; iconUrl?: string }

The app the message is from. Without `iconUrl`, the avatar shows the name's first letter.

Type{ name: string; iconUrl?: string }
Default{ name: "Block Kit Preview" }
ts?string | number

The message timestamp in seconds, as in Slack's `ts`.

Typestring | number
DefaultThe time the component mounted
timeZone?string

IANA zone for the displayed time.

Typestring
DefaultThe viewer's zone
message?SlackMessageLike

A whole Slack message object. See below.

TypeSlackMessageLike
channelId?string

The channel the message is in, sent in the `container` of `block_actions` payloads.

Typestring
isEphemeral?boolean

Show Slack's “Only visible to you” marker.

Typeboolean
Defaultfalse

Message objects

When you already have a message from Slack’s API, say from conversations.history, pass it as message. It supplies the blocks, text, timestamp and sender (username, icon_url, icon_emoji or bot_profile), and renders what surrounds them: legacy attachments, reactions, the thread summary and the (edited) marker.

const { messages } = await slack.conversations.history({ channel: "C0RELEASES", limit: 1 });

<Message message={messages[0]} channelId="C0RELEASES" />;
Your App(edited)
Release v4.2.0 is out.
:tada:4:eyes:1

Attachments

Legacy attachments render with their colour bar, author, title, fields, image and footer. An attachment can also hold blocks.

Your App
New incident
PagerDuty
5xx responses above 2% for 5 minutes.
Severity
High
Service
api

Ephemeral messages

Ephemeral messages, posted with chat.postEphemeral, carry Slack’s “Only visible to you” marker:

<Message isEphemeral blocks={blocks} />
Your AppAPP
Only you can see this. Run /deploy help for options.
Only visible to you

<Modal> renders a modal view the way views.open shows it: the title bar with the app icon and close button, a scrolling body, and the close and submit buttons.

import { Modal } from "@nkootstra/block-kit";

<Modal
  icon="/deploy-bot.png"
  view={{
    type: "modal",
    callback_id: "deploy",
    title: { type: "plain_text", text: "Deploy" },
    submit: { type: "plain_text", text: "Deploy" },
    close: { type: "plain_text", text: "Cancel" },
    blocks: [
      {
        type: "input",
        block_id: "version",
        label: { type: "plain_text", text: "Version" },
        element: {
          type: "plain_text_input",
          action_id: "value",
          placeholder: { type: "plain_text", text: "api@4.2.0" },
        },
      },
    ],
  }}
/>;

Deploy

Version

Press Deploy with the field empty: the modal validates it the way Slack does before it sends anything. When it’s valid, the provider’s onSubmit gets the view_submission payload. To open, push and update modals from actions, and answer a submission with errors, see Modals.

PropType
viewModalView

The view, as you'd pass it to `views.open`. Slack allows up to 100 blocks.

TypeModalView
icon?string

URL of the app icon shown before the title.

Typestring

Home tab

<HomeTab> renders a home view full width, under the App Home tab bar.

import { HomeTab } from "@nkootstra/block-kit";

<HomeTab view={{ type: "home", blocks }} />;
Home

Your deploys

api@4.2.0 went out to production 12 minutes ago.

Deploys from #releases in the last 7 days.

An action handler can swap the content with views.publish, just as your app republishes the Home tab.

Any view

<View> takes any view object, for example one you’ve loaded from your database, and renders <Modal> or <HomeTab> depending on its type:

import { View } from "@nkootstra/block-kit";

<View view={savedView} icon="/deploy-bot.png" />;

Choosing the surface for loose blocks

<Blocks> renders an array of blocks with no surface around them. Some elements look different per surface: selects and text inputs are taller in modals and the Home tab, and only there does an optional input block get its “(optional)” label. Set the provider’s surface to the one you’re imitating:

import { BlockKitProvider, Blocks } from "@nkootstra/block-kit";

<BlockKitProvider surface="modal">
  <div className="sbk-root">
    <Blocks blocks={blocks} />
  </div>
</BlockKitProvider>;

The sbk-root class applies the base font, colours and resets; <Message>, <Modal> and <HomeTab> add it for you.

Was this page helpful?