feat: support pasting images from clipboard in chat input#93
Conversation
Adds an onPaste handler to the textarea that detects image files in clipboard data and appends them as File objects named "Pasted image #". Pasted images flow through the same upload pipeline as file-picker attachments. https://claude.ai/code/session_016m1gpCeYMUSPFCJygVn2aj
There was a problem hiding this comment.
Code Review
This pull request adds support for pasting images directly into the ChatInput component's textarea. The reviewer identified three critical issues with the paste handler: a potential runtime crash from using a non-null assertion on item.getAsFile(), missing file extensions on the created files, and the lack of e.preventDefault() which can trigger unwanted default browser paste behavior. A refactored code snippet was suggested to address these concerns.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| (e: React.ClipboardEvent<HTMLTextAreaElement>) => { | ||
| const imageFiles = Array.from(e.clipboardData.items) | ||
| .filter((item) => item.kind === 'file' && item.type.startsWith('image/')) | ||
| .map((item) => { | ||
| const file = item.getAsFile()! | ||
| pasteCounter.current += 1 | ||
| return new File([file], `Pasted image ${pasteCounter.current}`, { | ||
| type: file.type, | ||
| }) | ||
| }) | ||
| if (imageFiles.length > 0) { | ||
| setFiles((prev) => [...prev, ...imageFiles]) | ||
| } | ||
| }, |
There was a problem hiding this comment.
There are three issues with the current paste handler implementation:
- Potential Null Pointer / Crash:
item.getAsFile()can returnnull. Using the non-null assertion operator (!) is unsafe and can lead to runtime errors if the file cannot be retrieved. - Missing File Extension: Naming the file
Pasted image Xwithout an extension (e.g.,.pngor.jpg) can cause issues with backend upload pipelines or APIs that rely on file extensions to determine the file type. - Unwanted Default Paste Behavior: If
e.preventDefault()is not called when an image is pasted, the browser may also trigger its default paste behavior, which can insert unwanted text/HTML representations of the image into the textarea.
We can resolve these issues by safely retrieving the file, extracting the extension from the MIME type, and calling e.preventDefault() when images are successfully processed.
(e: React.ClipboardEvent<HTMLTextAreaElement>) => {
const imageFiles: File[] = []
for (const item of Array.from(e.clipboardData.items)) {
if (item.kind === 'file' && item.type.startsWith('image/')) {
const file = item.getAsFile()
if (file) {
pasteCounter.current += 1
const ext = file.type.split('/')[1] || 'png'
imageFiles.push(
new File([file], `Pasted image ${pasteCounter.current}.${ext}`, {
type: file.type,
})
)
}
}
}
if (imageFiles.length > 0) {
setFiles((prev) => [...prev, ...imageFiles])
e.preventDefault()
}
},
…aste - Replace non-null assertion with null guard using flatMap/for loop - Derive file extension from MIME type (e.g. image/png → .png) - Call e.preventDefault() only when images are consumed to prevent browsers from inserting garbage text representations into the textarea https://claude.ai/code/session_016m1gpCeYMUSPFCJygVn2aj
$(cat <<'EOF'
Summary
onPastehandler to the chat textarea inChatInput.tsxclipboardData.items) and appends them asFileobjectsSaveFilesAsArtifactsPlugin→ artifact store)Test plan
https://claude.ai/code/session_016m1gpCeYMUSPFCJygVn2aj
EOF
)
Generated by Claude Code