-
Notifications
You must be signed in to change notification settings - Fork 431
Description
I have markdown text with multiple inline images - example: An image  within  a line of text.
And this works fine:

However, I also have logic that adds/removes images from within the markdown. If I remove the cloud image, making the markdown: An image  within a line of text.
, the cloud image is correctly removed. However, the sunset image is also briefly removed from the rendered text which causes some flickering and layout artifacts:
Simulator.Screen.Recording.-.iPhone.16e.-.2025-07-17.at.14.22.36.mp4
There are two problems in this video: see the "end" label wiggles up and down, because the Markdown height is slightly higher once all images are loaded. You can also see the word "within" shift to the left incorrectly; we never removed the sunset image from the markdown, but because InlineImageProvider is async, the first render of the label doesn't yet have any images, so the "within" is shifted to the left.
Checklist
- [x ] I can reproduce this issue with a vanilla SwiftUI project.
- [x ] I can reproduce this issue using the
main
branch of this package. - [x ] This bug hasn't been addressed in an existing GitHub issue.
Steps to reproduce
The following standalone code shows the issue:
import MarkdownUI
import SwiftUI
let one = "An image  within a line of text."
let two = "An image  within  a line of text."
struct SystemImageInlineImageProvider: InlineImageProvider {
private let name: (URL) -> String
public init(name: @escaping (URL) -> String = \.lastPathComponent) {
self.name = name
}
public func image(with url: URL, label: String) async throws -> Image {
// Add an artificial delay to make the issue more obvious.
try await Task.sleep(for: .seconds(0.2))
return .init(systemName: self.name(url))
}
}
extension InlineImageProvider where Self == SystemImageInlineImageProvider {
static var system: Self { .init() }
}
struct ImageFlickerView: View {
@State var currentContent: String = one
var body: some View {
ScrollView {
VStack {
Text("start")
.frame(maxWidth: .infinity, alignment: .leading)
.padding(.bottom, 24)
Markdown(currentContent)
.markdownInlineImageProvider(SystemImageInlineImageProvider())
.frame(maxWidth: .infinity, alignment: .leading)
Text("end")
.frame(maxWidth: .infinity, alignment: .leading)
.padding(.top, 24)
Spacer()
}
.onTapGesture {
currentContent = currentContent == one ? two : one
}
.padding(.horizontal, 24)
}
}
}
Version information
- MarkdownUI: current
- OS: iOS 18
- Xcode: 16
Additional context
My suggestion would be to add a function func placeholder() -> Text?
to InlineImageProvider, with a default impl that returns nil. TextInlineRenderer.renderImage(_:) would then have access to this placeholder, and would use that until the image is loaded.
I have this change working locally and would be happy to raise a PR for it.