You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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:
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.
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.
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
mainbranch of this package.Steps to reproduce
The following standalone code shows the issue:
Version information
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.