Inspect the fixed example
Construct FormData from the fixed form without submitting it. The script prints the initial entry list once. Name and note are read-only sample text; the tag choices are fixed html/css/js values. Later checkbox changes do not rerun this initial transcript.
<style>html{font-size:16px}body{margin:12px;font:1rem/1.5 system-ui,sans-serif;color:#17332d;background:#fff}p{overflow-wrap:anywhere}output{display:block;margin-block:12px;overflow-wrap:anywhere;white-space:pre-wrap}button,input{font:inherit;max-width:100%;box-sizing:border-box}button{margin:4px;padding:8px}label{display:block;margin-block:8px}button:focus-visible,input:focus-visible{outline:3px solid #23715d;outline-offset:2px}ul{padding-inline-start:24px}li{overflow-wrap:anywhere}.highlight{border:2px solid green}</style>
<form id="sample"><label>Name <input name="name" value="Ada" readonly></label><label>Read-only note <input id="note" name="note" value="Local" readonly></label><label>Disabled note <input name="disabled" value="Skip" disabled></label><label><input type="checkbox" name="tag" value="html" checked>Markup</label><label><input type="checkbox" name="tag" value="css" checked>Layout</label><label><input type="checkbox" name="other" value="js">Scripting</label></form><output id="result"></output>
<script>const result=[...new FormData(document.querySelector('#sample'))];
document.querySelector('#result').textContent=JSON.stringify(result);
console.log(JSON.stringify(result));
</script>[["name","Ada"],["note","Local"],["tag","html"],["tag","css"]]| Inspection | Supplied input or action | Result |
|---|---|---|
| name / note | Named read-only text | Both included |
| disabled / other | Disabled / unchecked | Both omitted |
| tag | html, css checked | getAll: ["html","css"] |
Follow the native mechanism
Named read-only text controls enter the form’s entry list. Disabled controls and unchecked checkboxes are skipped. Checked controls with the same name remain separate entries in control order. FormData construction is not a submission or authorization action.
Compare the material alternative
Object.fromEntries retains only the later value for a repeated name. The earlier html tag is lost although both checkbox controls were eligible.
<style>html{font-size:16px}body{margin:12px;font:1rem/1.5 system-ui,sans-serif;color:#17332d;background:#fff}p{overflow-wrap:anywhere}output{display:block;margin-block:12px;overflow-wrap:anywhere;white-space:pre-wrap}button,input{font:inherit;max-width:100%;box-sizing:border-box}button{margin:4px;padding:8px}label{display:block;margin-block:8px}button:focus-visible,input:focus-visible{outline:3px solid #23715d;outline-offset:2px}ul{padding-inline-start:24px}li{overflow-wrap:anywhere}.highlight{border:2px solid green}</style>
<form id="sample"><label>Name <input name="name" value="Ada" readonly></label><label>Read-only note <input id="note" name="note" value="Local" readonly></label><label>Disabled note <input name="disabled" value="Skip" disabled></label><label><input type="checkbox" name="tag" value="html" checked>Markup</label><label><input type="checkbox" name="tag" value="css" checked>Layout</label><label><input type="checkbox" name="other" value="js">Scripting</label></form><output id="result"></output>
<script>const entries=[...new FormData(document.querySelector('#sample'))];const result={tag:Object.fromEntries(entries).tag,allTags:new FormData(document.querySelector('#sample')).getAll('tag')};
document.querySelector('#result').textContent=JSON.stringify(result);
console.log(JSON.stringify(result));
</script>{"tag":"css","allTags":["html","css"]}Work the boundary
What happens if the read-only note is also disabled before building FormData?
Show the worked answer
The note is omitted. Read-only status does not override disabled exclusion. Name and both checked tags remain.
<style>html{font-size:16px}body{margin:12px;font:1rem/1.5 system-ui,sans-serif;color:#17332d;background:#fff}p{overflow-wrap:anywhere}output{display:block;margin-block:12px;overflow-wrap:anywhere;white-space:pre-wrap}button,input{font:inherit;max-width:100%;box-sizing:border-box}button{margin:4px;padding:8px}label{display:block;margin-block:8px}button:focus-visible,input:focus-visible{outline:3px solid #23715d;outline-offset:2px}ul{padding-inline-start:24px}li{overflow-wrap:anywhere}.highlight{border:2px solid green}</style>
<form id="sample"><label>Name <input name="name" value="Ada" readonly></label><label>Read-only note <input id="note" name="note" value="Local" readonly></label><label>Disabled note <input name="disabled" value="Skip" disabled></label><label><input type="checkbox" name="tag" value="html" checked>Markup</label><label><input type="checkbox" name="tag" value="css" checked>Layout</label><label><input type="checkbox" name="other" value="js">Scripting</label></form><output id="result"></output>
<script>document.querySelector('#note').disabled=true;const data=new FormData(document.querySelector('#sample'));const result={entries:[...data],hasNote:data.has('note'),tags:data.getAll('tag')};
document.querySelector('#result').textContent=JSON.stringify(result);
console.log(JSON.stringify(result));
</script>{"entries":[["name","Ada"],["tag","html"],["tag","css"]],"hasNote":false,"tags":["html","css"]}