Skip to content

fix(mobile): add a copy button to each code block in chat - #32270

Closed
radut wants to merge 5 commits into
stablyai:mainfrom
radut:mobile-code-block-copy
Closed

radut wants to merge 5 commits into
stablyai:mainfrom
radut:mobile-code-block-copy

Conversation

@radut

@radut radut commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 6 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​12 0 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​12
Prod 2 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​18 $\color{#cf222e}{\Huge{\mathbf{−}}}$​8 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​10

ELI5

Code blocks in the mobile chat now have their own copy button, so you can grab just the command instead of the whole reply.

What Changed

Before: the only copy button on mobile chat copied the whole message.
After: each code block shows a small copy button next to its language label, and it copies only that block. It reuses MobileSourceCopyButton, so the feedback and error handling match the message copy. Mermaid fences don't get one, since they turn into diagrams.

Why

Copying one command out of a long reply on a phone meant copying everything and trimming it by hand. Desktop markdown preview already has a per-block copy button.

Linked Issue

Fixes #32280

Visual Proof

Chat code blocks with the language label and copy button, on an iPhone:

screenshot

Testing

  • I manually tested these changes locally
  • Automated tests added/updated, or explained why not below

New rendering tests: each block copies only its own code, and a streaming mermaid fence gets no button. Mobile vitest, typecheck, oxlint and oxfmt pass.

AI Disclosure

Drafted with Claude Code, reviewed and tested by me.

Review

Agent skill upstream boundary

  • Not applicable, or this change copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.

Notes

Mobile only, no desktop, SSH or platform-specific code touched.

Checklist

  • This PR is small and focused
  • I explained what changed and why (ELI5, the user-facing before/after, the mechanism, and why over the alternatives)
  • Before/after screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred)

Maintainer changes

  • Merged current main into the branch. It was 578 commits behind and merged cleanly.
  • A Mermaid fence that's still streaming keeps its copy button again. Desktop chat does the same: a Mermaid fence gets copy while it shows as code, and loses it only when the diagram replaces the block. This removes the extra Mermaid rule and its test.
  • The copy button now sits beside the code instead of in a header row above it. Before, a fence with no language got a 24pt empty strip above the code just to hold the button. Now the button sits in the block's top-right corner. Labeled blocks keep their height, and unlabeled one-line blocks grow by about 3pt.

The "after" shots are this branch on an iPhone 18 Pro simulator, iOS 27, in a react-native-web harness. iOS builds draw chat in that web page. Tapping copy on the first block put exactly pnpm test --filter mobile on the clipboard, and the second put git push -u origin my-branch.

Before (main) After After tapping copy

Tap, check mark, back to the copy icon after 1.5s:

after-copy.mp4

Linear: STA-11848. Copy for shell commands that the app detects outside code fences is tracked separately in #32773.

@coderabbitai

coderabbitai Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Walkthrough

Mobile Markdown code blocks now place the language label and selectable code text in a flexible body. Non-empty code blocks display a copy button. The code-block layout places the body and button in a row. Tests verify that each code block passes only its own code to its copy button. Other Markdown tests mock the copy button.

Priority: Low

Severity of issue fixed: Low

Merge Risk: Low · up to 1d57c

