ComposeMarkdownMultiplatform
0.1.9indexedDeclarative Compose Markdown renderer using CommonMark parsing, modular plugin architecture for tables/images/HTML, themeable typography/colors, and extensible parser extensions for customizable rendering.
Declarative Compose Markdown renderer using CommonMark parsing, modular plugin architecture for tables/images/HTML, themeable typography/colors, and extensible parser extensions for customizable rendering.
A Compose Multiplatform Markdown rendering library that supports Android, iOS, Desktop (JVM), and WebAssembly (Wasm).
Looking for Android-only with richer Markdown compatibility? Check out ComposeMarkdown — it offers deeper Markdown spec support (powered by Flexmark) and more rendering features for Android projects.
| Desktop | Android | WebAssembly (Wasm) |
|---|---|---|
![]() | ![]() | ![]() |
| Platform | Status |
|---|---|
| Android | Supported |
| iOS (arm64, x64, simulator) |
Add the dependency to your project's build.gradle.kts:
// In your shared module's build.gradle.kts
kotlin {
sourceSets {
val commonMain by getting {
dependencies {
implementation("io.github.feiyin0719:markdown-multiplatform:<version>")
}
}
}
}
| Plugin | Artifact |
|---|
dependencies {
implementation("io.github.feiyin0719:markdown-multiplatform-table:<version>")
implementation("io.github.feiyin0719:markdown-multiplatform-image:<version>")
implementation("io.github.feiyin0719:markdown-multiplatform-html:<version>")
}
import io.github.feiyin0719.markdown.multiplatform.MarkdownView
@Composable
fun SimpleMarkdownExample() {
val markdownContent = """
# Hello Compose Markdown Multiplatform
This is a **cross-platform** Markdown rendering library.
- Android
- iOS
- Desktop
- Web (Wasm)
""".trimIndent()
MarkdownView(
content = markdownContent,
modifier = Modifier.fillMaxSize(),
)
}
LazyMarkdownView reads a stable line source incrementally and recycles parsed nodes away from the
viewport. Stable lazy-item keys preserve the visible anchor when nodes are removed or reloaded.
It can also accept a Markdown string directly for side-by-side comparison with the Android API.
@Composable
fun LargeMarkdownExample(markdown: String) {
val source = remember(markdown) { StringMarkdownLineSource(markdown) }
LazyMarkdownView(
source = source,
modifier = Modifier.fillMaxSize(),
chunkLoaderConfig = MarkdownChunkLoaderConfig(
initialLineCount = 1000,
incrementalLineCount = 500,
minNodesAhead = 100,
minNodesBehind = 30,
maxCachedNodes = 500,
maxCachedSourceLines = 10_000,
),
)
}
For true lazy I/O, implement MarkdownLineSource with a stable file, asset, database, or range API.
The source must support rereading old ranges because scrolling backward reloads recycled nodes.
Chunk parses do not share reference-definition state; use inline links or LazyMarkdownColumn when
full-document reference resolution is required.
onLoadingChanged reports only the initial empty-screen wait. Use onStateChanged with
LazyMarkdownViewState to observe optional background before/after loading UI. AST recycling is
silent and internal concurrency uses a separate operation guard.
maxCachedSourceLines is also a hard limit for one unconfirmed trailing block or source context.
Set on or while text is appended at the end. Stable prefix nodes are reused and only the previous final block is reparsed. Set when generation finishes to force an authoritative full parse. A custom can replace the default workflow through ; its method receives only the complete content and streaming flag and can control the entire parsing lifecycle. The factory defaults to ; without one, streaming requests use normal full parsing. Configure explicitly to enable the built-in workflow. It creates its own parser with at least block source spans. Regular parser spans are configurable and default to ; also forces at least .
A custom streaming parser must return a new root Document for each changed input so Compose sees
the update, while reusing unchanged completed child blocks by identity so their keyed renderers can
skip recomposition.
MarkdownView(
text = streamedMarkdown,
parseDispatcher = Dispatchers.Default,
isStreaming = streamInProgress,
)
| Technology | Purpose |
|---|---|
For full API signatures and detailed parameter explanations, see the dedicated API document:
We welcome contributions! To get started:
git checkout -b feat/my-featureReleased under the MIT License. See LICENSE for details.
Made with love by the Compose Markdown team
commonmark-kotlin parser (pure Kotlin Multiplatform)Text with maxLines / overflow support and cross-paragraph text selectionMarkdownView and MarkdownText overloads accept a parsing dispatcher with loading/error content| Supported |
| Desktop (JVM) | Supported |
| WebAssembly (Wasm) | Supported |
| Description |
|---|
| Table | markdown-multiplatform-table | GFM table support |
| Image | markdown-multiplatform-image | Markdown image rendering |
| HTML | markdown-multiplatform-html | HTML inline tag support |
isStreaming = trueMarkdownViewMarkdownTextisStreaming = falseStreamingMarkdownParserMarkdownRenderConfig.Builder.streamingMarkdownParserFactoryparsenull::DefaultStreamingMarkdownParserIncludeSourceSpans.BLOCKSLazyMarkdownViewBLOCKS| Compose Multiplatform |
| Cross-platform UI framework |
| commonmark-kotlin | Markdown parsing engine (pure Kotlin Multiplatform) |
| Kotlin Coroutines | Asynchronous processing |
| Material Design 3 | Design language specification |
./gradlew ktlintFormat./gradlew ktlintCheck./gradlew assemblefeat:, fix:, docs:, etc.)Surfaced from shared tags and platforms — no rankings paid for.