React Form with File Upload
A file upload input is only a few lines of HTML, but production-ready file uploads require size validation, type checking, and a preview so users know their file was received correctly. The FileReader API converts a selected image file into a base64 data URL that can be displayed as a preview immediately — with no server round-trip needed.
The challenge
File uploads introduce edge cases like previews, validation, and size limits that are not covered by a simple input element.
- Reading the selected file and displaying a preview before it is uploaded anywhere
- Enforcing a file size limit without confusing the user — the error needs to be clear and appear instantly
- Accepting only certain file types reliably (the accept attribute is advisory, not enforced by browsers)
- Clearing the file input state when the user removes the selected file, since input[type=file] cannot be set to null
Working code example
Here is a complete, self-contained working example you can drop directly into any React project. It uses Tailwind CSS for styling and requires no external dependencies beyond React itself.
import { useState, useRef } from 'react';
const MAX_MB = 2;
const MAX_BYTES = MAX_MB * 1024 * 1024;
export default function ImageUpload() {
const [preview, setPreview] = useState(null);
const [fileName, setFileName] = useState('');
const [error, setError] = useState('');
const inputRef = useRef(null);
const handleFile = (e) => {
const file = e.target.files?.[0];
setError('');
setPreview(null);
setFileName('');
if (!file) return;
if (!file.type.startsWith('image/')) {
setError('Please select an image file (JPEG, PNG, GIF, WebP).');
return;
}
if (file.size > MAX_BYTES) {
setError(`File is too large. Maximum size is ${MAX_MB}MB.`);
return;
}
setFileName(file.name);
const reader = new FileReader();
reader.onload = (ev) => setPreview(ev.target.result);
reader.readAsDataURL(file);
};
const clearFile = () => {
setPreview(null);
setFileName('');
setError('');
if (inputRef.current) inputRef.current.value = '';
};
return (
<div className="max-w-sm mx-auto p-6 bg-white rounded-2xl shadow space-y-4">
<h2 className="text-xl font-bold text-gray-800">Upload Image</h2>
<label className="flex flex-col items-center justify-center w-full h-36 border-2 border-dashed border-gray-300 rounded-xl cursor-pointer hover:border-teal-400 hover:bg-teal-50 transition">
<span className="text-sm text-gray-500">Click to select an image</span>
<span className="text-xs text-gray-400 mt-1">JPEG, PNG, GIF, WebP — max {MAX_MB}MB</span>
<input ref={inputRef} type="file" accept="image/*" onChange={handleFile} className="hidden" />
</label>
{error && <p className="text-red-500 text-sm">{error}</p>}
{preview && (
<div className="relative">
<img src={preview} alt="Preview" className="w-full h-48 object-cover rounded-xl border border-gray-200" />
<div className="mt-2 flex items-center justify-between">
<span className="text-xs text-gray-500 truncate">{fileName}</span>
<button type="button" onClick={clearFile}
className="text-xs text-red-500 hover:underline">Remove</button>
</div>
</div>
)}
{preview && (
<button type="button"
className="w-full bg-teal-600 text-white font-semibold py-2 rounded-lg hover:bg-teal-700 transition">
Upload Photo
</button>
)}
</div>
);
}How ReactForm.co helps
ReactForm's visual builder handles all of the above — file upload configuration, validation rules, state management, and responsive layout — without writing a single line of code. Drag fields onto the canvas, configure their properties in the sidebar, and get production-ready React output. You can publish the form and collect responses instantly, or export the JSX to drop into your own codebase.
Build this form visuallyFrequently asked questions
How do I show a preview of a selected image before uploading it?
Use the FileReader API: create a new FileReader(), call reader.readAsDataURL(file), and set your preview state inside reader.onload. The result is a base64 data URL you can pass directly to an <img src>. This works entirely in the browser and does not require any network request.
How do I enforce a maximum file size on the client side?
Check file.size in your onChange handler before doing anything else. The size is in bytes, so multiply your megabyte limit by 1024 * 1024. Show a clear error message and return early. Note that this is client-side only — always enforce the same limit on the server because the client check can be bypassed.
How do I clear a file input field in React?
You cannot set value on a file input (browsers block it for security). Use a ref and set inputRef.current.value = "" to clear it. This resets the native input state. Then reset your preview and error state separately. Alternatively, you can change the input's key prop to unmount and remount it.
Related topics
Build this form visually — no code needed
ReactForm.co handles file upload fields, validation, conditional logic, and responsive layout automatically. Publish in minutes and collect responses for free.

