SkillAgentSearch skills...

MarkdownView

Markdown View for iOS.

Install / Use

/learn @keitaoouchi/MarkdownView
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

MarkdownView

Swift 6.0 Swift Package Manager compatible

A WKWebView-based Markdown renderer for iOS. Converts Markdown to HTML using markdown-it with syntax highlighting by highlight.js.

GIF

Features

  • Renders Markdown as styled HTML inside a native UIView
  • Syntax highlighting for code blocks via highlight.js
  • Dark mode support (automatic, via prefers-color-scheme)
  • Custom CSS injection
  • markdown-it plugin support (e.g., KaTeX math)
  • External stylesheet loading
  • Intrinsic content size for Auto Layout integration
  • Link tap handling
  • SwiftUI support via MarkdownUI

Requirements

| Target | Version | |--------|---------| | iOS | >= 16.0 | | Swift | >= 6.0 |

Installation

MarkdownView is available through Swift Package Manager.

Swift Package Manager

dependencies: [
    .package(url: "https://github.com/keitaoouchi/MarkdownView.git", from: "2.1.0")
]

Alternatively, you can add the package directly via Xcode (File > Add Package Dependencies).

Quick Start

UIKit

import MarkdownView

let md = MarkdownView()
md.reconfigure()
md.render(markdown: "# Hello World!")

SwiftUI

import SwiftUI
import MarkdownView

struct ContentView: View {
    var body: some View {
        ScrollView {
            MarkdownUI(body: "# Hello World!")
                .onTouchLink { request in
                    print(request.url ?? "")
                    return false
                }
                .onRendered { height in
                    print(height)
                }
        }
    }
}

API Reference

MarkdownView (UIKit)

Initializers

| Signature | Description | |-----------|-------------| | init() | Creates a view with default settings. Call reconfigure() then render(markdown:) to display content. | | init(css: String?, plugins: [String]?, stylesheets: [URL]? = nil, styled: Bool = true) | Pre-configures a web view with CSS, plugins, and stylesheets. Use with render(markdown:) for efficient updates. | | init?(coder: NSCoder) | Interface Builder support. |

Properties

| Name | Type | Default | Description | |------|------|---------|-------------| | isScrollEnabled | Bool | true | Controls whether the internal web view scrolls. Set false when embedding in a UIScrollView. | | onTouchLink | ((URLRequest) -> Bool)? | nil | Called when a link is tapped. Return true to allow navigation, false to cancel. | | onRendered | ((CGFloat) -> Void)? | nil | Called when rendering completes. The parameter is the content height in points. | | intrinsicContentSize | CGSize | — | Returns the measured content height. Updates automatically after rendering. |

Methods

| Signature | Description | |-----------|-------------| | reconfigure(css: String? = nil, plugins: [String]? = nil, stylesheets: [URL]? = nil, styled: Bool = true) | Creates (or recreates) the internal web view with the given CSS, plugins, and stylesheets. | | reconfigure(with: ConfigurationOptions) | Same as above using a ConfigurationOptions struct. | | render(markdown: String, options: RenderOptions = RenderOptions()) | Renders Markdown on the current web view. If the web view is still loading, the request is queued and executed automatically when ready. |

reconfigure vs render: reconfigure sets up the web view and styling. render sends Markdown to the already-configured web view. For dynamic content that changes frequently, call reconfigure once and then render for each update.

Deprecated: load(markdown:...) and show(markdown:) still work but are deprecated. Use reconfigure + render instead.

MarkdownUI (SwiftUI)

Initializer

MarkdownUI(
    body: String? = nil,
    css: String? = nil,
    plugins: [String]? = nil,
    stylesheets: [URL]? = nil,
    styled: Bool = true
)

| Parameter | Type | Default | Description | |-----------|------|---------|-------------| | body | String? | nil | The Markdown string to render. | | css | String? | nil | Custom CSS to inject. | | plugins | [String]? | nil | Array of markdown-it plugin JavaScript strings. | | stylesheets | [URL]? | nil | External stylesheet URLs to load. | | styled | Bool | true | Use the built-in Bootstrap-based stylesheet. |

View Modifiers

| Modifier | Description | |----------|-------------| | .onTouchLink(perform: @escaping (URLRequest) -> Bool) | Called when a link is tapped. Return true to allow navigation, false to cancel. | | .onRendered(perform: @escaping (CGFloat) -> Void) | Called when rendering completes with the content height. |

Note: MarkdownUI disables internal scrolling. Wrap it in a ScrollView for scrollable content.

Customization

Custom CSS

Inject a CSS string to override the default styles:

// UIKit
let css = "body { background-color: #f0f0f0; } code { font-size: 14px; }"
let md = MarkdownView(css: css, plugins: nil)
md.render(markdown: "# Styled content")

// SwiftUI
MarkdownUI(body: "# Styled content", css: "body { background-color: #f0f0f0; }")

See Example/Example/ViewController/CustomCss.swift for a full example.

Plugins

Add markdown-it compatible plugins by passing the plugin JavaScript as a string. Each plugin must be self-contained with no external dependencies.

let katexPlugin = try! String(contentsOfFile: Bundle.main.path(forResource: "katex", ofType: "js")!)
let md = MarkdownView(css: nil, plugins: [katexPlugin])
md.render(markdown: "Inline math: $E = mc^2$")

See Example/Example/ViewController/Plugins.swift for a full example, and the sample plugin project for building a compatible plugin library.

External Stylesheets

Load CSS from remote URLs:

let url = URL(string: "https://example.com/custom.css")!
let md = MarkdownView(css: nil, plugins: nil, stylesheets: [url])
md.render(markdown: "# Remote-styled content")

Styled vs Non-Styled Mode

By default, styled: true loads a Bootstrap-based stylesheet with highlight.js themes. Set styled: false to start with a blank canvas and apply your own CSS from scratch.

let md = MarkdownView(css: myCustomCSS, plugins: nil, styled: false)

Dark Mode

The built-in stylesheet supports dark mode automatically via prefers-color-scheme. Text and link colors adapt to the system appearance. No additional configuration is needed.

To customize dark mode styles, inject CSS with a prefers-color-scheme media query:

let css = """
@media (prefers-color-scheme: dark) {
    body { background-color: #1a1a1a; }
    code { color: #e06c75; }
}
"""
let md = MarkdownView(css: css, plugins: nil)

Example Project

The Example/ directory contains a full iOS app demonstrating UIKit usage, custom CSS, and plugin integration.

Architecture

See AGENTS.md for a high-level overview of the component architecture and data flow.

License

bootstrap is licensed under the MIT License. highlight.js is licensed under the BSD-3-Clause License. markdown-it is licensed under the MIT License.

MarkdownView is available under the MIT license. See the LICENSE file for more info.

View on GitHub
GitHub Stars2.1k
CategoryDevelopment
Updated2d ago
Forks227

Languages

HTML

Security Score

100/100

Audited on Mar 29, 2026

No findings