The @streamdown/cjk plugin fixes two categories of parsing problems that arise with Chinese, Japanese, and Korean (CJK) text in CommonMark/GFM:
- Emphasis near ideographic punctuation — bold, italic, and strikethrough markers adjacent to characters like
()。, fail to be recognized by default parsers.
- Autolink boundary bleeding — URLs followed by CJK punctuation cause the punctuation to be swallowed into the URL.
This is especially relevant for AI-generated content, where language models write natural markdown emphasis around phrases that include or end with punctuation.
Installation
Install the package
npm install @streamdown/cjk
Pass the plugin to Streamdown
import { Streamdown } from 'streamdown';
import { cjk } from '@streamdown/cjk';
export default function Chat({ markdown }: { markdown: string }) {
return (
<Streamdown plugins={{ cjk }}>
{markdown}
</Streamdown>
);
}
What the plugin fixes
Emphasis near ideographic punctuation
The CommonMark specification has a known limitation where emphasis markers are not recognized when adjacent to ideographic punctuation. Without the CJK plugin:
**この用語(読み方など)**について説明します。
renders as plain text rather than bold, because the closing ** appears next to ).
With @streamdown/cjk, bold, italic, and GFM strikethrough all work correctly next to any ideographic punctuation in Japanese, Chinese, and Korean.
Autolink boundary splitting
When GFM autolinks are followed by CJK punctuation, the plugin splits the link at the boundary so the punctuation is rendered as text:
Check out https://example.com。这是一个链接。
Without the plugin, 。 is included in the URL. With the plugin, the link stops at https://example.com and the period renders as text.
Recognized boundary characters:
。.,、?!:;()【】「」『』〈〉《》
Plugin architecture
The CJK plugin provides remark plugins split into two groups based on where they must run relative to remark-gfm:
interface CjkPlugin {
name: 'cjk';
type: 'cjk';
/**
* Plugins that run BEFORE remark-gfm.
* remark-cjk-friendly modifies emphasis parsing rules
* and must be registered before GFM processing.
*/
remarkPluginsBefore: Pluggable[];
/**
* Plugins that run AFTER remark-gfm.
* Autolink boundary splitting and strikethrough enhancements
* need GFM autolinks and strikethrough to be created first.
*/
remarkPluginsAfter: Pluggable[];
/** @deprecated Use remarkPluginsBefore and remarkPluginsAfter */
remarkPlugins: Pluggable[];
}
Streamdown handles the ordering automatically. The final remark pipeline when using the CJK plugin is:
remarkPluginsBefore → remark-cjk-friendly
remark-gfm (default)
remarkPluginsAfter → autolink boundary splitter, remark-cjk-friendly-gfm-strikethrough
If you are assembling the remark pipeline manually (e.g. passing a custom remarkPlugins array), you must preserve this ordering yourself. Use remarkPluginsBefore and remarkPluginsAfter from the plugin object rather than the deprecated remarkPlugins array.
API reference
createCjkPlugin()
Creates a CjkPlugin instance. The function takes no options:
import { createCjkPlugin } from '@streamdown/cjk';
const cjk = createCjkPlugin();
@streamdown/cjk exports a pre-configured instance:
import { cjk } from '@streamdown/cjk';
// Equivalent to: createCjkPlugin()
When to use this plugin
Add @streamdown/cjk when:
- Your application renders AI-generated content in Chinese, Japanese, or Korean.
- Users can write markdown in CJK languages.
- You display content from sources that mix CJK text with emphasis markers or URLs.
The plugin is a no-op for purely ASCII content — there is no performance penalty for including it when CJK text is absent.