Skip to content
Astera Technology

Inspect which local form controls enter FormData

Inspect the initial local entry list, including repeated names and omitted controls.

Download complete case notes and answer keys ↓

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.

Complete body and fixed script
<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>
Exact console output
[["name","Ada"],["note","Local"],["tag","html"],["tag","css"]]
Inputs and native results
InspectionSupplied input or actionResult
name / noteNamed read-only textBoth included
disabled / otherDisabled / uncheckedBoth omitted
taghtml, css checkedgetAll: ["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.

Fresh counterexample source
<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>
Counterexample output
{"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.

Fresh boundary source
<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>
Boundary output
{"entries":[["name","Ada"],["tag","html"],["tag","css"]],"hasNote":false,"tags":["html","css"]}

Original example files