React File Upload: Complete Implementation Guide with Source Code Examples
React handles file uploads using the native HTML <input type="file"> element combined with the onChange synthetic event and browser APIs such as FileReader and FormData, rather than providing a dedicated upload component.
The facebook/react repository demonstrates that react file upload functionality relies on standard web patterns managed through React state. This approach gives you full control over file validation, progress tracking, and server transmission while keeping the UI synchronized with your component's state.
Core Architecture of React File Upload
React treats file inputs as uncontrolled components because the browser maintains the FileList internally. When a user selects a file, the browser creates File objects that you access through the synthetic onChange event. According to the source code in fixtures/flight/src/Form.js, the pattern involves attaching an onChange handler to read event.target.files and updating React state to drive UI changes.
Step-by-Step Implementation
Rendering the File Input
Create a standard file input element. React renders this as a standard DOM node, giving you access to the browser's native file picker dialog.
<input type="file" name="file" onChange={handleChange} />
Capturing File Selection with onChange
The onChange event provides access to the selected files through event.target.files, which returns a FileList object. In packages/react-devtools-shared/src/devtools/views/Profiler/ProfilingImportExportButtons.js, the React team uses this pattern to trigger file processing.
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file) return;
// Process file here
};
Reading Files with FileReader
For client-side processing, instantiate FileReader to read the file contents. The React DevTools implementation creates a reader instance, sets the onload callback, and calls readAsText() or readAsDataURL() depending on the use case.
const reader = new FileReader();
reader.onload = () => {
setPreview(reader.result as string);
};
reader.readAsDataURL(file);
Uploading to Server
To transmit files to a backend, use FormData paired with fetch or XMLHttpRequest. Append the file to a FormData instance and send it with the appropriate Content-Type header (omitted when using FormData so the browser sets the multipart boundary automatically).
const formData = new FormData();
formData.append('file', file);
await fetch('/api/upload', {
method: 'POST',
body: formData,
});
React Source Code Examples
The facebook/react repository contains several canonical implementations that demonstrate file upload patterns:
Form.js Fixture
Located at fixtures/flight/src/Form.js, this file provides a minimal demonstration of a form containing <input type="file">. It shows how to structure the onChange handler and access the file list from the event target.
ProfilingImportExportButtons.js
The packages/react-devtools-shared/src/devtools/views/Profiler/ProfilingImportExportButtons.js file implements a hidden file input pattern. The component programmatically clicks a hidden input to open the file picker, then uses FileReader to read the selected JSON data as text. This demonstrates the complete lifecycle: triggering the input, reading the file, and dispatching the result to React state.
ReactServerStreamConfigBrowser.js
In packages/react-server/src/ReactServerStreamConfigBrowser.js, the React team uses FileReader to consume blob data when streaming to the browser. While this handles server-side streaming, it shows the canonical pattern for reading file blobs that applies to client-side uploads.
Complete Working Example
This component combines file preview, client-side reading, and server upload, mirroring the patterns found in the React source code:
import React, { useState } from 'react';
export default function FileUpload() {
const [preview, setPreview] = useState<string | null>(null);
const [status, setStatus] = useState<'idle' | 'uploading' | 'done'>('idle');
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file) return;
// Client-side preview with FileReader
const reader = new FileReader();
reader.onload = () => setPreview(reader.result as string);
reader.readAsDataURL(file);
};
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const input = e.currentTarget.elements.namedItem('file') as HTMLInputElement;
const file = input.files?.[0];
if (!file) return;
setStatus('uploading');
const formData = new FormData();
formData.append('file', file);
await fetch('/api/upload', {
method: 'POST',
body: formData,
});
setStatus('done');
};
return (
<form onSubmit={handleSubmit}>
<input type="file" name="file" onChange={handleChange} />
{preview && (
<img src={preview} alt="Preview" style={{ maxWidth: '200px' }} />
)}
<button type="submit" disabled={status === 'uploading'}>
{status === 'uploading' ? 'Uploading…' : 'Upload'}
</button>
</form>
);
}
Summary
- React has no dedicated file upload component—it uses the standard HTML
<input type="file">element managed through synthetic events. - Access files via
event.target.filesin youronChangehandler to obtain theFileListcontainingFileobjects. - Use
FileReaderfor client-side processing such as generating image previews or parsing text content before uploading. - Send files using
FormDatacombined withfetchorXMLHttpRequestto transmit binary data to your server endpoint. - Study
ProfilingImportExportButtons.jsin the React DevTools source for a production-ready implementation of file reading and state management.
Frequently Asked Questions
Does React provide a built-in file upload component?
No—React relies on the browser's native <input type="file"> element. The facebook/react repository demonstrates this pattern in fixtures/flight/src/Form.js, where standard form inputs handle file selection through the synthetic onChange event system.
How do I access the selected file in my React component?
Access the file through the files property on the event target: event.target.files, which returns a FileList object. For single file uploads, use event.target.files[0] to obtain the File instance, as implemented in packages/react-devtools-shared/src/devtools/views/Profiler/ProfilingImportExportButtons.js.
Can I upload multiple files at once?
Yes—set the multiple attribute on the input element: <input type="file" multiple onChange={handleChange} />. The event.target.files property will contain a FileList with all selected files, which you can iterate through for batch processing or uploading.
How do I show an image preview before uploading?
Create a FileReader instance in your onChange handler, call readAsDataURL(file) to convert the file to a base64 string, and store the result in React state. Set this state value as the src attribute of an <img> tag, as shown in the ReactServerStreamConfigBrowser.js implementation pattern.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s https://instagit.com/install.md