A high-performance pure UIKit framework for rendering Markdown with real-time streaming support. Built for Open Relay, an iOS client for Open WebUI.
- iOS 16.0+ / iPadOS 16.0+
- Block-level render cache (
CachedBlockSegment): EachMarkdownBlockNodeis rendered once and cached. Only changed blocks are re-rendered. - Persistent
NSMutableAttributedStringmutation: Dirty tail is deleted and replaced in-place — CoreText only re-lays out the changed portion. - Deferred layout:
setNeedsLayout()lets the run loop coalesce passes — no per-token stalls. - Incremental streaming parser: Maintains a "stable prefix" (parsed once, cached). Only the short "live tail" is re-parsed each tick.
- Virtual line windowing (CodeView): Large code blocks render only the visible viewport + overscan — O(viewport), not O(total lines).
StreamingCodeBlockView: Bypasses the markdown parser entirely for unclosed fences — O(delta) append + O(viewport) windowed render.
- HighlightSwift (pure Swift/JavaScriptCore) with async per-block highlighting
- 300ms debounce during streaming — no flickering
- LRU cache (512 entries) with dark/light appearance variants
CodeHighlighter.warmUp()— call at app launch to front-load JSContext init
- SwiftMath for LaTeX → image rendering
- Async two-pass: text renders immediately, math images arrive off-main-thread
- LRU cache (256 entries)
- Tap-to-preview via QuickLook
- h1–h6 render at distinct sizes (1.6×–0.85× body) via
fontForHeadingLevel(_:) - Configurable through
MarkdownTheme
- 🚀 120Hz streaming — smooth token-by-token rendering on ProMotion displays
- 🎨 Syntax highlighting — async, debounced, cached, dark/light aware
- 📐 Configurable spacing — paragraph, line, heading, blockquote, list
- 📊 Math rendering — LaTeX with tap-to-preview
- 🔗 Clickable links — opens via notification (no setup needed)
- ✅ Task lists, tables, blockquotes — full GFM support
- 📱 iPad multitasking — correct sizing in Split View / Stage Manager
dependencies: [
.package(url: "https://github.com/Ichigo3766/MarkdownView", branch: "main"),
]import MarkdownView
struct ContentView: View {
var body: some View {
MarkdownView("# Hello World\n\nLinks are [clickable](https://example.com)!")
}
}StreamingCodeBlockView(
language: "python",
content: liveCode,
isStreaming: true,
theme: .default
)MarkdownView(text, theme: customTheme)
.codeAutoScroll(true) // auto-scroll code blocks during streaming
.codeBarHidden(true) // hide built-in code block headervar theme = MarkdownTheme.default
theme.align(to: 18) // scale all fonts to 18pt base
theme.colors.body = .white
theme.spacings.paragraphSpacing = 12MIT License. See LICENSE.
- Original framework by Lakr233
- Code adapted from swift-markdown-ui by Guillermo Gonzalez (MIT License)