Skip to content

Fix animate plugin whitespace handling in word splitting (especially inside links)#536

Open
aradhyacp wants to merge 4 commits into
vercel:mainfrom
aradhyacp:fix/underline-issue-while-streaming
Open

Fix animate plugin whitespace handling in word splitting (especially inside links)#536
aradhyacp wants to merge 4 commits into
vercel:mainfrom
aradhyacp:fix/underline-issue-while-streaming

Conversation

@aradhyacp

Copy link
Copy Markdown
Contributor

Description

Fixes an issue in the animate plugin where word-based splitting incorrectly handled whitespace inside inline elements (especially links), causing inconsistent token grouping and unexpected animation spans.

This improves whitespace handling logic so words and spaces are grouped more predictably during transformation, reducing fragmented span output.

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 #535
Closes #535
Related to #535

Changes Made

  • Improved word-splitting logic for sep: "word" mode
  • Fixed whitespace merging behavior in inline text nodes
  • Prevented isolated whitespace from becoming separate animated spans
  • Improved consistency of token grouping in nested elements
  • Ensured stagger delay calculation remains stable after token merging
  • Improved behavior inside inline elements like , , etc.

Testing

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

Test Coverage

Manually tested the Code rendered

How I tested it locally:

I wanted to verify my changes, so I linked the local package into a test React app:

# In the streamdown repo
pnpm build
pnpm link

# In my test project
pnpm link streamdown

Then I used the following test component:

import { Streamdown } from "streamdown";
import "streamdown/styles.css";


const App = () => {
  const markdown = `Here is a sentence with [a link to example.com](https://example.com) sitting right in the middle, followed by some more trailing words so you can clearly see how the link animates in relative to the text around it. And here's that link again: [a link to example.com](https://example.com)`

  const components = {
  a: ({ children, ...props }: React.ComponentProps<"a">) => (
    <a {...props} style={{ textDecoration: "underline", color: "#2563eb" }}>
      {children}
    </a>
  ),
};
  return (
    <div className="App">
      <div className="mx-auto mt-5 w-200">
        <Streamdown
        components={components}
        isAnimating={true}
        animated={{
          animation: "fadeIn",
          duration: 500,
          stagger: 50,
          easing: "ease-out",
        }}
      >{markdown}</Streamdown>
      </div>
    </div>
  );
};

export default App;

Screenshots/Demos

Before:

Present in the issue raised

After:

prvideoproof.mov

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

This change improves general robustness of the animation pipeline, but link behavior still needs design-level clarification from maintainers.

⚠️ Known Failing Test Cases (Needs Maintainer Input)

The following test cases are currently failing and were NOT fixed in this PR:


1. Leading/trailing whitespace inside links

it("should preserve leading and trailing spaces inside links correctly", async () => {
  const result = await processHtml('<a href="#"> Hello world </a>');

  expect(result).toContain("> Hello ");
  expect(result).toContain(">world ");
});

Issue:
Whitespace inside <a> tags is not preserved exactly as expected after word tokenization. Current behavior merges whitespace differently during processing.


2. Underline artifact prevention in links

it("should prevent underline artifacts in links", async () => {
  const result = await processHtml('<a href="#">a link to example.com</a>');

  expect(result).toContain(">a link ");
  expect(result).toContain(">example.com<");
});

Issue:
Inside links, text is still split into multiple spans instead of being grouped as expected, leading to unexpected rendering artifacts.

Current implementation improves whitespace handling but does not fully resolve expected link behavior.

@vercel

vercel Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

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

A member of the Team first needs to authorize it.

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.

Animated text with links that have text-decoration: underline show underlines before revealed

1 participant