The essentials

Quick reference

One focused task per row. Jump to the related section for complete, working examples.

UseSyntaxExamples
Choose one file<input id="avatar" name="avatar" type="file">View examples
Hint accepted formats<input type="file" accept="image/png,image/jpeg,.webp">View examples
Choose several files<input type="file" name="attachments" multiple>View examples
Require a selection<input type="file" name="document" required>View examples
Access selected filesconst files = input.filesView examples
Inspect file metadataconst { name, size, type, lastModified } = fileView examples
Check a byte limitif (file.size > 5 * 1024 * 1024) reject(file)View examples
Read text with a promiseconst text = await file.text()View examples
Read binary with FileReaderreader.readAsArrayBuffer(file)View examples
Cancel a FileReader readreader.abort()View examples
Create a local preview URLconst url = URL.createObjectURL(file)View examples
Release a preview URLURL.revokeObjectURL(url)View examples
Submit multipart form data<form method="post" enctype="multipart/form-data">View examples
Build an upload bodyformData.append('attachment', file, file.name)View examples

A file input gives a page access only to files the user deliberately selects. The resulting File objects expose blob data plus name and modification metadata, but names, extensions, sizes, and reported MIME types are untrusted. Use browser-side checks for fast feedback, read only what the interface needs, release temporary object URLs, and repeat every upload limit and content check on the server.

Step by step

Detailed examples

01

Start with a labeled native file input

input type=file invokes a user-controlled picker and represents its selected FileList. Give it a visible label and name, add multiple only when the workflow accepts several files, and use required when an empty selection is invalid. accept is a comma-separated hint made of MIME types, broad audio/video/image groups, or dot-prefixed extensions; it helps users filter choices but does not validate the result.

One required profile image
<label for="avatar">Profile image</label>
<input id="avatar" name="avatar" type="file"
       accept="image/png,image/jpeg,.webp"
       aria-describedby="avatar-help" required>
<p id="avatar-help">PNG, JPEG, or WebP; at most 2 MB.</p>

Note: Do not hide the native input in a way that removes it from keyboard or accessibility APIs. A label can provide custom presentation while the input remains operable.

Several optional attachments
<label for="attachments">Attachments</label>
<input id="attachments" name="attachments" type="file" multiple>
Back to quick reference ↑
02

Inspect File objects and give early feedback

On input or change, input.files contains zero or more File objects. A File is an immutable Blob with name and lastModified metadata; size is measured in bytes and type is a lower-case MIME string or an empty string when unknown. Check count, size, reported type, and extension for user feedback, but consider all of them attacker-controlled and repeat authoritative content inspection on the server.

Validate count, size, and reported type
const input = document.querySelector('#avatar');
const message = document.querySelector('#avatar-message');
const allowedTypes = new Set(['image/png', 'image/jpeg', 'image/webp']);
const maxBytes = 2 * 1024 * 1024;

input.addEventListener('change', () => {
  const [file] = input.files;
  if (!file) { message.textContent = 'No file selected.'; return; }

  if (!allowedTypes.has(file.type) || file.size > maxBytes) {
    input.value = '';
    message.textContent = 'Choose a PNG, JPEG, or WebP image no larger than 2 MB.';
    return;
  }
  message.textContent = `${file.name} — ${file.size.toLocaleString()} bytes`;
});

Note: Clearing input.value is allowed; scripts cannot set it to a local filename. File.type can be empty or incorrect, so it is not a security boundary.

Normalize a FileList to an array
const selected = Array.from(input.files);
const totalBytes = selected.reduce((sum, file) => sum + file.size, 0);
Back to quick reference ↑
03

Choose the smallest appropriate read

Blob.text() and Blob.arrayBuffer() return promises and are convenient when the complete file is reasonably small. FileReader offers event-driven text, data-URL, and ArrayBuffer reads plus progress and abort events. Both styles can allocate memory proportional to the data read, so enforce size limits before reading large files; for incremental processing, consume file.stream() instead.

