The Swift package that turns down HTML and turns up Markdown – it's a markup markdown!
- 🌍 Universal Apple Platform Support: Works seamlessly on iOS, macOS, watchOS, tvOS, and visionOS
- 🎯 WKWebView Integration: Real browser DOM environment for accurate HTML parsing
- ⚡ Turndown.js Powered: Industry-standard HTML to Markdown conversion engine
- 🔒 Swift 6 Ready: Full concurrency support with strict checking enabled
- ⚙️ Highly Configurable: Extensive formatting options for customized output
- 📝 CommonMark Compliant: Standard Markdown output that works everywhere
- 🚀 Async/Await: Modern Swift concurrency for smooth performance
- 🎨 Zero Dependencies: Only requires WebKit framework
Demark provides two HTML to Markdown conversion engines, each with different trade-offs:
How it works: Uses WKWebView to load Turndown.js in a real browser environment with full DOM parsing.
Advantages:
- 🎯 Most accurate conversion: Real browser DOM parsing handles complex/malformed HTML
- 🛡️ Battle-tested: Turndown.js is the industry standard used by millions
- ⚙️ Full configuration options: Supports all formatting styles (ATX/Setext headings, code block styles)
- 🌐 Handles any HTML: Processes JavaScript-rendered content, inline styles, complex nesting
Disadvantages:
- 🐌 Slower performance: ~100ms first conversion (WebView setup), ~10-50ms subsequent
- 💾 Higher memory usage: WKWebView has significant overhead
- 🧵 Main thread only: WebView requires main thread execution
When to use:
- Converting complex HTML from websites or CMSs
- Need maximum compatibility and accuracy
- Processing user-generated or untrusted HTML
- Require full configuration options
How it works: Uses JavaScriptCore to run html-to-md directly without WebView overhead.
Advantages:
- ⚡ Much faster: ~5-10ms per conversion (10x faster than Turndown)
- 💾 Lower memory footprint: No WebView overhead
- 🧵 Background thread capable: Can run on any thread via serial queue
- 🔋 Better for batch processing: Ideal for converting many documents
Disadvantages:
- 📉 Less accurate: String-based parsing may struggle with complex HTML
- ⚙️ Limited configuration: Fewer formatting options available
- 🚫 No DOM environment: Cannot handle JavaScript-rendered content
- 🐛 Less mature: Newer library, may have edge cases
When to use:
- High-performance requirements or batch conversions
- Simple, well-formed HTML content
- Memory-constrained environments (watchOS, widgets)
- Background processing needs
Turndown.js | ~100ms | ~10-50ms | ~20MB | Main thread only |
html-to-md | ~5-10ms | ~5-10ms | ~5MB | Any thread |
- Start with Turndown.js (default) for maximum compatibility
- Switch to html-to-md only if you need the performance boost and your HTML is simple
- Test both with your actual content to ensure quality meets your needs
Want to see Demark in action? Check out the comprehensive example app:
The example app provides a dual-pane interface where you can input HTML on the left and see both the generated Markdown source and rendered output on the right. Perfect for testing and understanding Demark's capabilities!
- Swift 6.0+
- iOS 17.0+ / macOS 14.0+ / watchOS 10.0+ / tvOS 17.0+ / visionOS 1.0+
- WebKit framework
Add Demark to your project using Swift Package Manager. In Xcode, go to File > Add Package Dependencies and enter:
Or add it to your Package.swift:
Then add it to your target:
Demark supports extensive customization through DemarkOptions:
Configure how HTML elements are converted to Markdown:
headingStyle | DemarkHeadingStyle | .atx | Heading format (ATX # or Setext underline) |
bulletListMarker | String | "-" | Character for unordered lists ("-", "*", or "+") |
codeBlockStyle | DemarkCodeBlockStyle | .fenced | Code block format (fenced ``` or indented) |
Demark handles all standard HTML elements that Turndown.js supports:
- Headings: <h1> through <h6>
- Text formatting: <strong>, <em>, <code>, <del>, <ins>, <sup>, <sub>
- Lists: <ul>, <ol>, <li> with proper nesting
- Links and images: <a>, <img> with attributes
- Code blocks: <pre>, <code> with language detection
- Tables: <table>, <tr>, <td>, <th> (GitHub Flavored Markdown)
- Block elements: <div>, <p>, <blockquote>, <hr>
- Custom elements: <del>, <ins>, <sup>, <sub> are preserved
Demark provides comprehensive error handling with detailed error messages:
⚠️ Important: Demark requires main thread execution due to WKWebView constraints:
- First Conversion: ~100ms (includes one-time WKWebView setup)
- Subsequent Conversions: ~10-50ms (reuses WebView instance)
- Memory Efficient: Single WebView per Demark instance
- Platform Optimized: Different configurations for each platform
- Full functionality with desktop optimizations
- Enhanced JavaScript execution environment
- Optimized for large document processing
- Full functionality with mobile/spatial optimizations
- Respects system memory constraints
- Optimized for touch/gesture interfaces
- Core functionality with minimal WebView footprint
- Optimized for limited resources
- Essential conversion features available
Contributions are welcome! Please feel free to submit issues, feature requests, and pull requests.
- Clone the repository
- Open Package.swift in Xcode
- Run tests with ⌘+U
- Make your changes
- Ensure all tests pass
- Submit a pull request
This project uses SwiftLint and SwiftFormat to maintain code quality:
Demark is available under the MIT license. See the LICENSE file for more info.
- Turndown.js: The powerful HTML to Markdown conversion engine by Dom Christie
- Swift Community: For the amazing Swift language and ecosystem
- WebKit Team: For providing the robust WKWebView framework
If Demark doesn't fit your needs, consider these alternatives:
- Server-side conversion: Use Turndown.js directly in Node.js
- Pure Swift: Implement a custom HTML parser (more complex)
- Web-based: Use a web service for conversion (requires network)
Made with ❤️ for the Swift community