Skip to content

feat: copy button on user messages, hover on message for buttons - #110

Merged
t3dotgg merged 1 commit into
mainfrom
theo/copy-on-hover
Feb 27, 2026
Merged

feat: copy button on user messages, hover on message for buttons#110
t3dotgg merged 1 commit into
mainfrom
theo/copy-on-hover

Conversation

@t3dotgg

@t3dotggt3dotgg commented Feb 27, 2026

Copy link
Copy Markdown
Member
image

Note

Add a copy button to user message bubbles and show message controls on hover in apps/web/src/components/ChatView.tsx

Introduce a memoized MessageCopyButton that writes text to the clipboard and toggles CopyIcon/CheckIcon for 2000ms, and update user message bubbles to reveal copy and revert controls on hover/focus with opacity transitions in ChatView.tsx.

📍Where to Start

Start with the MessageCopyButton component and its usage within MessagesTimeline in ChatView.tsx.

Macroscope summarized e09f859.

Summary by CodeRabbit

  • New Features
    • Added copy-to-clipboard functionality for user messages in the chat timeline. A copy button appears when hovering over messages with visual confirmation when text is successfully copied.
    • Enhanced message action button interactions and layout for improved usability.

@coderabbitai

coderabbitaiBot commented Feb 27, 2026

Copy link
Copy Markdown

Walkthrough

A MessageCopyButton component was added to ChatView.tsx that copies message text to the clipboard and displays brief visual feedback. The button is integrated into the MessagesTimeline component, appearing alongside existing message actions with hover activation and layout adjustments for consistent spacing.

Changes

Cohort / File(s)Summary
Message Copy Button Feature
apps/web/src/components/ChatView.tsx
Added MessageCopyButton component with copy-to-clipboard functionality and visual feedback. Integrated into MessagesTimeline for user messages with hover/focus group container. Added CopyIcon and CheckIcon imports from lucide-react. Minor layout adjustments for spacing consistency.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly and specifically describes the main changes: adding a copy button to user messages and implementing hover-triggered visibility for message action buttons.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch theo/copy-on-hover

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

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/web/src/components/ChatView.tsx`:
- Around line 2341-2344: handleCopy currently calls
navigator.clipboard.writeText without handling rejections and always sets
setCopied(true), and the timeout is never cleared on unmount; update handleCopy
to await or use .then/.catch on navigator.clipboard.writeText(text) and only
call setCopied(true) when the promise resolves, log or surface the error on
rejection and avoid setting copied on failure, store the timeout id in a ref
(e.g., copyTimeoutRef) and use clearTimeout(copyTimeoutRef.current) before
setting a new timeout, and add a cleanup (in a useEffect return) to clear the
timeout on unmount; reference handleCopy, navigator.clipboard.writeText,
setCopied and the timeout logic when making changes.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3a43047 and e09f859.

📒 Files selected for processing (1)
  • apps/web/src/components/ChatView.tsx

Comment on lines +2341 to +2344
const handleCopy = useCallback(() => {
void navigator.clipboard.writeText(text);
setCopied(true);
setTimeout(() => setCopied(false), 2000);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Handle clipboard API errors and clean up timeout on unmount.

navigator.clipboard.writeText can reject (permission denied, insecure context). Currently, failures are silently ignored and the user sees "copied" feedback regardless. Additionally, the timeout should be cleaned up if the component unmounts.

🛡️ Proposed fix
 const MessageCopyButton = memo(function MessageCopyButton({ text }: { text: string }) {
const [copied, setCopied] = useState(false);
const handleCopy = useCallback(() => {
- void navigator.clipboard.writeText(text);- setCopied(true);- setTimeout(() => setCopied(false), 2000);+ navigator.clipboard.writeText(text).then(+ () => setCopied(true),+ () => {+ // Optionally show error feedback or silently fail+ }+ );
}, [text]);
++ useEffect(() => {+ if (!copied) return;+ const timer = setTimeout(() => setCopied(false), 2000);+ return () => clearTimeout(timer);+ }, [copied]);
return (
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/web/src/components/ChatView.tsx` around lines 2341 - 2344, handleCopy
currently calls navigator.clipboard.writeText without handling rejections and
always sets setCopied(true), and the timeout is never cleared on unmount; update
handleCopy to await or use .then/.catch on navigator.clipboard.writeText(text)
and only call setCopied(true) when the promise resolves, log or surface the
error on rejection and avoid setting copied on failure, store the timeout id in
a ref (e.g., copyTimeoutRef) and use clearTimeout(copyTimeoutRef.current) before
setting a new timeout, and add a cleanup (in a useEffect return) to clear the
timeout on unmount; reference handleCopy, navigator.clipboard.writeText,
setCopied and the timeout logic when making changes.

@t3dotgg
t3dotgg merged commit 0b8e098 into mainFeb 27, 2026
3 checks passed
youpele52 referenced this pull request in youpele52/bigbud Jun 17, 2026
dcherrera pushed a commit to dcherrera/t3code that referenced this pull request Jul 7, 2026
NeilTheFisher pushed a commit to NeilTheFisher/t3code that referenced this pull request Aug 18, 2026
Sign up for freeto 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.

1 participant

@t3dotgg