Help us shape the future of Go! Take the 2026 Go Developer Survey

slackblocks

module
v3.1.0+incompatible Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 27, 2026 License: MIT

README

slackblocks

Downloads across PyPI, npm, NuGet, RubyGems, crates.io, Packagist and Hex

PyPI version npm version Go module version Maven Central version NuGet version RubyGems version crates.io version Packagist version Hex version Haskell package preparation

Python CI TypeScript CI Go CI Java CI Ruby CI Rust CI PHP CI Elixir CI Haskell CI

Build Slack messages in Python, TypeScript, Go, Java, C#, Ruby, Rust, PHP, Elixir, or Haskell — 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?

  • Concise — SectionBlock("Hello, *world*!") / SectionBlock.builder().markdownText("Hello, *world*!").build() / new 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, compile-checked concrete fluent builders in Go and Java, and typed constructors with nullable annotations in C#, RBS signatures in Ruby, and consuming builders with typed role enums in Rust, readonly classes with backed enums in PHP, and immutable structs with typespecs and atom enums in Elixir.
  • Plays well with established Slack clients — unpack a Message straight into client.chat_postMessage(**message) with slack-sdk, pass a payload directly to @slack/web-api, pass Go block builders directly to slack-go/slack, pass Java blocks directly to the official Slack Java SDK, serialize C# values with System.Text.Json, call to_json on Ruby values, use Serde with Rust values, pass PHP JSON to JoliCode, cURL or Laravel, or send Elixir maps with Req or the community Slack client.
  • One contract across ten implementations — the same blocks, validation rules, and version numbers in Python, TypeScript, Go, Java, C#, Ruby, Rust, PHP, Elixir, and Haskell. A shared conformance corpus keeps the implementations emitting the same Slack JSON. Haskell joins the coordinated 3.1.0 release.
  • 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 self-contained ESM module on npm, one direct Go dependency (slack-go/slack), Java integration through the official Slack model interfaces, no dependencies beyond .NET itself in C#, Ruby's default JSON gem, Serde/serde_json in Rust, built-in JSON/PCRE extensions in PHP, and Jason/Decimal in Elixir.

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
Go (1.22+)
go get github.com/nicklambourne/slackblocks/go/v3
Java (17+)
<dependency>
  <groupId>io.github.nicklambourne</groupId>
  <artifactId>slackblocks</artifactId>
  <version>3.1.0</version>
</dependency>
C# (.NET 8+)
dotnet add package Slackblocks
Ruby (3.3+)
gem install slackblocks
Rust (1.85+, edition 2024)
cargo add slackblocks@3.1.0
cargo add serde_json
PHP (8.2+, 64-bit)
composer require nicklambourne/slackblocks:^3.0

PHP support begins with coordinated version 2.7.0. See the PHP package guide for native usage and development setup.

Elixir (1.16.3+, compatible OTP 26.2+, 64-bit)

Add the Hex package to your dependencies in mix.exs:

{:slackblocks, "~> 3.0"}

Run mix deps.get. If Jason was compiled before Decimal was installed, run mix deps.compile jason --force in each build environment and rebuild the application/release. See the Elixir package guide.

Haskell (GHC 9.6.7+, tested through 9.14)

Add slackblocks >= 3.1 && < 3.2 to your application's Cabal build-depends, run cabal update, then cabal build. Haskell joins the coordinated 3.1.0 release on Hackage. See the package guide and installation and compiler policy. The pending badge is intentional; the shared download total excludes Hackage until publication and the dashboard collector are verified.

Quickstart

Python

A CI notification:

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)
TypeScript / JavaScript
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"),
    ),
  )
  .build();
import { WebClient } from "@slack/web-api";

const client = new WebClient(process.env.SLACK_API_TOKEN);
await client.chat.postMessage(payload);
Go
client := slack.New(os.Getenv("SLACK_API_TOKEN"))
_, _, err := client.PostMessageContext(
    context.Background(),
    "C0123456",
    slack.MsgOptionText("Build #482 passed", false),
    slack.MsgOptionBlocks(
        slackblocks.NewHeaderBlock().Text("Build #482 passed :white_check_mark:"),
        slackblocks.NewSectionBlock().Fields(
            "*Branch*\n`main`",
            "*Tests*\n1,247 passed",
        ),
        slackblocks.NewDividerBlock(),
    ),
)
Java
SectionBlock block = SectionBlock.builder()
    .markdownText("Build #482 passed :white_check_mark:")
    .build();

var client = Slack.getInstance().methods(System.getenv("SLACK_API_TOKEN"));
client.chatPostMessage(ChatPostMessageRequest.builder()
    .channel("C0123456")
    .text("Build #482 passed")
    .blocks(List.of(block))
    .build());
C#
using Slackblocks.Blocks;
using Slackblocks.Elements;
using Slackblocks.Payloads;

var message = new MessagePayload(
    "C0123456",
    text: "Build #482 passed", // plain-text fallback for notifications
    blocks:
    [
        new HeaderBlock("Build #482 passed :white_check_mark:"),
        new SectionBlock(fields: ["*Branch*\n`main`", "*Tests*\n1,247 passed"]),
        new DividerBlock(),
        new ActionsBlock([new ButtonElement("View build", "view", url: "https://ci.example.com/482")]),
    ]);

// POST message.ToJson() to chat.postMessage with HttpClient and a bot token.
Ruby
require "slackblocks"

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

puts message.to_json
Rust

The same validated construction in Rust uses consuming builders and native errors:

use slackblocks::{HeaderBlock, MessagePayload, SectionBlock};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let message = MessagePayload::builder("C01234567")
        .text("Build #482 passed")
        .block(HeaderBlock::builder().text("Build #482 passed").build()?)
        .block(SectionBlock::builder().fields(["*Branch*\n`main`", "*Status*\nPassed"]).build()?)
        .build()?;
    println!("{}", serde_json::to_string(&message)?);
    Ok(())
}

Values own their data, getters borrow, and clone().into_builder() supports editing without mutating the original. See the Rust package guide and Rust API reference.

PHP

The same construction in PHP uses readonly classes and named arguments:

<?php

declare(strict_types=1);

require 'vendor/autoload.php';

use Slackblocks as S;

$message = new S\MessagePayload(
    channel: 'C0123456789',
    text: 'Build #482 passed',
    blocks: [
        new S\HeaderBlock('Build #482 passed'),
        new S\SectionBlock(fields: ["*Branch*\n`main`", "*Tests*\n1,247 passed"]),
        new S\ActionsBlock(elements: [
            new S\ButtonElement(text: 'View build', actionId: 'view', url: 'https://ci.example.com/482'),
        ]),
    ],
);
echo $message->toJson();

See the PHP package guide, sending integrations, and PHP API reference.

Elixir

Native structs use keyword constructors and atom enums. Tagged functions return {:ok, value} or {:error, error}; bang functions raise.

alias Slackblocks.{Message, Blocks, Elements}
message = Message.new!(
  channel: "C0123456789",
  text: "Build #482 passed",
  blocks: [
    Blocks.Header.new!(text: "Build #482 passed"),
    Blocks.Section.new!(fields: ["*Branch*\n`main`", "*Tests*\n1,247 passed"]),
    Blocks.Actions.new!(elements: [
      Elements.Button.new!(text: "View build", action_id: "view", url: "https://ci.example.com/482")
    ])
  ]
)
Slackblocks.to_map!(message)

Send the resulting map with Req or the community client. See the Elixir package guide, sending integrations, API reference and Erlang example.

Haskell
{-# LANGUAGE OverloadedStrings #-}

import Data.Aeson (encode)
import Slackblocks

example = do
  label <- buildPlainText (plainText "Open")
  action <-
    buildButtonElement
      ((buttonElement label) {buttonElementActionId = Just "open"})
  body <- buildMarkdownText (markdownText "*Hello*")
  section <-
    buildSectionBlock
      ( sectionBlock
          { sectionBlockText = Just (markdownTextAsText body),
            sectionBlockAccessory = Just (buttonElementAsElement action)
          }
      )
  buildMessagePayload
    ( (messagePayload "C123")
        { messagePayloadBlocks = Just [sectionBlockAsBlock section]
        }
    )

-- Handle Left errors or send encode payload on Right payload.

Handle the structured Left errors, or encode the checked payload on Right. See the native API, HTTP integration and compiler table.

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).
  • go/ — the Go v3 module (github.com/nicklambourne/slackblocks/go/v3).
  • java/ — the Java artifact (io.github.nicklambourne:slackblocks on Maven Central).
  • csharp/ — the .NET package (Slackblocks on NuGet).
  • ruby/ — the Ruby gem (slackblocks on RubyGems from 2.5.0).
  • rust/ — the Rust crate (slackblocks on crates.io from 2.6.0).
  • php/ — native PHP values and Composer package (nicklambourne/slackblocks on Packagist from 2.7.0).
  • elixir/ — native Elixir values and Erlang integration (slackblocks on Hex from 2.8.0).
  • haskell/ — checked immutable Haskell values, native JSON and separate HTTP integration (introduced in 3.1.0).
  • spec/ — the shared conformance contract: fixtures, invalid cases, limits, and capability coverage that all ten implementations are tested against.
  • docs/ — the Docusaurus documentation site.

Download statistics

The Downloads badge sums all-time counts from PyPI (via Pepy), npm, NuGet, RubyGems, crates.io, Packagist, and Hex. Go and Maven Central have no comparable public all-time download counters and are excluded. Registry counting rules differ; these counts include automated downloads and do not represent unique users. The total refreshes hourly and shows unavailable if any contributing count is missing or more than 24 hours old.

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

cd go
go test -race -cover ./...

cd ../java
./mvnw clean verify

cd ../csharp
dotnet test

cd ../ruby
bundle install
bundle exec ruby -I test -e 'Dir[File.expand_path("test/*_test.rb")].sort.each { |path| require path }'

Elixir contributors use the pinned formatter toolchain and mix run tools/check.exs from elixir/; see native checks for packaging, Erlang, sending and quality prerequisites.

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

Adding a newly released Slack component or field? Follow the in-repo Adding New Block Kit Features for the shared contract, implementation, test, and documentation checklist.

Adding a new language? Follow the in-repo language implementation guide for native API design, parity, testing, documentation, packaging and release integration.

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

Haskell contributors run python bin/check from haskell/ with the pinned GHC, Cabal, Ormolu and HLint tools described in its README. This includes native suites, compiled API coverage, source archives and fresh consumers.

Directories

Path Synopsis
docs
examples/go command
scripts command
go module

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL