Skip to main content

Slack Blocks Markdown

PyPI version Python 3.11+ License: MIT Tests

Convert Markdown to Slack Block Kit blocks using Python. This library provides a clean, efficient way to transform your Markdown content into Slack's interactive Block Kit format.

Features

  • 🚀 Complete Markdown Support: Headers, paragraphs, lists, code blocks, quotes, tables, links, and inline formatting
  • 📱 Slack Block Kit Compatible: All blocks follow official Slack specifications with proper constraints
  • 🎯 Custom Table Support: Full implementation of Slack's table blocks with validation
  • 🔧 Flexible APIs: Dictionary-based for simplicity, object-based for editing, or direct renderer for full control
  • ✏️ Editable Blocks: Modify generated blocks before sending to Slack
  • High Performance: Efficient processing of large documents
  • 🧪 Well Tested: Comprehensive test suite with high coverage
  • 📝 Type Safe: Full type hints for better development experience

Installation

pip install slack-blocks-markdown

Quick Start

Simple Usage (Dictionary API)

from slack_blocks_markdown import markdown_to_blocks

# Convert markdown to Slack blocks (returns list of dictionaries)
markdown = """# Project Update

This is a **bold** announcement about our new features:

- ✅ User authentication
- ✅ Real-time updates
- 🚧 Mobile app (coming soon)

> **Note**: This is still in beta, so please report any issues!
"""

blocks = markdown_to_blocks(markdown)
print(f"Generated {len(blocks)} blocks")

# Use blocks directly with Slack SDK
from slack_sdk import WebClient

client = WebClient(token="your-token")
client.chat_postMessage(
    channel="#general",
    blocks=blocks
)

Object-Based API (Editable Blocks)

from slack_blocks_markdown import markdown_to_block_objects

# Convert markdown to Block objects that can be modified
markdown = "# Hello World\n\nThis is a paragraph."

blocks = markdown_to_block_objects(markdown)

# Edit blocks before sending to Slack
blocks[0].text.text = "Custom Header"
blocks[1].text.text = "Modified paragraph with *custom* content."

# Convert to dictionaries when ready to send
from slack_sdk import WebClient

client = WebClient(token="your-token")
client.chat_postMessage(
    channel="#general",
    blocks=[block.to_dict() for block in blocks]
)

Advanced Usage (Direct Renderer)

For maximum control over the rendering process, use the renderer directly:

from mistletoe import Document
from slack_blocks_markdown import SlackBlocksRenderer

# Direct renderer usage with options
with SlackBlocksRenderer(expand_sections=True) as renderer:
    document = Document(markdown)
    blocks = renderer.render(document)  # Returns Block objects

# Convert to dictionaries for JSON serialization
blocks_json = [block.to_dict() for block in blocks]

Supported Markdown Elements

Markdown Element Slack Block Type Notes
# Headers HeaderBlock Truncated to 150 chars
Paragraphs SectionBlock With mrkdwn formatting
**Bold***Bold* Inline formatting Slack markdown style
_Italic__Italic_ Inline formatting Slack markdown style
`Code``Code` Inline formatting Preserved
~~Strike~~~Strike~ Inline formatting Slack markdown style
[Link](url)<url|Link> Inline formatting Slack link format
Code blocks SectionBlock With triple backticks
> Blockquotes SectionBlock With > prefix
Lists SectionBlock Bullet (•) or numbered
Tables TableBlock Custom implementation
--- DividerBlock Horizontal rules

Examples

Basic Formatting

markdown = "This is **bold** and _italic_ with `code` and [links](https://example.com)"
blocks = markdown_to_blocks(markdown)
# Result: [{"type": "section", "text": {"type": "mrkdwn", "text": "This is *bold* and _italic_ with `code` and <https://example.com|links>"}}]

Lists and Code

markdown = """
## Features

- Easy to use
- Fast processing
- Great documentation

```python
def hello():
    return "world"

""" blocks = markdown_to_blocks(markdown)

Generates HeaderBlock, SectionBlock (list), and SectionBlock (code)


### Tables