Read a small UTF-8 text file
async function showText(file, output) {
  if (file.size > 256 * 1024) throw new Error('Text file is too large to preview');
  const text = await file.text();
  output.textContent = text.slice(0, 10_000);
}

Note: Blob.text() always decodes as UTF-8. Use a TextDecoder with an ArrayBuffer when the workflow explicitly supports another encoding.

Read binary data with FileReader events
function readBytes(file, signal) {
  return new Promise((resolve, reject) => {
    if (signal?.aborted) {
      reject(new DOMException('Read aborted', 'AbortError'));
      return;
    }
    const reader = new FileReader();
    const abort = () => reader.readyState === FileReader.LOADING && reader.abort();
    signal?.addEventListener('abort', abort, { once: true });
    reader.addEventListener('load', () => resolve(reader.result));
    reader.addEventListener('error', () => reject(reader.error));
    reader.addEventListener('abort', () => reject(new DOMException('Read aborted', 'AbortError')));
    reader.addEventListener('loadend', () => signal?.removeEventListener('abort', abort));
    reader.readAsArrayBuffer(file);
  });
}
Back to quick reference ↑
04

Preview blobs without base64 expansion

URL.createObjectURL(file) creates a blob URL that can be assigned to src or href without first copying the whole file into a base64 data URL. Each call creates an entry that can live for the document's lifetime, so retain the string and revoke it when replacing or removing the preview. Revoke only after consumers have started or finished loading it; dereferencing a revoked URL produces a network error.

Replace an image preview and release the old URL
const preview = document.querySelector('#avatar-preview');
let previewURL;

function showImage(file) {
  if (previewURL) URL.revokeObjectURL(previewURL);
  previewURL = URL.createObjectURL(file);
  preview.src = previewURL;
  preview.hidden = false;
}

window.addEventListener('pagehide', () => {
  if (previewURL) URL.revokeObjectURL(previewURL);
});

Note: Decode errors still need handling. Do not treat successful image rendering as proof that a later upload is safe to store or serve.

Back to quick reference ↑
05

Upload with multipart data and verify on the server

A native form that uploads files needs method=post and enctype=multipart/form-data. FormData provides the same multipart shape to fetch; let the browser generate its Content-Type boundary instead of setting that header manually. The server must independently enforce authentication, authorization, field names, count, byte limits, actual content type, filename policy, storage location, and malware or decompression safeguards appropriate to the application.

Progressive multipart upload form
<form action="/profile/photo" method="post" enctype="multipart/form-data">
  <label for="photo">Profile photo</label>
  <input id="photo" name="photo" type="file" accept="image/png,image/jpeg" required>
  <button type="submit">Upload photo</button>
</form>
Send selected files with fetch
const data = new FormData();
for (const file of input.files) data.append('attachments', file, file.name);

const response = await fetch('/api/attachments', {
  method: 'POST',
  body: data,
  credentials: 'same-origin'
});
if (!response.ok) throw new Error(`Upload failed: ${response.status}`);

Note: Do not set Content-Type when sending FormData; the browser adds multipart/form-data with the required boundary. Client validation improves UX but never replaces server validation.

Back to quick reference ↑

Local code tester

Try a local image preview

Choose a local PNG, JPEG, or WebP image up to 2 MB. The sandbox previews it with a revocable object URL and never uploads it.

Runs in your browser
Preview

Sources and further reading

References

Authoritative documentation used to verify and expand this cheat sheet.

  1. WHATWGHTML Standard: File Upload state (type=file)html.spec.whatwg.org
  2. World Wide Web ConsortiumFile APIw3.org
  3. WHATWGHTML Standard: Form submission attributeshtml.spec.whatwg.org
  4. MDN Web DocsUsing files from web applicationsdeveloper.mozilla.org

Help us improve

Found a typo or missing example?

Tell us what would make this cheat sheet clearer, more complete, or more useful.

Share feedback