Skip to content
Carl Victor Fontanos
Carl Victor Fontanos

Carl Victor Fontanos

Software Engineer

I build web applications and share what I learn along the way.

© 2026

Serialize an Entire Form in One Line with FormData

C
Carlo Fontanos
· 2 min read

The amount of code I've seen (and written) that collects form values field by field - getElementById, .value, repeat times twenty - is embarrassing in hindsight. The browser reads whole forms in one constructor call.

form.addEventListener('submit', async (e) => {
    e.preventDefault();
    const data = new FormData(form);   // every named field, including files

    await fetch('/api/save', { method: 'POST', body: data });
});

Passing FormData as a fetch body sets the multipart Content-Type (with boundary) automatically. Do not set the header yourself - a hand-written multipart header without the boundary is the classic way to break uploads.

Want JSON instead? One more line

const json = Object.fromEntries(new FormData(form));
// { title: "Hello", category: "css", published: "1" }

Caveat that bites people: fromEntries keeps only the last value per key. Checkbox groups and multi-selects need getAll():

const data = new FormData(form);
const payload = {
    ...Object.fromEntries(data),
    tags: data.getAll('tags[]'),   // all checked values, not just the last
};

Things FormData knows that you'd get wrong

  • Unchecked checkboxes are absent (matching classic form submission), checked ones send their value.
  • Disabled fields are excluded; readonly fields are included. This mirrors real browser submits exactly.
  • File inputs come through as File objects, ready to upload - no special handling.
  • Fields outside the form tag but linked with the form attribute (<input form="myform">) are picked up too. That attribute is its own little hidden gem for layouts where the submit button lives in a sticky footer.

Building FormData by hand

It's also the cleanest way to construct multipart payloads programmatically - I use this for pasted screenshot uploads:

const body = new FormData();
body.append('file', blob, 'screenshot.png');
body.append('folder', currentFolder);

The submitter detail almost nobody knows

Forms with multiple submit buttons (Save vs Save & Publish) traditionally lose the clicked button's value with FormData. The fix landed in all browsers: pass the submitter from the event.

const data = new FormData(form, e.submitter);   // includes the clicked button's name/value

On the receiving end, PHP sees a FormData POST identically to a normal form submit: $_POST and $_FILES, no JSON decoding required. Sometimes the boring old formats are the smoothest path.

C
Written by Carlo Fontanos

Full-stack web developer sharing practical tutorials and building tools that ship.

Got something on your mind?

My inbox is open - no forms disappearing into the void here.

  • Just say hello Found a tutorial useful? Spotted a mistake? Tell me.
  • Hire me for a project Have something custom in mind? Let's talk scope and timelines.
  • Product support Bought something here? I'll help you get it running.

I usually reply within 1-2 business days.

Message sent!

Your details are only used to reply to you.

Keep reading