Slack Blocks Markdown
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 stringexpand_sections: (Optional) Control section block expansionTrue: Force all section blocks to be fully expandedFalse: Allow Slack to show "Show more" button for long contentNone(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 stringexpand_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:
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
License
MIT License - see LICENSE file for details.
Changelog
See CHANGELOG.md for version history.
Related Projects
- mistletoe - The markdown parser we use
- slack-sdk - Official Slack SDK for Python
- Slack Block Kit Builder - Visual tool for building Slack blocks
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)
| File | Size | Uploaded | |
|---|---|---|---|
| slack_blocks_markdown-0.2.1.tar.gz | 24.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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 logRelease 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