Skip to main content
The @streamdown/cjk plugin fixes two categories of parsing problems that arise with Chinese, Japanese, and Korean (CJK) text in CommonMark/GFM:
  1. Emphasis near ideographic punctuation — bold, italic, and strikethrough markers adjacent to characters like ()。, fail to be recognized by default parsers.
  2. 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

1

Install the package

npm install @streamdown/cjk
2

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. 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:
  1. remarkPluginsBeforeremark-cjk-friendly
  2. remark-gfm (default)
  3. 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();

Pre-configured instance

@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.

Build docs developers (and LLMs) love