Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .changeset/fix-single-tilde-545.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
"streamdown": patch
---

fix: disable singleTilde in remark-gfm to prevent single ~ from rendering as strikethrough

Single tilde (`~foo~`) should not be interpreted as strikethrough markup.
This aligns with GitHub GFM behavior where only double tildes (`~~text~~`)
create strikethrough. Set `singleTilde: false` in the default remark-gfm
configuration.

Fixes #545
39 changes: 39 additions & 0 deletions packages/streamdown/__tests__/single-tilde.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { render } from "@testing-library/react";
import { describe, expect, it } from "vitest";
import { Streamdown } from "../index";

describe("Single tilde handling (#545)", () => {
it("should not render single tilde as strikethrough", () => {
const content = "~foo~ is not strikethrough";
const { container } = render(<Streamdown>{content}</Streamdown>);

// Single tilde should NOT create a <del> element
const del = container.querySelector("del");
expect(del).toBeNull();

// Text content should contain the tilde characters
const text = container.textContent;
expect(text).toContain("~foo~");
});

it("should still render double tilde as strikethrough", () => {
const content = "~~strikethrough~~";
const { container } = render(<Streamdown>{content}</Streamdown>);

// Double tilde SHOULD create a <del> element
const del = container.querySelector("del");
expect(del).not.toBeNull();
expect(del?.textContent).toBe("strikethrough");
});

it("should not render single ~ between words as strikethrough", () => {
const content = "Temperature range is 20~25°C";
const { container } = render(<Streamdown>{content}</Streamdown>);

const del = container.querySelector("del");
expect(del).toBeNull();

const text = container.textContent;
expect(text).toContain("20~25");
});
});
2 changes: 1 addition & 1 deletion packages/streamdown/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ export const defaultRehypePlugins: Record<string, Pluggable> = {
} as const;

export const defaultRemarkPlugins: Record<string, Pluggable> = {
gfm: [remarkGfm, {}],
gfm: [remarkGfm, { singleTilde: false }],
codeMeta: remarkCodeMeta,
} as const;

Expand Down
Loading