react-streamdown: code blocks keep the previous highlighter when components change without new text

Author: okisdevCreated Sep 17, 2026Updated Sep 17, 2026
Labelsbug

changing components.SyntaxHighlighter, components.CodeHeader or an entry of componentsByLanguage on StreamdownTextPrimitive does not update code blocks that are already rendered until their text changes. reproduced in streaming and static mode on f36e94500 and on 69c3d0f17 (before #7651):

typescript
const view = (SyntaxHighlighter: ComponentType<SyntaxHighlighterProps>) => (
  <TextMessagePartProvider text={"```ts\nconst x = 1;\n```"} isRunning={false}>
    <StreamdownTextPrimitive
      mode="static"
      componentsByLanguage={{ ts: { SyntaxHighlighter } }}
    />
  </TextMessagePartProvider>
);
const { rerender } = render(view(First));
rerender(view(Second));
// First is still rendered and Second never renders

useAdaptedComponents hands streamdown a code component that is a stable useCallbackRef wrapper (#7082), and StreamdownTextPrimitive stabilizes the components map, so streamdown receives the same props. streamdown 2.6.0's Streamdown memo does not compare components, and its Block memo compares entries by identity, so nothing re-renders; the new adapter only reaches a block the next time that block re-renders for another reason, such as new text or an animated message completing.

a fix has to let an adapter change reach settled blocks without bringing back a re-render per streamed token, for example by giving the code entry a new identity only when the adapter's components change.

Track in Rupic

Source: assistant-ui/assistant-ui