HTML forms
The HTML number input, explained.
<input type="number"> is for amounts: guests, quantities, ages, prices. It adds up and down arrows, accepts only numbers and checks the range for you. Here is how to set limits and decimals, the attributes that do not work on it, and the numbers that should not use it at all.
Updated 7 November 2026
The basic number input
<label for="guests">Number of guests</label>
<input id="guests" type="number" name="guests" min="1" max="12" value="2" />- min and max set the allowed range. The browser will not send the form with a value outside it, and the arrows stop at the limits.
- value sets the starting number.
- The arrows and the arrow keys change the value by one step. On phones, the keyboard switches to numbers.
- Letters cannot be sent. Some browsers stop letters being typed at all; others let them be typed but treat the value as empty or invalid.
Decimals and step
The default step is 1, so a number input only accepts whole numbers: 2.5 is marked invalid. To allow decimals, set the step to the smallest amount you accept, or to any:
<label for="price">Price</label>
<input id="price" type="number" name="price" min="0" step="0.01" />
<label for="weight">Weight in kg</label>
<input id="weight" type="number" name="weight" min="0" step="any" />Steps count from min. With min="1" and step="2", only odd numbers are valid.
Why maxlength does nothing
maxlength, minlength and pattern are ignored on number inputs. To limit the size of a number, use max: max="999" allows up to three digits. Note that number inputs also accept scientific notation, so “1e3” is a valid way to type 1000.
Remove the arrows
The arrows take up space and are fiddly to click. These rules hide them in every current browser, while keeping the number keyboard on phones and the arrow keys on a keyboard:
/* Chrome, Edge and Safari */
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
/* Firefox */
input[type="number"] {
-moz-appearance: textfield;
appearance: textfield;
}Watch out for scrolling, too: in some browsers, scrolling the page while the pointer is over a focused number input changes its value.
Numbers that are not amounts
Phone numbers, card numbers, postcodes, verification codes and account numbers are made of digits, but they are not amounts. You never add them up, and a leading zero or a space matters. A number input refuses the spaces and symbols in them, adds arrows that make no sense, and a long number such as a card number can lose digits once a script reads it as a number.
For those, use a text input with inputmode="numeric". Phones still show a number keyboard, and nothing about the value is changed:
<label for="code">Verification code</label>
<input id="code" type="text" name="code" inputmode="numeric" pattern="[0-9]*"
autocomplete="one-time-code" maxlength="6" />For phone numbers specifically, use type="tel"; see the HTML phone input.
Read the number in JavaScript
value is always a string, even on a number input. valueAsNumber gives you an actual number, or NaN when the field is empty or invalid.
const guests = document.querySelector('#guests');
guests.value; // always a string: '3', or '' when empty or not a number
guests.valueAsNumber; // 3, or NaN when empty
guests.stepUp(); // what the up arrow does
guests.addEventListener('input', () => console.log(guests.valueAsNumber));A form that sends
This booking request posts to Heartdove, which saves every message, emails you an alert and tracks it until it is delivered or bounces. The number arrives as text, exactly as entered, under a readable version of its name: “Guests: 4”.
<form action="https://submit.heartdove.com/v1/submit" method="POST">
<input type="hidden" name="access_key" value="YOUR_ACCESS_KEY" />
<input type="hidden" name="subject" value="Table booking request" />
<label for="name">Name</label>
<input id="name" type="text" name="name" autocomplete="name" required />
<label for="email">Email</label>
<input id="email" type="email" name="email" autocomplete="email" required />
<label for="guests">Number of guests</label>
<input id="guests" type="number" name="guests" min="1" max="12" value="2" required />
<label for="message">Anything we should know?</label>
<textarea id="message" name="message" rows="4"></textarea>
<input type="checkbox" name="botcheck" tabindex="-1" autocomplete="off" style="display:none" />
<button type="submit">Request a table</button>
</form>Replace YOUR_ACCESS_KEY with your key from a free Heartdove form.
Questions
How do I allow decimals in a number input?
Set step to the smallest amount you accept, such as step="0.01" for prices, or step="any" for any decimal. The default step of 1 only allows whole numbers.
Why does maxlength not work on type="number"?
maxlength only applies to text-like inputs. Limit a number input with max instead, such as max="999".
How do I hide the arrows on a number input?
Use the ::-webkit-inner-spin-button and ::-webkit-outer-spin-button selectors with -webkit-appearance: none for Chrome, Edge and Safari, and appearance: textfield for Firefox, as shown above.
Should I use type="number" for phone numbers or postcodes?
No. Use type="tel" for phone numbers, and type="text" with inputmode="numeric" for codes and postcodes, which keeps leading zeros and spaces intact.
Why is the value of a number input a string?
Every input’s value is a string. Use valueAsNumber to get a number, which is NaN when the field is empty or invalid.
Never lose another enquiry.
Connect your first form in a few minutes. Your existing design stays exactly as it is.