Theming

The renderer ships Slack-like light and dark themes. Switch with the theme prop:

import { BlockKit, type BlockKitInput } from "react-blockkit";

export function Preview({ data }: { data: BlockKitInput }) {
  return <BlockKit data={data} theme="dark" />;
}

theme is "light" (default) or "dark". It controls the renderer palette: text, surfaces, borders, buttons, and charts. It also sets color-scheme so native form controls (selects, date pickers, scrollbars) follow along.

The same payload, light then dark. Watch the chart palette and the button fills, not just the background:

theme="light" (default)

Nightly build

Branch: main
Tests: 214 passed

Suite duration by shard

020406080123
seconds
Duration
Triggered from main · 3 checks passed
View payload JSON
{
  "blocks": [
    {
      "type": "header",
      "text": {
        "type": "plain_text",
        "text": "Nightly build"
      }
    },
    {
      "type": "section",
      "fields": [
        {
          "type": "mrkdwn",
          "text": "*Branch:*\nmain"
        },
        {
          "type": "mrkdwn",
          "text": "*Tests:*\n214 passed"
        }
      ]
    },
    {
      "type": "divider"
    },
    {
      "type": "data_visualization",
      "title": "Suite duration by shard",
      "chart": {
        "type": "bar",
        "axis_config": {
          "categories": [
            "1",
            "2",
            "3"
          ],
          "y_label": "seconds"
        },
        "series": [
          {
            "name": "Duration",
            "data": [
              {
                "label": "1",
                "value": 62
              },
              {
                "label": "2",
                "value": 48
              },
              {
                "label": "3",
                "value": 71
              }
            ]
          }
        ]
      }
    },
    {
      "type": "actions",
      "elements": [
        {
          "type": "button",
          "action_id": "promote",
          "style": "primary",
          "text": {
            "type": "plain_text",
            "text": "Promote"
          }
        },
        {
          "type": "button",
          "action_id": "revert",
          "style": "danger",
          "text": {
            "type": "plain_text",
            "text": "Revert"
          }
        },
        {
          "type": "button",
          "action_id": "logs",
          "text": {
            "type": "plain_text",
            "text": "View logs"
          }
        }
      ]
    },
    {
      "type": "context",
      "elements": [
        {
          "type": "mrkdwn",
          "text": "Triggered from `main` · 3 checks passed"
        }
      ]
    }
  ]
}
theme="dark"

Nightly build

Branch: main
Tests: 214 passed

Suite duration by shard

020406080123
seconds
Duration
Triggered from main · 3 checks passed
View payload JSON
{
  "blocks": [
    {
      "type": "header",
      "text": {
        "type": "plain_text",
        "text": "Nightly build"
      }
    },
    {
      "type": "section",
      "fields": [
        {
          "type": "mrkdwn",
          "text": "*Branch:*\nmain"
        },
        {
          "type": "mrkdwn",
          "text": "*Tests:*\n214 passed"
        }
      ]
    },
    {
      "type": "divider"
    },
    {
      "type": "data_visualization",
      "title": "Suite duration by shard",
      "chart": {
        "type": "bar",
        "axis_config": {
          "categories": [
            "1",
            "2",
            "3"
          ],
          "y_label": "seconds"
        },
        "series": [
          {
            "name": "Duration",
            "data": [
              {
                "label": "1",
                "value": 62
              },
              {
                "label": "2",
                "value": 48
              },
              {
                "label": "3",
                "value": 71
              }
            ]
          }
        ]
      }
    },
    {
      "type": "actions",
      "elements": [
        {
          "type": "button",
          "action_id": "promote",
          "style": "primary",
          "text": {
            "type": "plain_text",
            "text": "Promote"
          }
        },
        {
          "type": "button",
          "action_id": "revert",
          "style": "danger",
          "text": {
            "type": "plain_text",
            "text": "Revert"
          }
        },
        {
          "type": "button",
          "action_id": "logs",
          "text": {
            "type": "plain_text",
            "text": "View logs"
          }
        }
      ]
    },
    {
      "type": "context",
      "elements": [
        {
          "type": "mrkdwn",
          "text": "Triggered from `main` · 3 checks passed"
        }
      ]
    }
  ]
}

The root paints its own background in the active theme's message-surface color, so a dark render sits correctly on any host page.

The stylesheet

All theme variables live in the one precompiled stylesheet:

import "react-blockkit/styles.css";

Import it once, after layered frameworks such as Tailwind so the CSS layer order is correct. Unlayered host selectors can override layered library styles regardless of import order; scope those rules away from [data-block-kit-root] when visual fidelity matters.

Styling the root

<BlockKit /> accepts a className that is appended to the root element. Use it for sizing and placement (width, margin) rather than restyling block internals:

import { BlockKit, type BlockKitInput } from "react-blockkit";

export function Preview({ data }: { data: BlockKitInput }) {
  return <BlockKit className="message-preview" data={data} />;
}

The root also carries stable data attributes for targeting from CSS or tests:

AttributeValue
data-block-kit-rootPresent on the root element
data-theme"light" or "dark"
data-surface"message", "modal", or "home"

Block components accept className the same way when composed individually.