react-blockkit
v0.5.0
Published
React components that render Slack Block Kit JSON exactly as Slack does.
Downloads
694
Maintainers
Readme
react-blockkit
React components that render Slack Block Kit JSON at Slack's measured pixel geometry, in both light and dark themes.
react-blockkit accepts any Block Kit payload; it is not coupled to a Markdown
source or compiler. The package uses Slack's official @slack/types
definitions, adds typed definitions for newer blocks not yet covered there,
offers explicit runtime validators, and ships precompiled StyleX CSS.
Compiling Markdown first? react-blockkit pairs perfectly with
slackmark.
Install
pnpm add react-blockkit react react-domImport the precompiled stylesheet once in your application:
import "react-blockkit/styles.css";Consumers do not need a StyleX plugin.
Render typed Block Kit
import { BlockKit, type BlockKitData } from "react-blockkit";
const data = {
blocks: [
{
type: "section",
text: {
type: "mrkdwn",
text: "A message with *bold text* and <https://slack.com|a link>.",
},
},
{
type: "actions",
elements: [
{
type: "button",
action_id: "approve",
text: { type: "plain_text", text: "Approve" },
style: "primary",
},
],
},
],
} satisfies BlockKitData;
export function Preview() {
return (
<BlockKit
data={data}
onAction={(action) => {
// Route the action to your preview tooling or app.
}}
/>
);
}data may also be a JSON string. It is parsed before blocks render:
<BlockKit data={jsonFromEditor} />Malformed JSON throws BlockKitInvariantError with a stable code and JSON
path. Valid JSON with future or unusual block shapes renders a visible,
human-readable fallback instead of crashing or silently dropping content.
Compose individual blocks
Every layout block and core element is exported independently:
import {
BlockKitProvider,
ButtonElement,
SectionBlock,
} from "react-blockkit";
export function ComposedPreview() {
return (
<BlockKitProvider surface="message">
<SectionBlock
block={{
type: "section",
text: { type: "plain_text", text: "Composable block" },
}}
/>
<ButtonElement
element={{
type: "button",
action_id: "continue",
text: { type: "plain_text", text: "Continue" },
}}
/>
</BlockKitProvider>
);
}Standalone components use the same tolerant rendering behavior as
<BlockKit />.
Themes and surfaces
<BlockKit data={data} theme="dark" surface="message" />theme:lightordarksurface:message,modal, orhome
Rendering does not reject payloads based on the selected surface. Pass the same
surface to assertBlockKitData or parseBlockKitData when strict compatibility
checks are required. Thirteen block types are surface-restricted: alert is
modal-only, input is modal or home, and eleven message blocks (card,
carousel, container, context_actions, data_table, data_visualization,
file, markdown, plan, table, task_card) are message-only. The full
table is in the
validation reference.
Resolve workspace references
Slack IDs can be mapped to human-readable labels without changing the payload:
<BlockKit
data={data}
resolvers={{
user: (id) => users[id] ?? id,
channel: (id) => channels[id] ?? id,
emoji: (name) => emoji[name] ?? `:${name}:`,
}}
/>Resolvers may return any React node.
Runtime guarantees
Rendering is total for valid block-shaped JSON: unknown blocks and elements, empty collections, and out-of-range presentation values degrade to bounded, visible output. Use the explicit validation API when strict Slack acceptance checks are required. Strict validation includes:
- message/view block limits and duplicate
block_iddetection - required fields, discriminators, lengths, and per-block element limits
- legal accessory/input/action element placement
- rich-text nesting and preformatted/list constraints
- table shape, cell types, row/column limits, and aggregate text budgets
- data-table header, row width, page size, and row-header invariants
- chart category/series/point consistency
- card, carousel, container, task-card, and plan constraints
- surface compatibility
Use the validation API without React:
import {
assertBlockKitData,
parseBlockKitData,
} from "react-blockkit";
assertBlockKitData(unknownPayload, "message");
const typed = parseBlockKitData(json, "message");The full block, element, and rich-text inventory, with the degradation behaviour for each, is in the blocks and elements reference.
Type source
Classic and current SDK-supported shapes come directly from @slack/types.
The package locally augments:
header.levelrich_text_list.offsetandrich_text_preformatted.languageraw_numbertable cellscard.subtextandcard.slack_iconcontainerdata_tabledata_visualization
Each is a stopgap for a shape @slack/types does not define.
Development
pnpm --filter react-blockkit typecheck
pnpm --filter react-blockkit test
pnpm --filter react-blockkit buildThe build emits ESM, CJS, declarations, source maps, and a single
dist/styles.css containing the compiled StyleX atoms and theme variables.
The measured Slack Block Kit Builder values this renderer reproduces, covering
typography, block geometry, and per-control metrics in both themes, are in
docs/slack-style-baseline.md.
