How7o
  • Home
  • Tools
  • Prank Screens
  • Learn
  • Blog
  • Contact
Reading: How to Upload Files via Ajax with jQuery
Share
How7oHow7o
Font ResizerAa
  • OS
Search
  • Home
  • Tools
  • Prank Screens
  • Learn
  • Blog
  • Contact
Follow US
© 2024–2026 How7o. All rights reserved.
How7o > Free Laravel, PHP, WordPress & Server Tutorials > Web Development > How to Upload Files via Ajax with jQuery
Web Development

How to Upload Files via Ajax with jQuery

how7o
By how7o
Last updated: May 23, 2026
4 Min Read
Upload files via Ajax with jQuery using FormData
SHARE

To upload image (or any) files via Ajax with jQuery, wrap the form in new FormData(this) and pass that to $.ajax with contentType: false and processData: false. The .serialize() approach silently drops file inputs — FormData is what carries multipart payloads.

Contents
  • The fix — use FormData
  • Server side (PHP)
  • Show upload progress
  • Vanilla fetch alternative
  • Frequently asked questions
  • Related guides
  • References

Last verified: 2026-05-17 with jQuery 3.7. Originally published 2022-09-21, rewritten and updated 2026-05-17.

The fix — use FormData

<form id="user-signup-form" enctype="multipart/form-data" action="/upload" method="post">
    <input type="text"     name="username">
    <input type="email"    name="email">
    <input type="password" name="password">
    <input type="file"     name="profile_picture" accept="image/*">
    <button type="submit">Register</button>
</form>

<script>
$('#user-signup-form').on('submit', function (e) {
    e.preventDefault();

    const formData = new FormData(this);

    $.ajax({
        type:        'POST',
        url:         $(this).attr('action'),
        data:        formData,
        cache:       false,
        contentType: false,
        processData: false,
    })
    .done(function (data) {
        console.log('Uploaded:', data);
    })
    .fail(function (xhr) {
        console.error('Upload failed:', xhr.statusText);
    });
});
</script>

new FormData(this) walks the form and grabs every field, including the file. contentType: false lets the browser set the multipart boundary; processData: false stops jQuery from URL-encoding the binary data.

jQuery Ajax file upload — FormData, contentType/processData false, upload progress, fetch alternative

Server side (PHP)

<?php
// /upload — receives the multipart POST
if (isset($_FILES['profile_picture'])) {
    $file = $_FILES['profile_picture'];
    if ($file['error'] === UPLOAD_ERR_OK) {
        move_uploaded_file($file['tmp_name'], 'uploads/' . basename($file['name']));
        echo json_encode(['ok' => true]);
        exit;
    }
}
http_response_code(400);
echo json_encode(['ok' => false]);

Show upload progress

$.ajax({
    type:        'POST',
    url:         '/upload',
    data:        formData,
    cache:       false,
    contentType: false,
    processData: false,
    xhr: function () {
        const xhr = new window.XMLHttpRequest();
        xhr.upload.addEventListener('progress', function (e) {
            if (e.lengthComputable) {
                const pct = Math.round((e.loaded / e.total) * 100);
                $('#progress').text(pct + '%');
            }
        });
        return xhr;
    },
});

Vanilla fetch alternative

document.getElementById('user-signup-form').addEventListener('submit', async (e) => {
    e.preventDefault();

    const res = await fetch(e.target.action, {
        method: 'POST',
        body:   new FormData(e.target),
    });

    const data = await res.json();
    console.log(data);
});

fetch with a FormData body is one line — no contentType/processData gymnastics needed. For new code without jQuery, this is the cleanest form.

Frequently asked questions

Why does $(form).serialize() lose file inputs?

.serialize() only handles successful form controls that have string values — text, select, checkbox, etc. <input type="file"> values are File objects, not strings. FormData(form) walks the form and grabs every field including files, then jQuery’s $.ajax sends it as a multipart request the same way a non-Ajax submit would.

Why contentType: false and processData: false?

