From fd99516e517e3dbce3d2298cd57dcfeb237aef98 Mon Sep 17 00:00:00 2001
From: "opencode-agent[bot]"
<219766164+opencode-agent[bot]@users.noreply.github.com>
Date: Wed, 7 Oct 2026 04:33:34 +0000
Subject: [PATCH] fix(session-ui): keep Markdown text selectable (#53665)
Co-authored-by: Brendonovich <14191578+Brendonovich@users.noreply.github.com>
---
packages/gui-extensions/src/file/artifact-view.tsx | 4 ++--
packages/session-ui/component-tests/markdown.spec.ts | 11 +++++++++++
packages/session-ui/src/components/markdown.css | 3 +++
3 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/packages/gui-extensions/src/file/artifact-view.tsx b/packages/gui-extensions/src/file/artifact-view.tsx
index 48af9065497..fcd58dce5c5 100644
--- a/packages/gui-extensions/src/file/artifact-view.tsx
+++ b/packages/gui-extensions/src/file/artifact-view.tsx
@@ -444,7 +444,7 @@ function ArtifactMarkdown(props: { session: MountedSession; path: string; text:
openLocalFile={(href) => void links.open({ href, base: dir(), session: props.session })}
>
-
+
)
@@ -454,7 +454,7 @@ function ArtifactMarkdown(props: { session: MountedSession; path: string; text:
function ArtifactMermaid(props: { text: string; cacheKey?: string }) {
return (
-
+
)
}
diff --git a/packages/session-ui/component-tests/markdown.spec.ts b/packages/session-ui/component-tests/markdown.spec.ts
index 26982b57f82..1837abae1f4 100644
--- a/packages/session-ui/component-tests/markdown.spec.ts
+++ b/packages/session-ui/component-tests/markdown.spec.ts
@@ -36,6 +36,17 @@ story("renders small completed Markdown immediately without skipping sanitizatio
await expect(harness.locator("pre.shiki")).toBeVisible()
})
+story("keeps Markdown text selectable inside a container that disables selection", async ({ page }) => {
+ await page.evaluate(async (fixture) => {
+ document.body.style.userSelect = "none"
+ const { mountMarkdown } = await import(fixture)
+ await mountMarkdown({ text: "Selectable answer text" })
+ }, fixture)
+
+ await page.getByTestId("markdown-fixture").getByText("Selectable answer text").click({ clickCount: 3 })
+ expect(await page.evaluate(() => getSelection()?.toString().trim())).toBe("Selectable answer text")
+})
+
story("sanitizes raw HTML while preserving supported Markdown markup", async ({ page }) => {
const result = await page.evaluate(async (fixture) => {
const { sanitizeMarkdown } = await import(fixture)
diff --git a/packages/session-ui/src/components/markdown.css b/packages/session-ui/src/components/markdown.css
index b237722c71f..529aaccdd1a 100644
--- a/packages/session-ui/src/components/markdown.css
+++ b/packages/session-ui/src/components/markdown.css
@@ -15,6 +15,9 @@
font-family: var(--font-family-sans);
font-size: var(--font-size-base); /* 14px */
line-height: 160%;
+ /* Shells such as the app's turn off selection for chrome; Markdown is content, so it stays selectable. */
+ -webkit-user-select: text;
+ user-select: text;
[data-markdown-word] {
display: inline;