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.
- 🚀 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
pip install slack-blocks-markdownfrom 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
)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]
)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]| 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 |
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>"}}]markdown = """
## Features
- Easy to use
- Fast processing
- Great documentation
```python
def hello():
return "world"""" blocks = markdown_to_blocks(markdown)
### Tables
```python
markdown = """
| Feature | Status |
|---------|--------|
| Auth | ✅ Done |
| API | 🚧 Progress |
"""
blocks = markdown_to_blocks(markdown)
# Generates custom TableBlock with proper cell structure
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]
)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]
)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)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 readyUse Cases:
- Modify generated blocks before sending
- Add dynamic content to specific blocks
- Combine with custom block creation
- Inspect block structure programmatically
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)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
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
# 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/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=htmlContributions welcome! Please:
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
MIT License - see LICENSE file for details.
See CHANGELOG.md for version history.
- mistletoe - The markdown parser we use
- slack-sdk - Official Slack SDK for Python
- Slack Block Kit Builder - Visual tool for building Slack blocks