Mermaid blocks can briefly show an unintended copy button while streaming; this is a narrow, localized UI issue with a straightforward fix.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 3 functions across 8 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title clearly and concisely describes the main change: adding a copy button to each mobile chat code block.
Description check Passed The description is complete and relevant. It explains the user-facing change, implementation, motivation, linked issue, visual proof, tests, AI use, scope, and review considerations. Some full reposit…
Linked Issues check Passed [#32280] Requirement: each code block in mobile chat gets its own copy button, so users can copy one block instead of the whole reply. Evidence at head: in mobile/src/components/mobile-markdown-blocks…
Out of Scope Changes check Passed Changed files in the whole-PR scope are: mobile-markdown-blocks.tsx (per-block copy button and codeBody wrapper), mobile-markdown-styles.ts (codeBlock row layout, codeBody flex style), and six mobile …
Full details: Description check

Explanation

The description is complete and relevant. It explains the user-facing change, implementation, motivation, linked issue, visual proof, tests, AI use, scope, and review considerations. Some full repository checks remain unchecked, but the description reports the relevant mobile tests that passed.

Full details: Linked Issues check

Explanation

[#32280] Requirement: each code block in mobile chat gets its own copy button, so users can copy one block instead of the whole reply. Evidence at head: in mobile/src/components/mobile-markdown-blocks.tsx, renderCode() wraps each non-Mermaid code block in a codeBody view and renders MobileSourceCopyButton with text={node.value} for non-empty blocks. Each button receives only its own block contents. The copy button is therefore per block. The button reuses the existing MobileSourceCopyButton component. Automated test: MobileMarkdown.rendering.test.tsx adds 'gives each code block its own copy button holding only that code'. It renders two fenced blocks and asserts that the button text props equal ['pnpm test', 'exit']. The test mocks MobileSourceCopyButton and checks props only; it does not exercise clipboard behavior. Mermaid fences that complete render as diagrams, so they show no code copy button. This matches the desktop precedent cited in the issue. The issue sets no other coding requirement. No unmet requirement found.

Full details: Out of Scope Changes check

Explanation

Changed files in the whole-PR scope are: mobile-markdown-blocks.tsx (per-block copy button and codeBody wrapper), mobile-markdown-styles.ts (codeBlock row layout, codeBody flex style), and six mobile markdown test files. The test files add a mock for MobileSourceCopyButton. MobileMarkdown.rendering.test.tsx also adds the per-block copy test. The style change supports placing the button beside the code. All changes connect directly to the copy-button objective of #32280. No desktop, SSH, or platform-specific code appears in the changed-file list. The PR description states that copy for shell commands outside code fences is tracked separately in #32773, and this PR does not implement it. The changes_since_previous_review data lists only these files. Limit: the diff for mobile-markdown-blocks.tsx and mobile-markdown-styles.ts was not read as a text diff; the head file was read directly, and the base-to-head style delta is taken from the supplied summary.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2


ℹ️ Review info
⚙️ Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: bb9e3ba9-7b9d-445c-afb8-d03b37dedcc5
📥 Commits

Reviewing files that changed from the base of the PR and between 352b29a and 765c794.

📒 Files selected for processing: 8
  • mobile/src/components/MobileMarkdown.file-links.test.ts
  • mobile/src/components/MobileMarkdown.rendering.test.tsx
  • mobile/src/components/mobile-markdown-android-selection.test.tsx
  • mobile/src/components/mobile-markdown-blocks.tsx
  • mobile/src/components/mobile-markdown-mermaid-routing.test.ts
  • mobile/src/components/mobile-markdown-selectable.test.tsx
  • mobile/src/components/mobile-markdown-styles.ts
  • mobile/src/components/mobile-markdown-table.test.tsx

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


Review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 7c41da03-32dc-4e4a-ab07-6abe92fc9275
Commits

Reviewing files that changed from the base of the PR and between e64f3f8 and 1d57c5a.

Files selected for processing: 5
  • mobile/src/components/MobileMarkdown.rendering.test.tsx
  • mobile/src/components/mobile-markdown-android-selection.test.tsx
  • mobile/src/components/mobile-markdown-blocks.tsx
  • mobile/src/components/mobile-markdown-mermaid-routing.test.ts
  • mobile/src/components/mobile-markdown-styles.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

{node.value}
</MarkdownText>
</View>
{node.value ? (

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor · Functional Correctness · Quick win

Keep the copy button off Mermaid fences.

When a non-empty Mermaid fence is still growing, renderCode skips the diagram branch and reaches this condition. The copy button then appears during streaming, despite the intended Mermaid exclusion. Exclude Mermaid languages from this condition.

Proposed fix
--- "a/mobile/src/components/mobile-markdown-blocks.tsx"
+++ "b/mobile/src/components/mobile-markdown-blocks.tsx"
@@ -64,7 +64,7 @@
           {node.value}
         </MarkdownText>
       </View>
-      {node.value ? (
+      {node.value && !isMobileMermaidLanguage(node.lang ?? undefined) ? (
         <MobileSourceCopyButton text={node.value} accessibilityLabel="Copy code" />
       ) : null}
     </View>
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{node.value ? (
{node.value && !isMobileMermaidLanguage(node.lang ?? undefined) ? (

@OrcaWin

OrcaWin commented Oct 27, 2026

Copy link
Copy Markdown
Collaborator

Thanks for adding per-code-block copy on mobile, @radut, and for following through on the layout and Mermaid cases. Your work is now on main through #34039, including the copy button beside each block and the compact layout from this PR.

I’m closing this one because the contribution is already included. Thank you!

@OrcaWin OrcaWin closed this Oct 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Mobile chat: no copy button on individual code blocks

3 participants