How to handle pasting images to inputs in React

Just a guy who loves to write code and watch anime.
Search for a command to run...

Just a guy who loves to write code and watch anime.
Thanks for sharing!
Qualities that make outstanding builders.

Bipedal vs quadrupedal: how many legs This is about the number of legs the creature walks on. Bipedal. Two legs. Humans, ostriches, T-rex, kangaroos, most fantasy humanoids. Quadrupedal. Four legs. Do

Intro You hear "lerp" and "smoothstep" everywhere in game dev. They sound like math jargon. They're not. Both are small tools that do the same job: smoothly move from one value to another. The problem

What is Kinematics Kinematics is the math field. It's the study of how things move without worrying about forces (which would be dynamics). FK and IK are the two branches: forward kinematics and inver

Intro Textures are usually the biggest cost in a 3D scene. Memory, bandwidth, and load time all get eaten by them. Resizing them is the obvious lever. There's more. This post is about the less obvious

When a user pastes content with Ctrl+V or Command+V, React fires a ClipboardEvent. This event contains a clipboardData property that gives you access to everything that was copied.
The clipboardData object has these main properties:
items: A collection of everything in the clipboard
files: Any files present in the clipboard
types: Format strings like "text/plain" or "image/png"
Each item in the clipboard has:
A kind property: Either "string" or "file"
A type property: The MIME type such as "image/png" or "text/plain"
This example handles multiple image pastes and shows file information:
import React, { useState, useEffect, useRef } from "react";
interface PastedFile {
url: string;
name: string;
type: string;
size: number;
file: File;
}
const ImagePasteInput: React.FC = () => {
const [pastedFiles, setPastedFiles] = useState<PastedFile[]>([]);
const [inputValue, setInputValue] = useState("");
const inputRef = useRef<HTMLInputElement>(null);
const containerRef = useRef<HTMLDivElement>(null);
// Set up paste event listener on the document
useEffect(() => {
const handlePaste = (event: ClipboardEvent) => {
// Check if our input element is focused
if (document.activeElement !== inputRef.current) return;
const items = event.clipboardData?.items;
if (!items) return;
// Process image files
const newFiles: PastedFile[] = [];
Array.from(items).forEach((item) => {
if (item.kind === "file" && item.type.startsWith("image/")) {
const file = item.getAsFile();
if (file) {
newFiles.push({
url: URL.createObjectURL(file),
name: file.name || `pasted-image-${Date.now()}.png`,
type: file.type,
size: file.size,
file: file,
});
}
}
});
if (newFiles.length > 0) {
setPastedFiles((prev) => [...prev, ...newFiles]);
event.preventDefault(); // Prevent pasting text into input
}
};
document.addEventListener("paste", handlePaste);
return () => {
document.removeEventListener("paste", handlePaste);
};
}, []);
// Clean up object URLs on unmount
useEffect(() => {
return () => {
pastedFiles.forEach((file) => URL.revokeObjectURL(file.url));
};
}, [pastedFiles]);
const handleRemoveFile = (index: number) => {
setPastedFiles((prev) => {
const newFiles = [...prev];
URL.revokeObjectURL(newFiles[index].url);
newFiles.splice(index, 1);
return newFiles;
});
};
const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setInputValue(event.target.value);
};
const handleUpload = () => {
// Example function to handle the upload of pasted files
console.log(
"Files to upload:",
pastedFiles.map((file) => file.file)
);
// Here you would typically send these files to your server
};
return (
<div ref={containerRef}>
<div style={{ marginBottom: "20px" }}>
<label htmlFor="pasteInput">
Paste images here (click and press Ctrl+V):
</label>
<input
ref={inputRef}
id="pasteInput"
type="text"
value={inputValue}
onChange={handleInputChange}
placeholder="Click here and paste images with Ctrl+V"
style={{
display: "block",
width: "100%",
padding: "8px",
border: "1px solid #ccc",
borderRadius: "4px",
marginTop: "5px",
}}
/>
</div>
{pastedFiles.length > 0 && (
<div>
<h3>Pasted Images:</h3>
<div style={{ display: "flex", flexWrap: "wrap", gap: "10px" }}>
{pastedFiles.map((file, index) => (
<div
key={index}
style={{
border: "1px solid #eee",
padding: "10px",
borderRadius: "4px",
}}
>
<img
src={file.url}
alt={file.name}
style={{ maxWidth: "200px", maxHeight: "200px" }}
/>
<div>Type: {file.type}</div>
<div>Size: {Math.round(file.size / 1024)} KB</div>
<button
onClick={() => handleRemoveFile(index)}
style={{ marginTop: "5px", padding: "4px 8px" }}
>
Remove
</button>
</div>
))}
</div>
<button
onClick={handleUpload}
style={{
marginTop: "20px",
padding: "8px 16px",
backgroundColor: "#4285f4",
color: "white",
border: "none",
borderRadius: "4px",
cursor: "pointer",
}}
>
Upload Images
</button>
</div>
)}
</div>
);
};
export default ImagePasteInput;
The clipboard can contain different types of content:
Plain text
Rich text or HTML
Images from screenshots or copied content
Files from explorer/finder
Mixed content with multiple formats
When someone pastes an image:
It appears as a file-like object in the clipboard
It has a MIME type like "image/png" or "image/jpeg"
You use item.getAsFile() to get a File object
You can create an object URL to display it
Common clipboard scenarios include:
Screenshots creating "image/png" items
Web images often creating multiple clipboard items
Images from editors coming with their appropriate MIME type