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
Set vi as the default editor in Ubuntu — a terminal opening the vim editor
How to Set vi (Vim) as the Default Editor in Ubuntu
June 8, 2026
rsync says ALL DONE but files are missing — a terminal showing ALL DONE next to an empty folder
rsync Says “ALL DONE” but Files Are Missing: How to Verify
June 8, 2026
Migrate a website to a new server with rsync — files copying from an old server to a new one over SSH
How to Migrate a Website to a New Server With rsync
June 8, 2026
Bun runtime — faster JS toolkit replacing npm in Laravel projects
How to Install Bun Runtime on Ubuntu (And Use It in a Laravel Project)
May 24, 2026
Tailscale mesh — peer-to-peer connections between devices, coordination server
How to Install Tailscale on Ubuntu (Zero-Config Mesh VPN for Self-Hosters)
May 24, 2026

You Might Also Like

JavaScript check HTTP referrer — document.referrer
Web Development

How to Check the HTTP Referrer with JavaScript

4 Min Read
Select all text in a contenteditable div on click
Web Development

How to Select All Text in a Contenteditable Div on Click

4 Min Read
Run Laravel queue workers with Supervisor
Web Development

How to Run Laravel Queue Workers in Production with Supervisor

12 Min Read
Fix 409 Conflict error in Laravel (cookies, cache, WAF)
Web Development

How I Fixed the 409 Conflict Error in Laravel (Cookie / Browser / WAF Fix)

7 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?