Hi, thanks for this great library.
I noticed a significant performance problem when rendering Markdown with deeply nested lists, especially when the content contains multiple levels of nested ordered and unordered lists.
What happens
Rendering becomes very slow when the nesting depth increases. In my testing, the slowdown is much more noticeable with nested lists than with other block structures.
This seems to be a rendering/layout problem rather than a Markdown parsing problem.
Why this may be happening
After reading the code, I think the main cost comes from SwiftUI layout invalidation and repeated recomputation in the list rendering pipeline:
-
NumberedListView measures marker width dynamically via GeometryReader + PreferenceKey, then writes the result back into @State.
This appears to cause an extra layout pass for each ordered-list level.
-
BlockSequence uses PreferenceKey updates to collect block margins and stores them in local state.
In deeply nested list trees, this likely creates cascading state updates and relayout across parent/child list containers.
-
BlockSequence uses ForEach(..., id: \.self), while BlockNode / RawListItem are recursive Hashable structures.
For deeply nested content, identity/hash calculation may become unnecessarily expensive.
-
When relayout happens, inline text rendering also gets recomputed repeatedly, which amplifies the visible cost.
Relevant code paths
Sources/MarkdownUI/Views/Blocks/NumberedListView.swift
Sources/MarkdownUI/Views/Blocks/ListItemView.swift
Sources/MarkdownUI/Views/Blocks/ColumnWidthPreference.swift
Sources/MarkdownUI/Views/Blocks/BlockSequence.swift
Suggested direction
A minimal optimization might be:
- Avoid dynamic marker width measurement for ordered lists, or at least avoid feeding it back through
@State for every nested list level.
- Use stable positional identity like
id: \.index in BlockSequence instead of id: \.self for recursive list/block nodes.
I suspect these two changes alone could significantly improve nested list rendering performance.
Minimal example
A deeply nested structure like this is enough to reproduce the issue:
1. Level 1
- Level 2
1. Level 3
- Level 4
1. Level 5
- Level 6
1. Level 7
- Level 8
1. Level 9
- Level 10
The real issue becomes more obvious when each item contains paragraph text and multiple sibling items at each level.
Expected behavior
Rendering nested lists should remain reasonably fast even when the nesting depth is high.
Actual behavior
Rendering time increases sharply as list nesting grows, especially with ordered lists.
If helpful, I can also rewrite this into a more GitHub-native style, like a shorter “bug report” version or a more technical version with clearer implementation notes.
Hi, thanks for this great library.
I noticed a significant performance problem when rendering Markdown with deeply nested lists, especially when the content contains multiple levels of nested ordered and unordered lists.
What happens
Rendering becomes very slow when the nesting depth increases. In my testing, the slowdown is much more noticeable with nested lists than with other block structures.
This seems to be a rendering/layout problem rather than a Markdown parsing problem.
Why this may be happening
After reading the code, I think the main cost comes from SwiftUI layout invalidation and repeated recomputation in the list rendering pipeline:
NumberedListViewmeasures marker width dynamically viaGeometryReader+PreferenceKey, then writes the result back into@State.This appears to cause an extra layout pass for each ordered-list level.
BlockSequenceusesPreferenceKeyupdates to collect block margins and stores them in local state.In deeply nested list trees, this likely creates cascading state updates and relayout across parent/child list containers.
BlockSequenceusesForEach(..., id: \.self), whileBlockNode/RawListItemare recursiveHashablestructures.For deeply nested content, identity/hash calculation may become unnecessarily expensive.
When relayout happens, inline text rendering also gets recomputed repeatedly, which amplifies the visible cost.
Relevant code paths
Sources/MarkdownUI/Views/Blocks/NumberedListView.swiftSources/MarkdownUI/Views/Blocks/ListItemView.swiftSources/MarkdownUI/Views/Blocks/ColumnWidthPreference.swiftSources/MarkdownUI/Views/Blocks/BlockSequence.swiftSuggested direction
A minimal optimization might be:
@Statefor every nested list level.id: \.indexinBlockSequenceinstead ofid: \.selffor recursive list/block nodes.I suspect these two changes alone could significantly improve nested list rendering performance.
Minimal example
A deeply nested structure like this is enough to reproduce the issue:
The real issue becomes more obvious when each item contains paragraph text and multiple sibling items at each level.
Expected behavior
Rendering nested lists should remain reasonably fast even when the nesting depth is high.
Actual behavior
Rendering time increases sharply as list nesting grows, especially with ordered lists.
If helpful, I can also rewrite this into a more GitHub-native style, like a shorter “bug report” version or a more technical version with clearer implementation notes.