The hidden depths of the input element

by Phil Nash published on

The <input> element is the most fascinating element in HTML.

Most elements behave the same way regardless of their attributes, the type attribute of the <input> element can take 1 of 22 different values that gives it not only different behaviour, but a different visual appearance too (many of which are hell to style, of course).

The <input> element is responsible for everything from text input, through checkboxes and radio buttons, to a button that resets all other elements in the form. I want to look beyond the various types that the <input> can embody, to the attributes you may not know about. Attributes that tweak the behaviour of the <input> to make it more usable, more accessible, and more applicable to various situations. Let's dig in.

Keyboard control

On a mobile device, focusing a text input will bring up the default virtual keyboard. But what if the input you are expecting is numerical or some other format? In this case the inputmode attribute can help to optimise the keyboard for the input you are expecting.

If the expected input is an email address, you can set the inputmode to “email” and the @ symbol will surface on the main keyboard. If, however, you're looking for a number, then you can set the inputmode to “numeric” or “decimal” and the number keypad will appear. This is useful in cases where your input is a number, but the input type of number isn't appropriate, for example with a one time password or a credit card number.

<input type="text" inputmode="numeric" />

The full list of inputmode values that you can use are listed below with their keyboard appearance on iOS. Android will display different variations.

  • none: stops virtual keyoards appearing for when you want to implement your own keyboard (you probably don't want this)
  • text: the default
  • numeric: just numbers
  • decimal: numbers and a decimal point
  • tel: numbers and other dial pad characters
  • url: the normal keyboard, with a period, forward slash and ".com" in place of the space bar
  • email: the normal keyboard, with a small space bar, an "@" symbol and a period
  • search: the normal keyboard, with a slightly smaller space bar, a period and a highlighted button that says "go" rather than the normal "return"

An animation showing a browser on iOS tabbing through the different inputmodes, appearing as listed above.

inputmode is also supported on <textarea>s and any element in contenteditable mode.

Get the right keyboard and your users will thank you as they input their data.

Inactive inputs

If you need to display an <input> element, but you don't want a user to be able to change the contents or you intend to change the contents in some other programmatic way, you might think that enabling the disabled attribute will help. However, disabled input elements are removed from the accessibility tree and thus disappear for users of assistive technologies. The contents of disabled inputs are also not submitted with the form.

An alternative to disabled is the readonly attribute. It makes the field inert, but the content remains accessible and will be submitted with the rest of the inputs within the form.

<label for="input">The label</label>
<input type="text" value="You can't change this" readonly id="input" />

Note by Manuel: Not all screen readers announce the field as “read only”. You may want to test it first and decide whether to support it with an additional description.

You can also target readonly elements in CSS with the pseudoclass :read-only. Elements that can be read and written can be targeted with the :read-write pseudoclass.

readonly only works on <input>s that behave like text controls and is also supported on <textarea> elements.

Choosing whether to use readonly over disabled on an element is about choosing whether an element is usable on the page. Don't forget to consider this.

Lights, camera, action

You might think the only way to have a user access the camera on their mobile device and take pictures or video is via JavaScript and the getUserMedia API. But camera access is also available declaratively. On a file upload <input> you can specify the capture attribute, which will direct the element to trigger the device camera.

Sadly this is a feature that is limited to the mobile versions of supporting browsers, on a desktop it will work like a regular file upload field.

For devices with front and back cameras, you can even provide hints for which camera to use. So if you are asking your user to take a selfie, you can set capture="user" to prefer the front-facing camera. If you are more interested in pictures of the surroundings, you can set capture="environment" to hint that you'd prefer the rear facing camera. The device can override these hints if, for example, it doesn't have a user facing camera available.

You can also use the accept attribute to hint at the type of content you want from the camera. If you accept image types, then the camera will be primed to take pictures, but if you hint that you want video then the camera will set up to record instead.

So, using the following HTML will produce the result below.

<label for="input">Cheeeeese</label>
<input type="file" capture="user" accept="image/jpeg,image/png" id="input" />

An animation showing a file input on a page using the capture attribute set to "user" and the accept attribute set to image types. When touching on the input the camera is opened, facing the user with only photo as an option. An image is captured and it appears as a small thumbnail in the file input.

This is a great way to capture an avatar for a user with no need for JavaScript, just HTML.

Spellbound

The spellcheck attribute is a generic attribute that can be used on any element. It's used to trigger the browser's spellchecking capability on elements where you also set contenteditable="true". It also works on <input> elements and is definitely something you should consider.

Different browsers treat <input> elements differently. Firefox and Safari on the desktop will not spellcheck <input> elements without the attribute, but Chrome and Safari on iOS will. To get consistent behaviour across browsers, you should set the spellcheck attribute to "true" or "false" depending on the contents of the <input>.

For regular text, help your users out with spellcheck="true". For identifiers, like usernames, email addresses, URLs, or other things that you would not expect to find in a dictionary, set spellcheck="false".

One other thing to consider, how spellchecking is implemented is left to the browser. Chrome and Edge have been known to send the contents of <input> elements to a spellchecking service over the network, exposing whatever was in the field. If your <input> elements are capturing sensitive data, like personally identifiable information, like names or birth dates, or passwords, then you should set spellcheck="false" to avoid sharing it.

<label for="input">Name</label>
<input type="text" spellcheck="false" id="input" />

Note that a <input> with type of "password" won't leak its value, but if you implement a show password feature that sets the type to "text" then this opens the field to be spellchecked.

Getting your spellcheck settings consistent helps your users as they input data into your forms and being aware of the risks of spellcheck helps you protect your users' data.

Automatic Shift

The default behaviour for an <input> on a mobile device is to capitalise the first word and make all other characters lowercase. This is fine when writing a sentence, however things like names and addresses expect all words to be capitalised. Other inputs, like airline ticket identifiers and UK postcodes expect their input to be in all capitals.

The autocapitalize attribute is your friend in this case and saves your users having to use the shift key to produce text in the format you want it.

Capitalise the first letter of every word with autocapitalize="words" and capitalise every letter with autocapitalize="characters".

<label for="input">Name</label>
<input type="text" name="full-name" autocapitalize="words" id="input" />

One thing to note, the autocapitalize attribute does not have an effect where it doesn't make sense, like on <input> elements with type of "email", "url", and, most importantly, "password".

Getting autocapitalisation right will make entering data on mobile devices much easier for your users.

Less typing is always better

Last but not least, my absolute favourite <input> attribute is the autocomplete attribute.

It provides hints for the browser to fill in input fields with data it already knows. The autocomplete attribute can take an enormous number of values that associate an <input> with many things the browser knows or can find out.

For things like registration or logging in, you can set autocomplete to values like "username" or "email". For passwords, you can use the value "new-password" to prevent a browser from autocompleting an existing password and to suggest a secure new password. Or you can use the value "current-password" to indicate that the browser or password manager should autocomplete the field with the user's password.

You can autocomplete a user's address with values like "street-address", "country-name" and "postal-code". For ecommerce applications you can combine the values with additional identifiers to separate between "billing" and "shipping" addresses.

<label for="input">Address</label>
<input type="text" autocomplete="street-address shipping" name="street-address" id="input" />

For one time passwords sent over SMS, you can use the value "one-time-password" to indicate that the browser should look at recently received messages and extract the OTP for autocomplete.

And if you're implementing passkeys, you can use the autocomplete value "webauthn" to help implement passkey autofill.

Correctly using the autocomplete attribute is even a sufficient technique to fulfill the WCAG level AA rule "identify input purpose". Providing fine-grained hints to the browser for the type of content the input fields are expecting means that they can be filled in saving time and typing for all users.

Conversely, there are times you might want to disable autocomplete entirely. Using autocomplete="off" will stop the browser remembering what was entered in an input. This is useful for fields that expect different input each time, like a text CAPTCHA.

Getting the right autocomplete attributes helps all users fill in inputs with the least amount of effort.

Picking the right attributes

Designing and developing forms that work for all users is hard. The <input> element has many options that you can choose to use to make your forms more usable and accessible.

For controlling the available virtual keyboards use inputmode. To control whether an <input> can be updated, but also still read and submitted, choose readonly over disabled. You can trigger the camera on mobile devices using capture. Use the spellcheck attribtue to control whether spellchecking is activated on an input, and remember to set it to "false" on sensitive inputs. Save users time by using autocapitalize to control the capitalisation of text in an input. And finally, use autocomplete to help the browser fill in the contents of an input and save your users typing.

All of these attributes, when deployed correctly will help your users fill in your forms with the least amount of effort.

About Phil Nash

Phil Nash is a developer advocate for Sonar living in Melbourne, Australia. He loves working with HTML, CSS, and JavaScript, in that order, to build web applications and tools to help developers.

Blog: philna.sh
Mastodon: Mastodon
Twitter: Twitter
Bluesky: Bluesky
LinkedIn: LinkedIn