Skip to content

Conversation

@zhdzb
Copy link
Contributor

@zhdzb zhdzb commented Nov 27, 2025

The second

(after the blank line) gets rendered as a code block instead of HTML.

Description

Description

When rendering AI-generated HTML content with nested tags (e.g., from streaming socket data), indented HTML tags with 4+ leading spaces are incorrectly parsed as code blocks by the Markdown parser.

This occurs because the Markdown specification treats lines starting with 4+ spaces as indented code blocks. While this behavior is correct for Markdown syntax, it causes issues when rendering HTML content that uses indentation for readability.

Problem Scenario

In streaming scenarios where HTML content is generated incrementally, nested tags are often indented with 4+ spaces for better readability. However, when such content is parsed by Streamdown, the indented HTML tags after blank lines are mistakenly treated as code blocks instead of HTML elements.

Example

HTML content like this:

Title One

<div class="failure">
  <h4>Title Two</h4>
</div>
The second `div tag` (after the blank line) gets rendered as a code block instead of HTML.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Performance improvement
  • Refactoring (no functional changes)

Related Issues

Fixes #
Closes #
Related to #

Changes Made

  • New normalizeHtmlIndentation prop - When enabled, removes excessive indentation (4+ spaces) before HTML tags
  • New normalizeHtmlIndentation() utility function - Exported for manual preprocessing
  • Improved HTML block merging - Better handling of nested HTML tags with void elements and self-closing tags
  • Updated documentation - Added normalizeHtmlIndentation prop to the configuration documentation.

Testing

  • All existing tests pass
  • Added new tests for the changes
  • Manually tested the changes

Test Coverage

-Added 20 new unit tests in normalize-html-indentation.test.tsx covering:
Utility function edge cases (empty strings, non-HTML content, various HTML structures)
Streamdown component behavior with the new prop enabled/disabled
HTML block merging scenarios with nested tags, void elements, and self-closing tags
-All 541 existing tests continue to pass
-No breaking changes to existing functionality

Screenshots/Demos

Before (without normalizeHtmlIndentation):
Indented HTML tags after blank lines are rendered as code blocks.
After (with normalizeHtmlIndentation={true}):
All HTML tags are correctly rendered as HTML elements.

Checklist

  • My code follows the project's code style
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings or errors
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • I have created a changeset (pnpm changeset)

Changeset

  • I have created a changeset for these changes

Additional Notes

@vercel
Copy link
Contributor

vercel bot commented Nov 27, 2025

@zhdzb is attempting to deploy a commit to the Vercel Team on Vercel.

A member of the Team first needs to authorize it.

@zhdzb zhdzb force-pushed the zhdzb/add-normalizeHtmlIndentation-prop branch from 16abcfe to b14e9e2 Compare November 27, 2025 10:13
Copy link
Contributor

@vercel vercel bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Suggestion:

The normalizeHtmlIndentation prop is missing from the Streamdown component's memo comparison function, which means changes to this prop won't trigger a re-render.

View Details
📝 Patch Details
diff --git a/packages/streamdown/index.tsx b/packages/streamdown/index.tsx
index 617da5e..8750c84 100644
--- a/packages/streamdown/index.tsx
+++ b/packages/streamdown/index.tsx
@@ -395,6 +395,7 @@ export const Streamdown = memo(
     prevProps.children === nextProps.children &&
     prevProps.shikiTheme === nextProps.shikiTheme &&
     prevProps.isAnimating === nextProps.isAnimating &&
-    prevProps.mode === nextProps.mode
+    prevProps.mode === nextProps.mode &&
+    prevProps.normalizeHtmlIndentation === nextProps.normalizeHtmlIndentation
 );
 Streamdown.displayName = "Streamdown";

Analysis

Streamdown memo comparison missing normalizeHtmlIndentation prop check

What fails: The Streamdown component's memo comparison function only checks 4 props (children, shikiTheme, isAnimating, mode) but ignores the normalizeHtmlIndentation prop. When this prop changes while others remain the same, the component doesn't re-render, preventing Block components from receiving the updated shouldNormalizeHtmlIndentation value.

How to reproduce:

const [normalize, setNormalize] = useState(false);
return (
  <>
    <button onClick={() => setNormalize(true)}>Toggle normalization</button>
    <Streamdown normalizeHtmlIndentation={normalize}>
      {contentWithIndentedHtml}
    </Streamdown>
  </>
);

After clicking the button, the prop changes but the component won't re-render because the memo comparison returns true (skip re-render) when only normalizeHtmlIndentation changes.

Result: The HTML content is not re-normalized according to the new prop value since Block components never receive the updated shouldNormalizeHtmlIndentation prop.

Expected: When normalizeHtmlIndentation prop changes, the Streamdown component should re-render and pass the new value to Block components.

Fix applied: Added normalizeHtmlIndentation to the memo comparison function in the Streamdown component (line 399 of packages/streamdown/index.tsx). The comparison now checks:

  • prevProps.normalizeHtmlIndentation === nextProps.normalizeHtmlIndentation

This ensures that changes to this prop trigger a re-render, allowing Block components to receive and apply the updated normalization setting.

Fix on Vercel

@zhdzb zhdzb force-pushed the zhdzb/add-normalizeHtmlIndentation-prop branch from b14e9e2 to 683b9b4 Compare November 27, 2025 11:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant