Form properties & elements
Access forms and form controls with document.forms, form.elements, input values, checkboxes, radios, selects, and options.
- 01Find the controls in a formGet a form with
document.forms, then find each control by name withform.elements. - 02Read what each control holdsPick the right property:
.valuefor text,.valueAsNumberfor numbers,.checkedfor checkboxes, and the group's.valuefor radio buttons. - 03Work with choicesRead and change checkboxes, radio buttons, menus, and their options, including menus where you can choose more than one.
Reading a form with JavaScript
A form is the part of a page where people type or choose things. A login box, a checkout page, and a search box are all forms. Each thing in a form that you can type in or click is called a control. Common controls are:
- Text boxes and number boxes, made with
<input>. - Checkboxes and radio buttons, also made with
<input>. - Drop-down menus, made with
<select>. - Big boxes for many lines of text, made with
<textarea>. - Buttons, made with
<button>.
JavaScript reads a form in three steps:
- Get the form.
- Use
form.elementsto find one control by its name. - Read the property that fits that kind of control.
Which property you read depends on the control:
- Text boxes and number boxes:
value. - Checkboxes:
checked. - A group of radio buttons: one shared
valuefor the whole group. - Menus:
value,selectedIndex,options, andselectedOptions.
Picture a clipboard at a front desk. The sheet has blanks with labels, like Email and Plan. A small index on the side says where each blank is, so you can jump straight to Email.
- In real life: The whole clipboard
- In JavaScript: The
formelement - In real life: A labeled blank, like Email
- In JavaScript: A control with a name, like
name="email" - In real life: The clipboard's index
- In JavaScript:
form.elements - In real life: Looking up the Email blank
- In JavaScript:
form.elements.emailorform.elements.namedItem("email")
For this lesson, you should know DOM objects and their properties. Some values look like numbers but are really text; the Type conversion lesson helps with those. The next lesson, Form events, shows how to react when someone changes a field. This lesson is only about reading the fields.
form.elements: the list of controls
INTERACTIVEFirst, get the form. document.forms is a list of every form on the page. You can pick a form in two ways:
- By position:
document.forms[0]is the first form. - By its
nameattribute:document.forms.signupis the form withname="signup".
Once you have the form, form.elements is the list of controls inside that form. You can pick a control by its name, like form.elements.email. You can also pick it by position, like form.elements[0]. form.elements.namedItem("email") does the same as form.elements.email.
const form = document.forms.signup;
const email = form.elements.email;
console.log(form.name);
console.log(email.value);Line 1 gets the form named signup. Line 2 gets the control named email from that form's own list, so a control in another form can't get mixed in. Line 3 prints the form's name, signup. Line 4 prints what is in the email box, ada@example.com.
form.elements.email finds the email box inside it, and .value reads what is typed there.The browser calls this list an HTMLFormControlsCollection. A collection is an object that works like a list: it has a length and numbered items, but it is not a real array. These tags go in the list: button, fieldset, input, object, output, select, and textarea. Two details:
- An image button,
<input type="image">, is not in the list. - A disabled control is still in the list. Disabled means greyed out: the user can't change it. The browser only leaves it out when it sends the form.
You can also write form.email. It works, but it can clash with the form's own properties. The form already has a submit method and an action property. A control named submit hides the submit method. A control named action hides the action property. form.elements.email only looks in the list of controls, so it can't clash.
const form = document.forms.signup;const email = form.elements.email;const age = form.elements.age;const plan = form.elements.plan;const snacks = form.elements.snacks; email.value; // always a stringage.valueAsNumber; // number, or NaN when emptyplan.value; // checked radio value, or ""snacks.selectedOptions;- form.elements.length
0- form.elements.email.value
""- password.value.length
0- age.value / valueAsNumber
"" /- birthday.valueAsDate
- textarea.value
""- checkboxes: checked
terms false, newsletter false- form.elements.plan.value
""- snack.value / selectedIndex
/ -1- snack.selectedOptions
- interests: chosen values
- coupon.value (disabled)
- fieldset.elements / element.form
0 / false
Change any field. The list on the right reads the real form again each time.
Two more links between forms and controls:
- Every control has an
element.formproperty. It points back to the form the control belongs to. - A
<fieldset>puts some controls in a group. It has its own smaller list,fieldset.elements, with only the controls in that group.
Input values are text
STEP THROUGHHere is the most important rule: input.value is always a string. A string is text. Even a number box gives text. If a number box shows 4, then input.value is "4". If you add 1 to that text, JavaScript joins the two and gives "41".
function readNumberInput(rawValue) { const value = String(rawValue); const plusOne = value + 1; const valueAsNumber = value === "" ? NaN : Number(value); const fixed = valueAsNumber + 1; return { value, plusOne, valueAsNumber, fixed };} const result = readNumberInput("4");console.log(result.plusOne);console.log(result.fixed);This code doesn't use a real page. It copies what a number box does, so you can step through it. In plain words, line by line:
- Line 2 turns the input into text, like
input.valuedoes. - Line 3 adds
1to the text, so it gets"41". - Line 4 makes a number from the text, like
input.valueAsNumberdoes. An empty box givesNaN. - Line 5 adds
1to the number, so it gets5. - Lines 10 and 11 print
41and then5.
value is the text "4", so + 1 joins it into "41". valueAsNumber is the number 4, so + 1 gives 5.Guess first: will the box act like text or like a number? Then step through the run.
script
function readNumberInput(rawValue) { const value = String(rawValue); const plusOne = value + 1; const valueAsNumber = value === "" ? NaN : Number(value); const fixed = valueAsNumber + 1; return { value, plusOne, valueAsNumber, fixed };} console.log(result.plusOne);console.log(result.fixed);NaN.To get a number, read valueAsNumber. It works for number boxes (type="number") and sliders (type="range"). For an empty number box:
valueis the empty string,"".valueAsNumberisNaN, which means "not a number".
So check before you do math. Number.isNaN(x) gives true when x is NaN.
Date boxes (type="date") have valueAsDate. Their value is text like "2026-09-25". Their valueAsDate is a Date object, or null when the box is empty.
Two more words you will see on controls:
- A disabled control can still be read with
form.elements. But the browser doesn't send it with the form. - A readonly control can't be edited either. But the browser does send it with the form.
const form = document.forms.signup;
const bio = form.elements.bio;
bio.value = "Current note";
console.log(bio.value);
console.log(bio.textContent);A <textarea> is a big box for many lines of text. Read what is in it now with its value property. Its textContent is the text written between its HTML tags, and typing doesn't change it. Line 3 sets the value to Current note. Line 4 prints Current note. Line 5 still prints Original HTML, the text from the HTML.
An empty number box gives NaN. A number box with something that isn't a number also gives NaN. Check with Number.isNaN() before you show a total. Don't use parseInt as a shortcut: it keeps only the whole-number part, so 12.5 becomes 12.
Checkboxes and radio buttons
INTERACTIVEOld car radios had a row of buttons, one for each station. Press one, and the button that was down pops back up, so only one is down at a time. Light switches are different. Each switch is on or off by itself.
- In real life: The row of station buttons on an old car radio
- In JavaScript: Radio buttons that share one
name - In real life: Press one button and the others pop up
- In JavaScript: Only one radio button with that name can be checked
- In real life: Light switches, each on or off by itself
- In JavaScript: Checkboxes, each with its own
checked
A radio button is a round button for choosing one answer. Radio buttons with the same name form one group, and only one button in the group can be checked. For a group named plan, form.elements.plan gives a RadioNodeList: a list of all the radio buttons named plan. Its value is the value of the checked button, or "" when none is checked.
A checkbox is a square box that is on or off. Each checkbox works on its own. Its checked property is a boolean: true when it is on, false when it is off.
"pro". Each checkbox is on its own and has its own true or false.const newsletter = document.querySelector("#newsletter");const pro = document.querySelector("#plan-pro");const selectAll = document.querySelector("#select-all"); newsletter.checked = true; // no input/change event firespro.checked = true; // same name: other radio pops outselectAll.indeterminate = true; // visual mixed stateselectAll.checked = false;- newsletter.checked
false- form.elements.plan.value
"free"- free / pro checked
true / false- select-all: checked / indeterminate
false / false- change events counted
0
Click the buttons. When code sets checked, the boxes change, but the event count stays the same.
An event is a signal the browser sends when something happens, like a click. When your code sets checked or value, the browser does not send an input or change event. That is useful: your code can fix a field without pretending the user did it. If you do want your event code to run, send the event yourself with dispatchEvent.
A "Select all" checkbox can show a third look, a dash, when only some of the boxes below it are checked. Set checkbox.indeterminate = true to show the dash. It only changes how the box looks. checked stays true or false.
Menus: select and option
INTERACTIVEA vending machine has a menu of snacks. Each snack has a code, like B7, and a place in the menu. You choose one snack. At a buffet, you can put several foods on your plate.
- In real life: The whole menu of snacks
- In JavaScript:
select.options - In real life: The code of the snack you chose, like B7
- In JavaScript:
select.value - In real life: Where that snack is in the menu
- In JavaScript:
select.selectedIndex - In real life: A buffet plate with several foods
- In JavaScript: A
multiplemenu andselectedOptions
A <select> is a drop-down menu. Each choice inside it is an <option>. A select has four useful properties:
value: the value of the chosen option, like"tea".selectedIndex: the position of the chosen option. Counting starts at 0. It is-1when nothing is chosen.options: the list of all the options.selectedOptions: the list of chosen options. A menu with themultipleattribute lets the user choose more than one.
const select = document.querySelector("select"); const tea = new Option("Tea", "tea", false, false);select.add(tea);select.value = "tea"; select.multiple = true;select.options[0].selected = true;const chosen = [...select.selectedOptions].map((option) => option.value);tea.remove();- select.value
""- selectedIndex
-1- select.multiple
false- selectedOptions
Add Tea with new Option, let the menu take more than one choice, then remove a chosen option.
value is "tea". It is at position 2, counting from 0, so selectedIndex is 2.To make a new option, write new Option(text, value, defaultSelected, selected). The four parts are:
text: the words the user sees, like"Tea".value: the value your code reads, like"tea".defaultSelected:truemakes it the starting choice, the one the menu goes back to when the form is reset.selected:truechooses it right now.
Add the option to the menu with select.add(option). Take it out with option.remove().
selectedOptions is an HTMLCollection, not an array, so it has no map method. Spread it into an array first: [...select.selectedOptions].map(option => option.value).
input.valuecheckbox.checkednumberInput.valueAsNumberform.elementsform.elements.planselect.selectedOptionsselect.selectedIndexform.elements.plan.value
Sort each form property by the kind of value it gives you.
Where you will use this
PRACTICALIn real pages, you read a form before you check it, show a preview, turn a button on, save a draft, or send it to a server. The function below reads a signup form. Each line reads the property that fits its control.
function readSignup(form) { const elements = form.elements; return { email: elements.email.value.trim(), age: elements.age.valueAsNumber, plan: elements.plan.value, toppings: [...elements.toppings.selectedOptions].map((option) => option.value), acceptsTerms: elements.terms.checked, };} function readSignupSubmission(form) { return Object.fromEntries(new FormData(form));}In plain words, line by line:
- Line 2 keeps
form.elementsin a shorter name,elements. - Line 4 reads the email text.
trim()removes spaces at the start and the end. - Line 5 reads the age as a number.
- Line 6 reads the value of the checked radio button in the
plangroup. - Line 7 spreads the chosen toppings into an array, then keeps each option's value.
- Line 8 reads the terms checkbox as
trueorfalse. - Lines 12 to 14 are a second, shorter reader that uses
FormData, shown next.
const form = document.forms.signup;
const data = new FormData(form);
const signup = Object.fromEntries(data);
console.log(signup.email);
console.log(data.getAll("toppings").join(","));new FormData(form) collects what the browser would send if the form were submitted. Line 3 turns it into a plain object with Object.fromEntries. Line 4 prints the email, ada@example.com.
That plain object keeps only one value for each name. But a menu with multiple can send the same name more than once, like toppings twice. Line 5 uses data.getAll("toppings") to keep every value, so it prints cheese,olives.
FormData leaves out checkboxes that are not checked, and it leaves out disabled controls. It keeps readonly controls.
The table below is a quick guide. Each row starts with a question you might ask about a form. Read across to see what to read and why.
| What you want to know | What to read | Why |
|---|---|---|
| What text is in the box now? | input.value | It is the current text, and it is always a string. |
| What number did the user type? | input.valueAsNumber | It gives a number, or NaN. Check for NaN before math. |
| Is the checkbox on? | checkbox.checked | It is true when on and false when off. |
| Which radio button in the group is checked? | form.elements.plan.value | The group gives the value of its checked button. |
| Which menu choice is chosen? | select.value and selectedIndex | One gives the option's value; the other gives its position. |
| Which choices are chosen in a multiple menu? | [...select.selectedOptions] | It gives the chosen option elements, spread into an array. |
| What will the form send? | new FormData(form) | It leaves out unchecked and disabled controls, and keeps every value of a repeated name. |
Common misconceptions
WATCH OUT- "A number box gives a number." Its
valueis a string. ReadvalueAsNumber, or change the text to a number yourself. - "
form.emailis always safe." It can clash with the form's own properties, likesubmit. Useform.elements.email. - "Disabled controls are not in
form.elements." They are in the list. They are only left out when the form is sent. - "A radio button is just a round checkbox." Radio buttons with the same name form a group, and only one can be checked. Read the group's value with
form.elements.plan.value. - "Setting
checkedfrom code sends achangeevent." Setting a property from code does not send any form event. - "
selectedOptionsis an array." It is anHTMLCollection. Spread it into an array before you use array methods likemap.
Practice exercises
5 EXERCISESThis code copies an empty number box. What does line 4 print?
const value = "";
const valueAsNumber = value === "" ? NaN : Number(value);
console.log(value);
console.log(Number.isNaN(valueAsNumber));const value = "";
const valueAsNumber = value === "" ? NaN : Number(value);
console.log(value);
console.log(Number.isNaN(valueAsNumber));Line 3 prints an empty line, because the value is the empty string. Line 4 prints true, because valueAsNumber is NaN and Number.isNaN finds it.
What does form.elements.plan.value give when the Pro radio button is checked?
const plan = { value: "pro" };
console.log(plan.value);const plan = { value: "pro" };
console.log(plan.value);A RadioNodeList gives the value of its checked button through .value, so the answer is pro.
A multiple menu has Tea and Cake chosen. What does the code print?
const selectedOptions = [{ value: "tea" }, { value: "cake" }];
console.log(selectedOptions.map((option) => option.value).join(","));const selectedOptions = [{ value: "tea" }, { value: "cake" }];
console.log(selectedOptions.map((option) => option.value).join(","));map keeps the value of each chosen option, and join puts them together, so it prints tea,cake.
What does the first console.log print?
const events = [];
const checkbox = { checked: false };
checkbox.checked = true;
console.log(events.length);
events.push("change");
console.log(events.length);const events = [];
const checkbox = { checked: false };
checkbox.checked = true;
console.log(events.length);
events.push("change");
console.log(events.length);After checkbox.checked = true, no event has happened, so the first count is 0. Line 5 adds one event by hand, so the second count is 1.
Write a function that reads a profile form. The form has a text box email, a number box age, a radio group plan, a multiple menu interests, and a checkbox terms.
function readProfile(form) {
// return email, age, plan, topics, and subscribed
}function readSignup(form) {
const elements = form.elements;
return {
email: elements.email.value.trim(),
age: elements.age.valueAsNumber,
plan: elements.plan.value,
toppings: [...elements.toppings.selectedOptions].map((option) => option.value),
acceptsTerms: elements.terms.checked,
};
}
function readSignupSubmission(form) {
return Object.fromEntries(new FormData(form));
}The solution finds each control through form.elements, then reads the property that fits that kind of control.
Quiz
7 QUESTIONSQuestion 1 of 7Why is
form.elements.emailusually better thanform.email?Choose an answer to see the explanation.
Question 2 of 7What does this print?
Read the code, then predictconst value = "4"; console.log(value + 1); console.log(Number(value) + 1);Choose an answer to see the explanation.
Question 3 of 7A form has three radio buttons with
name="plan", and none is checked. What isform.elements.plan.value?Choose an answer to see the explanation.
Question 4 of 7Which sentence about checkboxes is true?
Choose an answer to see the explanation.
Question 5 of 7What does this program print?
Read the code, then predictconst events = []; const box = { checked: false }; box.checked = true; console.log(events.length);Choose an answer to see the explanation.
Question 6 of 7In a menu where you can choose one thing, what does
selectedIndexmean?Choose an answer to see the explanation.
Question 7 of 7Which call makes a new option and chooses it right now?
Choose an answer to see the explanation.
Key takeaways
document.formsfinds forms.form.elementsfinds the controls inside one form.- Use
form.elements.name, notform.name, because a control's name can clash with the form's own properties. input.valueis always a string. UsevalueAsNumber,valueAsDate, or your own conversion when you need another type.- Checkboxes use
checked. A radio group gives the value of its checked button throughform.elements.plan.value. - Menus have
value,selectedIndex,options, andselectedOptions. Make new choices withnew Option.
In one line: form properties let JavaScript find each control in a form and read what it holds right now.
Up next: Form events.