npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-blockkit

v0.6.0

Published

React components for previewing Slack Block Kit JSON in light and dark themes.

Readme

react-blockkit

React components for previewing Slack Block Kit JSON in light and dark themes. Known Slack blocks render as Slack-like UI; unknown block and element discriminators stay visible as labeled fallbacks. Rendering is deliberately tolerant, while the separate validation API enforces the package's strict payload contract.

react-blockkit is not coupled to a Markdown compiler. To compile Markdown into Block Kit first, use slackmark.

Install

pnpm add react-blockkit react react-dom

Import the precompiled stylesheet once from your application's global entry point or root layout:

import "react-blockkit/styles.css";

Consumers do not need a StyleX plugin.

The JavaScript entry does not install styles at runtime. Import the stylesheet after layered frameworks such as Tailwind so the layer order is correct. Unlayered host rules can override layered library CSS regardless of import order; scope those rules away from [data-block-kit-root] when visual fidelity matters.

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
      aria-label="Approval request preview"
      data={data}
      onAction={(action) => {
        console.log(action.actionId, action.value);
      }}
    />
  );
}

data accepts a payload object, a bare block array, or a JSON string:

<BlockKit data={jsonFromEditor} />

Rendering does not run strict validation. Unknown discriminators and malformed known shapes render a labeled fallback or the usable fields that remain. Malformed JSON strings throw BlockKitInvariantError with code: "invalid_json" and path: "data".

Validate separately when you need strict payload checks:

import { assertBlockKitData } from "react-blockkit";

const payload: unknown = JSON.parse(jsonFromEditor);
assertBlockKitData(payload, "message");
// payload is now BlockKitData

See Validation for limits, surface checks, the current message-input compatibility caveat, and portable error handling.

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>
  );
}

Use the standalone components with their exported …Data types. Wrap them in BlockKitProvider when they need resolvers or onAction.

Text formats

Slack's text formats are not interchangeable:

  • plain_text is literal text.
  • mrkdwn text objects use Slack's *bold*, <url|label>, mention, emoji, and date syntax.
  • A markdown block uses CommonMark and GFM, including **bold**, standard links, lists, task lists, tables, and fenced code.
  • rich_text is already a structured element tree and is not reparsed.

The renderer also recognizes Slack mentions and emoji in ordinary Markdown text, while respecting Markdown escapes and code spans. See Markdown and mrkdwn before generating text programmatically.

Themes, surfaces, and resolvers

<BlockKit data={data} theme="dark" surface="message" />

theme controls presentation. surface only sets the root's data-surface attribute and the value exposed through BlockKitProvider; built-in blocks do not branch on it, and it does not invoke validation. Validation helpers accept a separate surface argument when you want the package's surface checks.

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.

Local interaction callbacks

onAction reports interactions to the host application. It does not send a Slack interactivity payload or perform network I/O. Elements emit only when they have an action_id; workflow_button is display-only. See Handling actions for the exact local event shape and preview limitations.

Markdown safety fallbacks

Markdown blocks preserve their source as visible, inert text when an input exceeds any of these parser or render bounds:

  • 12,000 source characters (Slack's cumulative markdown-block limit)
  • 1,024 attention or strikethrough delimiter sequences
  • 256 GFM table columns or 4,096 cumulative parsed table cells; the header and delimiter pair count as two rows
  • 64 blockquote/list markers on one source line, counted together
  • 64 nested render levels

These safety fallbacks are separate from the strict validation API.

SSR and accessibility

The renderer supports renderToString and static generation without browser globals. Interactive controls activate after hydration. In a React Server Components framework, render it through a client module because the package uses React context and hooks; keep the stylesheet import in the framework's global CSS entry. Date pickers do not read the current clock. A datetime picker's initial HTML uses the server's local time zone, suppresses the expected value mismatch, and updates to the viewer's local time after hydration. Render that control after mount only when its pre-hydration value must already use the viewer's zone.

The root is a named role="article" (default label: "Slack Block Kit preview"). Set a specific aria-label when a page contains more than one preview. The renderer uses native lists, tables, links, form controls, image alternatives, and named chart images where the payload allows, but it is a preview—not a replacement for accessibility testing of the workflow around it. Current semantics and limitations are documented in Accessibility.

API reference

Development

From the Slackmark monorepo root:

pnpm --filter react-blockkit typecheck
pnpm --filter react-blockkit test
pnpm --filter react-blockkit build

The build emits ESM, CJS, declarations, source maps, and dist/styles.css.