feat(ui): add copy button to multi-line code blocks#38261
feat(ui): add copy button to multi-line code blocks#38261DevendraNathLimbu wants to merge 3 commits into
Conversation
|
Looks like this PR is not ready to merge, because of the following issues:
Please fix the issues and try again If you have any trouble, please check the PR guidelines |
|
WalkthroughA copy button is added to the CodeBlock component with clipboard functionality. The button appears in an absolute-positioned wrapper above the code block and toggles between "Copy" and "Copied" states when clicked, providing visual feedback to users. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@packages/gazzodown/src/code/CodeBlock.tsx`:
- Line 96: The <pre role='region'> in the CodeBlock component lacks an
accessible name; either remove the role or give the region a name by adding
aria-label or aria-labelledby on the same element (or on a wrapping element) so
the region is properly announced; locate the <pre role='region'> in
CodeBlock.tsx (inside the CodeBlock component) and add a meaningful aria-label
(or reference an id'd caption/label via aria-labelledby) or simply drop
role='region' if no named region is needed.
- Around line 59-67: The handleCopy function should guard for clipboard
availability and ensure timers are cleared to avoid accumulating stale timeouts
and setState-after-unmount warnings: update handleCopy to check
navigator.clipboard and return early if unavailable, store the timeout id in a
ref (e.g., copyTimeoutRef) and call clearTimeout before creating a new timer,
and add a useEffect cleanup that clears the timeout and flips an isMounted ref
so you don't call setCopied on an unmounted component; reference the handleCopy
function, setCopied state, and use a copyTimeoutRef/isMountedRef for locating
where to add these changes.
| const handleCopy = async () => { | ||
| try { | ||
| await navigator.clipboard.writeText(code); | ||
| setCopied(true); | ||
| setTimeout(() => setCopied(false), 1500); | ||
| } catch (e) { | ||
| console.error('Copy failed', e); | ||
| } | ||
| }; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n packages/gazzodown/src/code/CodeBlock.tsxRepository: RocketChat/Rocket.Chat
Length of output: 3339
Clear copy timers and guard clipboard availability.
Rapid clicks can accumulate multiple stale timers without cleanup, and unmounting while a timer is pending causes setState warnings. Additionally, clipboard API is unavailable in some contexts (SSR, non-HTTPS, older browsers).
🛠️ Proposed fix
-import { Fragment, useContext, useLayoutEffect, useMemo, useRef, useState } from 'react';
+import { Fragment, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
const CodeBlock = ({ lines = [], language }: CodeBlockProps): ReactElement => {
const ref = useRef<HTMLElement>(null);
const [copied, setCopied] = useState(false);
+ const copyTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const handleCopy = async () => {
+ if (typeof navigator === 'undefined' || !navigator.clipboard) {
+ return;
+ }
try {
await navigator.clipboard.writeText(code);
setCopied(true);
- setTimeout(() => setCopied(false), 1500);
+ if (copyTimeoutRef.current) {
+ clearTimeout(copyTimeoutRef.current);
+ }
+ copyTimeoutRef.current = setTimeout(() => setCopied(false), 1500);
} catch (e) {
console.error('Copy failed', e);
}
};
+
+ useEffect(() => {
+ return () => {
+ if (copyTimeoutRef.current) {
+ clearTimeout(copyTimeoutRef.current);
+ }
+ };
+ }, []);🤖 Prompt for AI Agents
In `@packages/gazzodown/src/code/CodeBlock.tsx` around lines 59 - 67, The
handleCopy function should guard for clipboard availability and ensure timers
are cleared to avoid accumulating stale timeouts and setState-after-unmount
warnings: update handleCopy to check navigator.clipboard and return early if
unavailable, store the timeout id in a ref (e.g., copyTimeoutRef) and call
clearTimeout before creating a new timer, and add a useEffect cleanup that
clears the timeout and flips an isMounted ref so you don't call setCopied on an
unmounted component; reference the handleCopy function, setCopied state, and use
a copyTimeoutRef/isMountedRef for locating where to add these changes.
| {copied ? 'Copied' : 'Copy'} | ||
| </button> | ||
|
|
||
| <pre role='region'> |
There was a problem hiding this comment.
Add an accessible name for the region (or drop the role).
role="region" requires an accessible name to avoid a11y violations.
🛠️ Proposed fix
- <pre role='region'>
+ <pre role='region' aria-label='Code block'>📝 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.
| <pre role='region'> | |
| <pre role='region' aria-label='Code block'> |
🤖 Prompt for AI Agents
In `@packages/gazzodown/src/code/CodeBlock.tsx` at line 96, The <pre
role='region'> in the CodeBlock component lacks an accessible name; either
remove the role or give the region a name by adding aria-label or
aria-labelledby on the same element (or on a wrapping element) so the region is
properly announced; locate the <pre role='region'> in CodeBlock.tsx (inside the
CodeBlock component) and add a meaningful aria-label (or reference an id'd
caption/label via aria-labelledby) or simply drop role='region' if no named
region is needed.
|
Hi maintainers 👋 |
Summary
Adds a copy button to Multi-line code blocks in messages, allowing users to copy code with a single click.
Details
Motivation
Improves developer experience during technical discussions and code reviews.
Screenshots
Before:

After:

Related issue
Closes #38260
Summary by CodeRabbit
Release Notes
New Features
✏️ Tip: You can customize this high-level summary in your review settings.