```python
markdown = """
| Feature | Status |
|---------|--------|
| Auth | ✅ Done |
| API | 🚧 Progress |
"""
blocks = markdown_to_blocks(markdown)
# Generates custom TableBlock with proper cell structure

Editing Blocks (Object-Based API)

from slack_blocks_markdown import markdown_to_block_objects

# Generate blocks from markdown
markdown = """# Project Status

Current progress:

- Feature A: Complete
- Feature B: In progress
"""

blocks = markdown_to_block_objects(markdown)

# Modify the header dynamically
project_name = "My Awesome Project"
blocks[0].text.text = f"{project_name} - Status Report"

# Add a timestamp to the paragraph
from datetime import datetime
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M")
blocks[1].text.text = f"Report generated at {timestamp}\n\n" + blocks[1].text.text

# Convert to dictionaries and send
from slack_sdk import WebClient
client = WebClient(token="your-token")
client.chat_postMessage(
    channel="#general",
    blocks=[block.to_dict() for block in blocks]
)

Combining Manual and Generated Blocks

from slack_blocks_markdown import markdown_to_block_objects
from slack_sdk.models.blocks import DividerBlock, SectionBlock, MarkdownTextObject

# Generate blocks from markdown
markdown = "## Summary\n\nProject is on track."
generated_blocks = markdown_to_block_objects(markdown)

# Create custom blocks manually
custom_header = SectionBlock(
    text=MarkdownTextObject(text="*Custom Section*")
)

# Combine blocks in any order
all_blocks = [
    custom_header,
    DividerBlock(),
    *generated_blocks,  # Insert all generated blocks
]

# Send to Slack
client.chat_postMessage(
    channel="#general",
    blocks=[block.to_dict() for block in all_blocks]
)

API Reference

markdown_to_blocks(markdown_text: str, expand_sections: bool | None = None) -> list[dict[str, Any]]

Convenience function to convert markdown to Slack block dictionaries.

Parameters:

  • markdown_text: Markdown formatted string
  • expand_sections: (Optional) Control section block expansion
    • True: Force all section blocks to be fully expanded
    • False: Allow Slack to show "Show more" button for long content
    • None (default): Use Slack's default behavior

Returns:

  • List of Slack block dictionaries ready for API use

Example:

blocks = markdown_to_blocks("# Hello\n\nWorld", expand_sections=True)
client.chat_postMessage(channel="#general", blocks=blocks)

markdown_to_block_objects(markdown_text: str, expand_sections: bool | None = None) -> list[Block]

Convert markdown to editable Slack Block objects.

Parameters:

  • markdown_text: Markdown formatted string
  • expand_sections: (Optional) Control section block expansion (same as above)

Returns:

  • List of Block objects from slack_sdk that can be modified

Example:

blocks = markdown_to_block_objects("# Hello\n\nWorld")
blocks[0].text.text = "Modified Header"  # Edit blocks
block_dicts = [b.to_dict() for b in blocks]  # Convert when ready

Use Cases:

  • Modify generated blocks before sending
  • Add dynamic content to specific blocks
  • Combine with custom block creation
  • Inspect block structure programmatically

SlackBlocksRenderer

Main renderer class inheriting from mistletoe's BaseRenderer.

Parameters:

  • expand_sections: (Optional) Control section block expansion behavior

Methods:

  • render(document): Convert mistletoe Document to list of Block objects
  • Context manager support for proper resource handling

Example:

from mistletoe import Document
with SlackBlocksRenderer(expand_sections=True) as renderer:
    document = Document(markdown_text)
    blocks = renderer.render(document)

TableBlock

Custom table block implementation for Slack Block Kit.

Parameters:

  • rows: List of rows (each row is list of cell objects)
  • block_id: Optional unique identifier (max 255 chars)
  • column_settings: Optional column configuration

Slack Block Kit Constraints

This library automatically handles Slack's Block Kit constraints:

  • Headers: Maximum 150 characters (truncated with "..." if longer)
  • Text blocks: Maximum 3000 characters (truncated with "..." if longer)
  • Tables: Maximum 100 rows, 20 columns per row
  • Block IDs: Maximum 255 characters

Development

# Clone repository
git clone https://github.com/atacan/slack-blocks-markdown.git
cd slack-blocks-markdown

# Install with development dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Run linting
ruff check src/ tests/
black src/ tests/

# Run type checking
mypy src/

Testing

The library includes comprehensive tests covering:

  • All markdown element types
  • Slack constraint validation
  • Edge cases and error handling
  • Integration with Slack API format
  • Performance with large documents
# Run with coverage
pytest --cov=slack_blocks_markdown --cov-report=html

Contributing

Contributions welcome! Please:

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new functionality
  4. Ensure all tests pass
  5. Submit a pull request

License

MIT License - see LICENSE file for details.

Changelog

See CHANGELOG.md for version history.

Related Projects

Release files for slack-blocks-markdown 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for slack-blocks-markdown 0.2.1
File Size Uploaded
slack_blocks_markdown-0.2.1.tar.gz 24.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for slack-blocks-markdown 0.2.1
File Interpreter ABI Platform
slack_blocks_markdown-0.2.1-py3-none-any.whl Python 3 none any Details

Total release size: 38.2 kB

Release files / slack_blocks_markdown-0.2.1.tar.gz

Download URL slack_blocks_markdown-0.2.1.tar.gz
Size 24.1 kB
Tags Source
SHA-256 checksum
How to use checksums
c623913e0590bdc097b74697857dbf3c4b93525f6ba2100cfeb2445f1c36da7f
BLAKE2b-256 checksum
How to use checksums
afd7aa1990f8e24a38202df2d64dbaf58955f25a1eda6185e96e513ffe30cbc5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Dec 15, 2025.

Transparency log

Release files / slack_blocks_markdown-0.2.1-py3-none-any.whl

Download URL slack_blocks_markdown-0.2.1-py3-none-any.whl
Size 14.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
620332d365f80161c81b27cb15ae573d4c097d12768becc75219d01b35f53c3d
BLAKE2b-256 checksum
How to use checksums
7f28bf7fe4eb5f6a5a0c2bf673f43410335b9eb2db687c767d0ee8c875e540ba
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Dec 15, 2025.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 release files

0.2.0

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page