contentType: false tells jQuery not to set the Content-Type header — the browser sets it to multipart/form-data; boundary=... with a generated boundary string. processData: false tells jQuery not to URL-encode the data (it would default to application/x-www-form-urlencoded, which can’t carry binary file content). Both are required for file uploads.

How do I show upload progress?

Override the XHR via xhr: xhr: function () { const x = new window.XMLHttpRequest(); x.upload.addEventListener('progress', e => { if (e.lengthComputable) console.log(e.loaded / e.total); }); return x; }. The progress event fires while bytes are uploading; the percentage is loaded / total.

Should I bother with jQuery or use fetch?

For new code, fetch: fetch(url, { method: 'POST', body: new FormData(form) }) is one line and doesn’t need the contentType/processData dance — fetch respects FormData natively. Use jQuery only when you’re already in a jQuery codebase.

Related guides

  • How to Upload Only Image Files Using PHP
  • How to Open a File Dialog When Clicking a Button
  • How to Convert an Image to a Base64 String in JavaScript

References

jQuery $.ajax: api.jquery.com/jquery.ajax. MDN FormData: developer.mozilla.org/en-US/docs/Web/API/FormData. MDN XMLHttpRequest.upload: developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/upload.

TAGGED:ajaxformsJavaScriptjQuery

Sign Up For Daily Newsletter

Be keep up! Get the latest breaking news delivered straight to your inbox.
[mc4wp_form]
By signing up, you agree to our Terms of Use and acknowledge the data practices in our Privacy Policy. You may unsubscribe at any time.
Share This Article
Facebook Copy Link Print
Previous Article Disable binary logging in MySQL or MariaDB How to Disable Binary Logging in MySQL or MariaDB
Next Article Securely upload only image files in PHP How to Upload Only Image Files Using PHP
Leave a Comment

Leave a Reply Cancel reply

You must be logged in to post a comment.

FacebookLike
XFollow
PinterestPin
InstagramFollow
Most Popular
Run Laravel queue workers with Supervisor
How to Run Laravel Queue Workers in Production with Supervisor
May 23, 2026
Nginx as a reverse proxy for a Node.js app on Ubuntu
How to Set Up Nginx as a Reverse Proxy for Node.js on Ubuntu
May 23, 2026
Install and configure Redis on Ubuntu for Laravel and WordPress
How to Install and Configure Redis on Ubuntu (for Laravel & WordPress)
May 23, 2026
Harden a fresh Ubuntu VPS with UFW, Fail2Ban, and SSH key auth
How to Harden a Fresh Ubuntu VPS: UFW + Fail2Ban + SSH Key Auth
May 23, 2026
Set up Let's Encrypt SSL with Certbot on Ubuntu
How to Set Up Let’s Encrypt SSL with Certbot on Ubuntu (Apache & Nginx)
May 23, 2026

You Might Also Like

How I Fixed Composer Dependency Errors
Web Development

How I Fixed Composer Dependency Errors Using the –ignore-platform-reqs Flag (Step-by-Step Guide)

7 Min Read
Laravel migration column types cheat sheet
Web Development

Laravel Migration Column Types — Cheat Sheet

5 Min Read
Laravel Eloquent count rows — Post::count query snippet with aggregate bar chart icon
Web Development

How to Count Rows in Laravel Eloquent Efficiently

6 Min Read
Laravel DataTables custom column search — filterColumn callback handles the search SQL
Web Development

How to Search Custom or Composite Columns in Laravel DataTables

8 Min Read
How7o

We provide tips, tricks, and advice for improving websites and doing better search.

Tools

  • Age Calculator
  • Word Counter
  • Image Upscaler
  • Password Generator
  • QR Code Generator
  • See all tools→

Pranks

  • Fake Blue Screen Prank
  • Hacker Typer
  • Fake iMessage Generator
  • Windows XP Crash Prank
  • Windows 11 Update Prank
  • See all prank screens →

Company

  • About Us
  • Blog
  • Contact
  • Privacy Policy
  • Terms of Service
  • Sitemap
© 2024–2026 How7o. All rights reserved.
Welcome Back!

Sign in to your account

Username or Email Address
Password

Lost your password?