Changelog
September 17, 2026 · View on GitHub
All notable changes to slackblocks are documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[2.4.0] — 2026-09-17
This coordinated release introduces the C# package, published to NuGet as
Slackblocks, and moves all five packages onto one shared release number. The
Python public API and wire format are unchanged.
Changed
- Coordinated release validation now requires the Python, TypeScript, Java, and C# package manifests and all five language changelogs to agree before any tags are created.
- Project documentation now includes the C# implementation alongside the existing Python, TypeScript, Go, and Java variants.
[2.3.0] — 2026-09-16
This coordinated release introduces the Java package while moving Python, TypeScript, Go, and Java onto one shared release number. The Python public API and wire format are unchanged.
Changed
- Coordinated release validation now requires the Python, TypeScript, and Java package manifests and all four language changelogs to agree before any tags are created.
- Project documentation now includes the Java implementation alongside the existing Python, TypeScript, and Go variants.
[2.2.0] — 2026-08-29
This coordinated release introduces the fluent TypeScript API while keeping the Python and TypeScript packages on one release number. Python constructor signatures are unchanged.
Changed
- Complete message payloads now enforce Slack's 50-block and 100-attachment limits and require a non-empty channel.
- Message, modal, and App Home block collections now reject blocks that Slack does not support on that surface.
- Modals containing an input block now require submit text, matching Slack's view rules.
- The shared cross-language conformance contract is now version 1.1.0 and covers these complete-payload rules in both implementations.
[2.1.1] — 2026-08-16
A documentation and packaging-metadata patch; no library behaviour changes.
Changed
- The PyPI page now carries Homepage, Repository, Documentation, and Changelog
links (
[project.urls]was previously misplaced and silently dropped from the wheel metadata). - The README leads with the new language-neutral project logo, links to the current documentation site paths, and shows the quickstart's rendered message.
- Wheels are built with current Hatchling again (Core Metadata 2.5), now that
Twine 7 validates it; the temporary
hatchling<1.28pin is retired.
[2.1.0] — 2026-08-14
The 2.1 release adds the current generation of Block Kit blocks while keeping the Python and TypeScript packages on one coordinated release number.
Added
- Support for
AlertBlock,CardBlock,CarouselBlock,ContainerBlock,ContextActionsBlock,DataTableBlock,DataVisualizationBlock,TaskCardBlock, andPlanBlock, together with their supporting elements and composition objects. - Shared valid and invalid conformance cases for the new block families, with coverage checks that require both language implementations to handle every registered capability.
Changed
FileInputnow emits"type": "file_input"in its JSON (the field was previously deliberately omitted from the rendered payload).HeaderBlocknow enforces the 150-character limit on pre-builtTextobjects (previously only plain strings were length-checked) and convertsmrkdwnTexttoplain_text, matching the Slack API's requirement that header text be plain text.InputBlocknow acceptsFileInputelements.block_idvalues longer than 255 characters now raiseLengthError(previously they were accepted and passed through to the Slack API unchecked).- Documentation now covers the new blocks with Python, JSON, and rendered Slack previews.
- The project is now a multi-package workspace with coordinated Python and TypeScript releases.
[2.0.0] — 2026-05-15
The 2.0 release. First final release of the modernised line.
slackblocks 2.x requires Python 3.10 or newer. Users on Python 3.8 or 3.9
should pin to the 1.x release line; see the
Compatibility
docs page for details.
Added
MarkdownBlockfor Slack's 2024 GitHub-flavored Markdown block type (1-12000 charactertextfield). Used for AI / agentic app outputs. (#198, #199)VideoBlockfor embedding video content withalt_text,thumbnail_url,title,video_url, plus six optional fields. (#200, #201)PlainTextandMarkdownthin subclasses ofTextthat remove the boilerplate of constructing plain-text ormrkdwn-flavored text:PlainText("Hi", emoji=True)instead ofText("Hi", type_=TextType.PLAINTEXT, emoji=True). (#202, #203)block_kit_builder_url(payload, team_id=None)utility that turns any block, list of blocks, message, view, or raw dict into a Block Kit Builder URL for browser-based preview. (#204, #205)Workflow.from_url(url, **params)classmethod factory that collapses the four-deep nested workflow construction (Workflow->Trigger->customizable_input_parameters->InputParameter) into a single call. (#206, #207)from_dict()parsers for round-tripping Slack JSON back intoslackblocksobjects. Supported now: every composition object (Text,Option,OptionGroup,Confirm,ConversationFilter,DispatchActionConfiguration,InputParameter,SlackFile,Trigger,Workflow) and the basic blocks (DividerBlock,FileBlock,HeaderBlock,MarkdownBlock,ImageBlock,SectionBlock,ContextBlock,VideoBlock). Element-level and rich-text round-tripping is deferred to follow-up phases. (#208, #209)- Top-level
Block.from_dict(data)dispatcher that readsdata["type"]and routes to the right subclass.Blockis now exported from the package root. (#208, #209) - Five new typed exception subclasses of
InvalidUsageErrorso consumer code canexceptfor specific failure categories instead of string-matching the message:LengthError,RangeError,TypeMismatchError,MutualExclusivityError,MissingRequiredError. Existingexcept InvalidUsageErrorblocks continue to catch every subclass unchanged. (#196, #197) PEP 561py.typedmarker file so downstream type checkers honourslackblocks' inline annotations. (#164, #165)- Compatibility docs page (
usage/compatibility.md) documenting which Python versions each release line supports. (#166, #167) PEP 585/PEP 604annotation syntax across the codebase (list[X],X | Y) plusfrom __future__ import annotationsin every module. (#170, #171)PEP 613TypeAliasdeclarations on the public type aliases:TextLike,ButtonStyleLike,ButtonStyleName,ColumnAlignment,ConversationType. (#194, #195)Literaltype narrowing for string-valued enums:Button.style: ButtonStyle | Literal["primary", "danger"] | None,ColumnSettings.align: Literal["left", "center", "right"] | None,ConversationFilter.includeitems typed asLiteral["im", "mpim", "private", "public"]. mypy / pyright now reject misspellings at type-check time. (#190, #191)@overloadonText.to_textso the return type narrows toTextwhenallow_none=False(the default), and toText | Nonewhenallow_none=True. (#192, #193)- Internal
slackblocks/_core.pymodule providing a sharedResolvableprotocol, recursiveresolve()walker, andomit_none()helper. The walker structurally eliminates the entire class of bugs that produced eight Phase 1 P0 fixes (forgotten._resolve()calls on nested objects). (#174, #175)
Changed
- Minimum Python version raised to 3.10 (was 3.8.1). Bump version to
2.0.0.dev0. (#168, #169) - Tooling migrated from
black+flake8+flake8-pyprojecttorufffor both linting and formatting. Workflow files renamed (formatting.yml->ruff-format.yml,linting.yml->ruff-lint.yml); CI job names updated toRuff FormatandRuff Lint. Branch protection required-status-check list updated correspondingly. (#162, #163) - Additional ruff rule families enabled:
B(bugbear),I(isort),SIM(simplify),TC(type-checking),UP(pyupgrade) on top of the baselineE,F,W. (#172, #173) _resolve()methods refactored across the entire library to use the centralresolve()/omit_none()helpers from_core.py. The diff is internal — public API and JSON output are byte-identical — but the per-class boilerplate is dramatically reduced. (#176-#185)- Shared
RenderableMixinfactored out of the five abstract base classes (Block,Element,CompositionObject,RichTextElement,RichTextObject) which previously each defined their own copy of__repr__. (#188, #189) _MessagePayloadMixinfactored out ofBaseMessageandWebhookMessageto dedupe theto_dict/json/__repr__/__getitem__/keyspayload helpers. (#186, #187)- Rich-text style emission deduplicated via a private
_style_dict()helper; the same 8-line block previously appeared in 5 classes. (#182, #183) - Renamed
text_basic_file_blocktest (typo, never collected by pytest) totest_basic_file_block. (#156, #157)
Fixed
19 P0 correctness bugs found in the audit before 2.0 development began, each in its own focused PR. The most impactful:
Confirm.__init__was broken —super(*args, **kwargs)(missing parens) raisedTypeErroron every invocation. (#126, #127)- Eight
_resolve()methods forgot to recurse into nested objects, causingjson.dumpsto raiseTypeErrorfor any caller exercising the affected fields:Image.slack_file(#130, #131),URLInput.placeholder(#132, #133),TimePicker.confirm(#134, #137),DatePicker(confirm + missinginitial_date) (#135, #138),DateTimePicker(confirm + missinginitial_datetime) (#136, #139),ConversationSelectMenu.filter(#140, #141),RichTextInput.dispatch_action_configandplaceholder(#142, #143). ConversationMultiSelectMenutypo'd JSON key"intial_conversations"(Slack silently ignored it). (#144, #145)NumberInputdroppedmin_value=0/max_value=0via truthy checks, plus a typo'd error message that referencedmin_valuetwice. (#146, #147)StaticSelectMenuraisedUnboundLocalErrorwhen neitheroptionsnoroption_groupswas provided. (#150, #151)FileBlockrequired an explicitblock_idinstead of synthesising one. (#152, #153)FileInputandSlackFilewere missing from the top-level package exports. (#154, #155)validate_intmax-value error message said "less than the minimum" (copy-paste bug from the min-value branch). (#120, #121)validate_string_nonnulltruthymin_length/max_lengthchecks silently dropped explicit0values. (#122, #123)validate_stringandvalidate_string_nonnullhad inconsistent positional argument order. (#124, #125)DispatchActionConfiguration.__init__did not callsuper().__init__, soself.typewas unset. (#128, #129)option_groupsflattening used quadraticsum([list], [])instead ofitertools.chain.from_iterable. (#148, #149)- mypy was failing on master because
DatePicker.initial_datewas inferred asstr(from theifbranch) and conflicted with theNonein theelsebranch. (#158, #160) - black was failing on master in
test_elements.pyafter a multi-lineOption(...)invocation. (#159, #161)
Removed
- Removed
black,flake8,flake8-pyprojectdev dependencies (replaced byruff). (#162, #163) - Removed Python 3.8 and 3.9 from the supported versions and the CI matrix. (#168, #169)
- Removed Slack-API-URL
# noqa: E501comments inside docstrings (ruff correctly does not honour them since they are within string literals, not real code comments). (#162, #163)
[1.2.5] — 2026-05-10
Last release of the 1.x line. Patch release; no functional changes.
Earlier releases
For 1.x and 0.x release history, see the Git tag history.