Skip to content

feat(models): add ContainerBlock for block kit - #1949

Merged
srtaalej merged 3 commits into
mainfrom
ale-add-containerblock
Sep 4, 2026
Merged

feat(models): add ContainerBlock for block kit#1949
srtaalej merged 3 commits into
mainfrom
ale-add-containerblock

Conversation

@srtaalej

@srtaalej srtaalej commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds ContainerBlock (type: "container") to the Block Kit models per https://docs.slack.dev/reference/block-kit/blocks/container-block/
  • Supports all documented properties: title, rich_text_title, subtitle, child_blocks, width, icon, is_collapsible, default_collapsed, has_header_divider
  • Includes validators for title/rich_text_title presence, max lengths, child_blocks count, width enum, and mutual exclusion of is_collapsible + has_header_divider

Test plan

  • Full existing test suite passes (99 tests, 0 regressions)
  • Manually tested against the Slack API via a Bolt test app (see below)
Example Bolt test app (app.py)

Register a /container-block slash command in your test app and use the text argument to test different property combinations:

  • /container-block — base (title + child_blocks)
  • /container-block width — adds width: "wide"
  • /container-block mrkdwn-subtitle — subtitle with mrkdwn type
  • /container-block has-header-divider — adds has_header_divider: true
  • /container-block default-collapsed — adds is_collapsible + default_collapsed
  • /container-block icon — adds icon image element
  • /container-block rich-text-title — uses rich_text_title instead of title
  • /container-block all — all compatible properties together
import logging
import os

from slack_bolt import App
from slack_bolt.adapter.socket_mode import SocketModeHandler

logging.basicConfig(level=logging.DEBUG)

app = App(token=os.environ.get("SLACK_BOT_TOKEN"))


@app.command("/container-block")
def container_block_command(ack, respond, command):
    ack()
    variant = command.get("text", "").strip()

    base = {
        "type": "container",
        "title": {"type": "plain_text", "text": "Container Block Test"},
        "child_blocks": [
            {"type": "section", "text": {"type": "mrkdwn", "text": "Section inside a container."}},
            {"type": "divider"},
            {"type": "section", "text": {"type": "mrkdwn", "text": "Another section below the divider."}},
        ],
    }

    if variant == "width":
        base["width"] = "wide"
    elif variant == "mrkdwn-subtitle":
        base["subtitle"] = {"type": "mrkdwn", "text": "*Bold* subtitle"}
    elif variant == "has-header-divider":
        base["has_header_divider"] = True
    elif variant == "default-collapsed":
        base["is_collapsible"] = True
        base["default_collapsed"] = True
    elif variant == "icon":
        base["icon"] = {
            "type": "image",
            "image_url": "https://api.slack.com/img/blocks/bkb_template_images/plants.png",
            "alt_text": "icon",
        }
    elif variant == "rich-text-title":
        del base["title"]
        base["rich_text_title"] = {
            "type": "rich_text",
            "elements": [
                {"type": "rich_text_section", "elements": [{"type": "text", "text": "Rich Title"}]},
            ],
        }
    elif variant == "all":
        base["subtitle"] = {"type": "plain_text", "text": "All compatible properties"}
        base["width"] = "wide"
        base["icon"] = {
            "type": "image",
            "image_url": "https://api.slack.com/img/blocks/bkb_template_images/plants.png",
            "alt_text": "icon",
        }
        base["is_collapsible"] = True
    else:
        base["subtitle"] = {
            "type": "plain_text",
            "text": "Base test (try: width, mrkdwn-subtitle, has-header-divider, default-collapsed, icon, rich-text-title, all)",
        }

    respond(blocks=[base])


if __name__ == "__main__":
    SocketModeHandler(app, os.environ.get("SLACK_APP_TOKEN")).start()

@codecov

codecov Bot commented Aug 31, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 84.13%. Comparing base (19209fe) to head (d38b6d3).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1949      +/-   ##
==========================================
+ Coverage   84.08%   84.13%   +0.05%     
==========================================
  Files         118      118              
  Lines       13509    13553      +44     
==========================================
+ Hits        11359    11403      +44     
  Misses       2150     2150              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

@srtaalej srtaalej self-assigned this Aug 31, 2026
@srtaalej srtaalej added enhancement M-T: A feature request for new functionality semver:minor models labels Aug 31, 2026
@srtaalej
srtaalej marked this pull request as ready for review August 31, 2026 16:27
@srtaalej
srtaalej requested a review from a team as a code owner August 31, 2026 16:27

@zimeg zimeg left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@srtaalej LGTM! Thanks for getting this shipped! 🎁 🚢 💨

Comment on lines +1096 to +1098
@JsonValidator("width must be a valid value (narrow, standard, wide, full)")
def _validate_width(self):
return self.width is None or self.width in self.valid_widths

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🌊 note: These validation patterns sometimes concern me if the API changes what's accepted but no blocker for the current patterns available.

@zimeg zimeg added this to the 3.next milestone Sep 3, 2026
@srtaalej
srtaalej merged commit 2643bcc into main Sep 4, 2026
18 checks passed
@srtaalej
srtaalej deleted the ale-add-containerblock branch September 4, 2026 17:27
WilliamBergamin added a commit that referenced this pull request Sep 4, 2026
ContainerBlock (#1949) landed on main before the D-rules were enabled and
was merged into this branch, tripping D205/D415. Add the blank line after
the summary so `ruff check` passes tree-wide.

Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement M-T: A feature request for new functionality models semver:minor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants