Skip to content

Repository files navigation

slackblocks

Licence: MIT Licence: BSD-3-Clause Python Versions PyPI npm Downloads Python CI TypeScript CI Docs

Build Slack messages in Python or TypeScript — without writing JSON by hand.

Anyone who has built a non-trivial Slack message knows the drill: a wall of nested Block Kit JSON, five levels deep, where a typo'd field name or an over-long string sails silently through your code and only blows up when Slack rejects the API call. slackblocks replaces that JSON with typed objects that assemble it for you — and that complain at construction time, in your editor and your tests, rather than in production.

Why slackblocks?

  • ConciseSectionBlock("Hello, *world*!") / sectionBlock({ text: "Hello, *world*!" }) instead of a ten-line JSON object.
  • Validated up front — character limits, required fields, mutually-exclusive options, and element-type restrictions are enforced when you construct the block, so you find out before hitting Slack's API.
  • Typed — full type hints and py.typed in Python; strict types in TypeScript that reject typo'd properties at compile time.
  • Plays well with the official SDKs — unpack a Message straight into client.chat_postMessage(**message) with slack-sdk, or pass the payload directly to @slack/web-api's chat.postMessage.
  • One library, two languages — the same blocks, the same validation rules, and the same version numbers in both packages, so a team can hop between a Python service and a TypeScript bot without relearning anything. A shared conformance corpus keeps both implementations emitting the same Slack JSON.
  • Everything Block Kit ships today — all current blocks and elements, rich text, modals and Home tabs, and the 2025 block families (tables, cards, carousels, charts).
  • Light — zero runtime dependencies in Python; a single self-contained ESM module on npm.

Installation

Python (3.10+ — earlier Pythons should pin the 1.x line, see Compatibility):

pip install slackblocks

TypeScript / JavaScript (Node 20.19+ or 22.12+, ESM):

npm install @nicklambourne/slackblocks

Quickstart

A CI notification, in Python:

from slackblocks import (
    ActionsBlock,
    Button,
    DividerBlock,
    HeaderBlock,
    Message,
    SectionBlock,
)

message = Message(
    channel="#general",
    text="Build #482 passed",  # plain-text fallback for notifications
    blocks=[
        HeaderBlock("Build #482 passed :white_check_mark:"),
        SectionBlock(
            fields=[
                "*Branch*\n`main`",
                "*Author*\n@nick",
                "*Duration*\n3m 12s",
                "*Tests*\n1,247 passed",
            ],
        ),
        DividerBlock(),
        ActionsBlock(
            elements=[
                Button(text="View build", action_id="view", url="https://ci.example.com/482"),
                Button(text="Re-run", action_id="rerun", value="482", style="primary"),
            ],
        ),
    ],
)

Send it in one line with the official Slack SDK — the ** operator unpacks Message objects directly into the call, no to_dict() boilerplate:

import os
from slack_sdk import WebClient

client = WebClient(token=os.environ["SLACK_API_TOKEN"])
client.chat_postMessage(**message)

The same message in TypeScript:

import {
  actionsBlock,
  button,
  dividerBlock,
  headerBlock,
  message,
  sectionBlock,
} from "@nicklambourne/slackblocks";

const payload = message({
  channel: "#general",
  text: "Build #482 passed", // plain-text fallback for notifications
  blocks: [
    headerBlock({ text: "Build #482 passed :white_check_mark:" }),
    sectionBlock({
      fields: ["*Branch*\n`main`", "*Author*\n@nick", "*Duration*\n3m 12s", "*Tests*\n1,247 passed"],
    }),
    dividerBlock(),
    actionsBlock({
      elements: [
        button({ text: "View build", actionId: "view", url: "https://ci.example.com/482" }),
        button({ text: "Re-run", actionId: "rerun", value: "482", style: "primary" }),
      ],
    }),
  ],
});
import { WebClient } from "@slack/web-api";

const client = new WebClient(process.env.SLACK_API_TOKEN);
await client.chat.postMessage(payload);

The build notification rendered in Slack

Documentation

Repository layout

  • python/ — the established Python package (slackblocks on PyPI).
  • typescript/ — the TypeScript package (@nicklambourne/slackblocks on npm).
  • spec/ — the shared conformance contract: fixtures, invalid cases, limits, and capability coverage that both implementations are tested against.
  • docs/ — the Docusaurus documentation site.

Licensing

slackblocks is dual-licensed under MIT and BSD-3-Clause. Use whichever fits your project — this makes it safe to vendor into projects under either license.

Contributing

Contributions are welcome. Python development uses uv from python/; TypeScript and the docs site use pnpm from the repository root:

git clone https://github.com/nicklambourne/slackblocks.git

cd slackblocks/python
uv sync --group dev
uv run pytest test/unit test/conformance test/docs

cd ..
pnpm install
pnpm --filter @nicklambourne/slackblocks test

For the full development guide — testing conventions, the conformance-fixture workflow, docstring style, and the release process — see the Contributing page.

Bug reports and feature requests: https://github.com/nicklambourne/slackblocks/issues.

About

🎲 Native language APIs for building messages using the Slack Block Kit API

Topics

Resources

Stars

75 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages