UI pseudo-classes - Learn web development

UI pseudo-classes
=================

* Previous
* Overview: Forms
* Next

In the previous articles, we covered the styling of various form controls in a general manner. This included some usage of pseudo-classes, for example, using `:checked` to target a checkbox only when it is selected. In this article, we explore the different UI pseudo-classes available for styling forms in different states.

|  |  |
| --- | --- |
| Prerequisites: |
 A basic understanding of
 HTML and
 CSS, including general
 knowledge of
 pseudo-classes and pseudo-elements.
  |
| Objective: |
 To understand what parts of forms are hard to style, and why; to learn
 what can be done to customize them.
  |

What pseudo-classes do we have available?
-----------------------------------------

The original pseudo-classes (from CSS 2.1) that are relevant to forms are:

* `:hover`: Selects an element only when it is being hovered over by a mouse pointer.
* `:focus`: Selects an element only when it is focused (i.e. by being tabbed to via the keyboard).
* `:active`: selects an element only when it is being activated (i.e. while it is being clicked on, or when the
 `Return`
 /
 `Enter`
 key is being pressed down in the case of a keyboard activation).

These basic pseudo-classes should be familiar to you now. CSS selectors provide several other pseudo-classes related to HTML forms. These provide several useful targeting conditions that you can take advantage of. We'll discuss these in more detail in the sections below, but briefly, the main ones we'll be looking at are:

* `:required` and `:optional`: Target elements that can be required (e.g. elements that support the `required` HTML attribute)), based on whether they are required or optional.
* `:valid` and `:invalid`, and `:in-range` and `:out-of-range`: Target form controls that are valid/invalid according to form validation constraints set on them, or in-range/out-of-range.
* `:enabled` and `:disabled`, and `:read-only` and `:read-write`: Target elements that can be disabled (e.g. elements that support the `disabled` HTML attribute), based on whether they are currently enabled or disabled, and read-write or read-only form controls (e.g. elements with the `readonly` HTML attribute set).
* `:checked`, `:indeterminate`, and `:default`: Respectively target checkboxes and radio buttons that are checked, in an indeterminate state (neither checked or not checked), and the default selected option when the page loads (e.g. an `<input type="checkbox">` with the `checked` attribute set, or an `<option>` element with the `selected` attribute set).

There are many others, but the ones listed above are the most obviously useful. Some of them are aimed at solving very specific niche problems. The UI pseudo-classes listed above have excellent browser support, but of course, you should test your form implementations carefully to ensure they work for your target audience.

**Note:** A number of the pseudo-classes discussed here are concerned with styling form controls based on their validation state (is their data valid, or not?) You'll learn much more about setting and controlling validation constraints in our next article — Client-side form validation — but for now we'll keep things simple regarding the form validation, so it doesn't confuse things.

Styling inputs based on whether they are required or not
--------------------------------------------------------

One of the most basic concepts regarding client-side form validation is whether a form input is required (it has to be filled in before the form can be submitted) or optional.

`<input>`, `<select>`, and `<textarea>` elements have a `required` attribute available which, when set, means that you have to fill in that control before the form will successfully submit. For example:

```html
<form>
  <fieldset>
    <legend>Feedback form</legend>
    <div>
      <label for="fname">First name: </label>
      <input id="fname" name="fname" type="text" required />
    </div>
    <div>
      <label for="lname">Last name: </label>
      <input id="lname" name="lname" type="text" required />
    </div>
    <div>
      <label for="email">
        Email address (include if you want a response):
      </label>
      <input id="email" name="email" type="email" />
    </div>
    <div><button>Submit</button></div>
  </fieldset>
</form>
```

Here, the first name and last name are required, but the email address is optional.

You can match these two states using the `:required` and `:optional` pseudo-classes. For example, if we apply the following CSS to the above HTML:

```css
input:required {
  border: 1px solid black;
}

input:optional {
  border: 1px solid silver;
}
```

The required controls would have a black border, and the optional control will have a silver border, like so:

You can also try submitting the form without filling it in, to see the client-side validation error messages browsers give you by default.

The above form isn't bad, but it isn't great either. For a start, we are signaling required versus optional status using color alone, which isn't great for colorblind people. Second, the standard convention on the web for required status is an asterisk (`*`), or the word "required" being associated with the controls in question.

In the next section, we'll look at a better example of indicating required fields using `:required`, which also digs into using generated content.

**Note:** You'll probably not find yourself using the `:optional` pseudo-class very often. Form controls are optional by default, so you could just do your optional styling by default, and add styles on top for required controls.

**Note:** If one radio button in a same-named group of radio buttons has the `required` attribute set, all the radio buttons will be invalid until one is selected, but only the one with the attribute assigned will actually match `:required`.

Using generated content with pseudo-classes
-------------------------------------------

In previous articles, we've seen the usage of generated content, but we thought now would be a good time to talk about it in a bit more detail.

The idea is that we can use the `::before` and `::after` pseudo-elements along with the `content` property to make a chunk of content appear before or after the affected element. The chunk of content is not added to the DOM, so it may be invisible to some screen readers. Because it is a pseudo-element, it can be targeted with styles in the same way that any actual DOM node can.

This is really useful when you want to add a visual indicator to an element, such as a label or icon, when alternative indicators are also available to ensure accessibility for all users. For example, in our custom radio buttons example, we use generated content to handle the placement and animation of the a custom radio button's inner circle when a radio button is selected:

```css
input[type="radio"]::before {
  display: block;
  content: " ";
  width: 10px;
  height: 10px;
  border-radius: 6px;
  background-color: red;
  font-size: 1.2em;
  transform: translate(3px, 3px) scale(0);
  transform-origin: center;
  transition: all 0.3s ease-in;
}

input[type="radio"]:checked::before {
  transform: translate(3px, 3px) scale(1);
  transition: all 0.3s cubic-bezier(0.25, 0.25, 0.56, 2);
}
```

This is really useful — screen readers already let their users know when a radio button or checkbox they encounter is checked/selected, so you don't want them to read out another DOM element that indicates selection — that could be confusing. Having a purely visual indicator solves this problem.

Back to our required/optional example from before, this time we'll not alter the appearance of the input itself — we'll use generated content to add an indicating label (see it live here, and see the source code here).

First of all, we'll add a paragraph to the top of the form to say what you are looking for:

```html
<p>Required fields are labeled with "required".</p>
```

Screen reader users will get "required" read out as an extra bit of information when they get to each required input, while sighted users will get our label.

Since form inputs don't directly support having generated content put on them (this is because generated content is placed relative to an element's formatting box, but form inputs work more like replaced elements and therefore don't have one), we will add an empty `<span>` to hang the generated content on:

```html
<div>
  <label for="fname">First name: </label>
  <input id="fname" name="fname" type="text" required />
  <span></span>
</div>
```

The immediate problem with this was that the span was dropping onto a new line below the input because the input and label are both set with `width: 100%`. To fix this we style the parent `<div>` to become a flex container, but also tell it to wrap its contents onto new lines if the content becomes too long:

```css
fieldset > div {
  margin-bottom: 20px;
  display: flex;
  flex-flow: row wrap;
}
```

The effect this has is that the label and input sit on separate lines because they are both `width: 100%`, but the `<span>` has a width of `0` so it can sit on the same line as the input.

Now onto the generated content. We create it using this CSS:

```css
input + span {
  position: relative;
}

input:required + span::after {
  font-size: 0.7rem;
  position: absolute;
  content: "required";
  color: white;
  background-color: black;
  padding: 5px 10px;
  top: -26px;
  left: -70px;
}
```

We set the `<span>` to `position: relative` so that we can set the generated content to `position: absolute` and position it relative to the `<span>` rather than the `<body>` (The generated content acts as though it is a child node of the element it is generated on, for the purposes of positioning).

Then we give the generated content the content "required", which is what we wanted our label to say, and style and position it as we want. The result is seen below.

Styling controls based on whether their data is valid
-----------------------------------------------------

The other really important, fundamental concept in form validation is whether a form control's data is valid or not (in the case of numerical data, we can also talk about in-range and out-of-range data). Form controls with constraint limitations can be targeted based on these states.

### :valid and :invalid

You can target form controls using the `:valid` and `:invalid` pseudo-classes. Some points worth bearing in mind:

* Controls with no constraint validation will always be valid, and therefore matched with `:valid`.
* Controls with `required` set on them that have no value are counted as invalid — they will be matched with `:invalid` and `:required`.
* Controls with built-in validation, such as `<input type="email">` or `<input type="url">` are (matched with) `:invalid` when the data entered into them does not match the pattern they are looking for (but they are valid when empty).
* Controls whose current value is outside the range limits specified by the `min` and `max` attributes are (matched with) `:invalid`, but also matched by `:out-of-range`, as you'll see later on.
* There are some other ways to make an element matched by `:valid`/`:invalid`, as you'll see in the Client-side form validation article. But we'll keep things simple for now.

Let's go in and look at a simple example of `:valid`/`:invalid` (see valid-invalid.html for the live version, and also check out the source code).

As in the previous example, we've got extra `<span>`s to generate content on, which we'll use to provide indicators of valid/invalid data:

```html
<div>
  <label for="fname">First name: </label>
  <input id="fname" name="fname" type="text" required />
  <span></span>
</div>
```

To provide these indicators, we use the following CSS:

```css
input + span {
  position: relative;
}

input + span::before {
  position: absolute;
  right: -20px;
  top: 5px;
}

input:invalid {
  border: 2px solid red;
}

input:invalid + span::before {
  content: "✖";
  color: red;
}

input:valid + span::before {
  content: "✓";
  color: green;
}
```

As before, we set the `<span>`s to `position: relative` so that we can position the generated content relative to them. We then absolutely position different generated content depending on whether the form's data is valid or invalid — a green check or a red cross, respectively. To add a bit of extra urgency to the invalid data, we've also given the inputs a thick red border when invalid.

**Note:** We've used `::before` to add these labels, as we were already using `::after` for the "required" labels.

You can try it below:

Notice how the required text inputs are invalid when empty, but valid when they have something filled in. The email input on the other hand is valid when empty, as it is not required, but invalid when it contains something that is not a proper email address.

### In-range and out-of-range data

As we hinted at above, there are two other related pseudo-classes to consider — `:in-range` and `:out-of-range`. These match numeric inputs where range limits are specified by the `min` and `max`, when their data is inside or outside the specified range, respectively.

**Note:** Numeric input types are `date`, `month`, `week`, `time`, `datetime-local`, `number`, and `range`.

It is worth noting that inputs whose data is in-range will also be matched by the `:valid` pseudo-class and inputs whose data is out-of-range will also be matched by the `:invalid` pseudo-class. So why have both? The issue is really one of semantics — out-of-range is a more specific type of invalid communication, so you might want to provide a different message for out-of-range inputs, which will be more helpful to users than just saying "invalid". You might even want to provide both.

Let's look at an example that does exactly this. Our out-of-range.html demo (see also the source code) builds on top of the previous example to provide out-of-range messages for the numeric inputs, as well as saying whether they are required.

The numeric input looks like this:

```html
<div>
  <label for="age">Age (must be 12+): </label>
  <input id="age" name="age" type="number" min="12" max="120" required />
  <span></span>
</div>
```

And the CSS looks like this:

```css
input + span {
  position: relative;
}

input + span::after {
  font-size: 0.7rem;
  position: absolute;
  padding: 5px 10px;
  top: -26px;
}

input:required + span::after {
  color: white;
  background-color: black;
  content: "Required";
  left: -70px;
}

input:out-of-range + span::after {
  color: white;
  background-color: red;
  width: 155px;
  content: "Outside allowable value range";
  left: -182px;
}
```

This is a similar story to what we had before in the `:required` example, except that here we've split out the declarations that apply to any `::after` content into a separate rule, and given the separate `::after` content for `:required` and `:out-of-range` states their own content and styling. You can try it here:

It is possible for the number input to be both required and out-of-range at the same time, so what happens then? Because the `:out-of-range` rule appears later in the source code than the `:required` rule, the cascade rules come into play, and the out of range message is shown.

This works quite nicely — when the page first loads, "Required" is shown, along with a red cross and border. When you've typed in a valid age (i.e. in the range of 12-120), the input turns valid. If however, you then change the age entry to one that is out of range, the "Outside allowable value range" message then pops up in place of "Required".

**Note:** To enter an invalid/out-of-range value, you'll have to actually focus the form and type it in using the keyboard. The spinner buttons won't let you increment/decrement the value outside the allowable range.

Styling enabled and disabled inputs, and read-only and read-write
-----------------------------------------------------------------

An enabled element is an element that can be activated; it can be selected, clicked on, typed into, etc. A disabled element on the other hand cannot be interacted with in any way, and its data isn't even sent to the server.

These two states can be targeted using `:enabled` and `:disabled`. Why are disabled inputs useful? Well, sometimes if some data does not apply to a certain user, you might not even want to submit that data when they submit the form. A classic example is a shipping form — commonly you'll get asked if you want to use the same address for billing and shipping; if so, you can just send a single address to the server, and might as well just disable the billing address fields.

Let's have a look at an example that does just this. First of all, the HTML is a simple form containing text inputs, plus a checkbox to toggle disabling the billing address on and off. The billing address fields are disabled by default.

```html
<form>
  <fieldset id="shipping">
    <legend>Shipping address</legend>
    <div>
      <label for="name1">Name: </label>
      <input id="name1" name="name1" type="text" required />
    </div>
    <div>
      <label for="address1">Address: </label>
      <input id="address1" name="address1" type="text" required />
    </div>
    <div>
      <label for="pcode1">Zip/postal code: </label>
      <input id="pcode1" name="pcode1" type="text" required />
    </div>
  </fieldset>
  <fieldset id="billing">
    <legend>Billing address</legend>
    <div>
      <label for="billing-checkbox">Same as shipping address:</label>
      <input type="checkbox" id="billing-checkbox" checked />
    </div>
    <div>
      <label for="name" class="billing-label disabled-label">Name: </label>
      <input id="name" name="name" type="text" disabled required />
    </div>
    <div>
      <label for="address2" class="billing-label disabled-label">
        Address:
      </label>
      <input id="address2" name="address2" type="text" disabled required />
    </div>
    <div>
      <label for="pcode2" class="billing-label disabled-label">
        Zip/postal code:
      </label>
      <input id="pcode2" name="pcode2" type="text" disabled required />
    </div>
  </fieldset>

  <div><button>Submit</button></div>
</form>
```

Now onto the CSS. The most relevant parts of this example are as follows:

```css
input[type="text"]:disabled {
  background: #eee;
  border: 1px solid #ccc;
}

.disabled-label {
  color: #aaa;
}
```

We've directly selected the inputs we want to disable using `input[type="text"]:disabled`, but we also wanted to gray out the corresponding text labels. These weren't quite as easy to select, so we've used a class to provide them with that styling.

Now finally, we've used some JavaScript to toggle the disabling of the billing address fields:

```js
// Wait for the page to finish loading
document.addEventListener(
  "DOMContentLoaded",
  () => {
    // Attach `change` event listener to checkbox
    document
      .getElementById("billing-checkbox")
      .addEventListener("change", toggleBilling);
  },
  false,
);

function toggleBilling() {
  // Select the billing text fields
  const billingItems = document.querySelectorAll('#billing input[type="text"]');
  // Select the billing text labels
  const billingLabels = document.querySelectorAll(".billing-label");

  // Toggle the billing text fields and labels
  for (let i = 0; i < billingItems.length; i++) {
    billingItems[i].disabled = !billingItems[i].disabled;

    if (
      billingLabels[i].getAttribute("class") === "billing-label disabled-label"
    ) {
      billingLabels[i].setAttribute("class", "billing-label");
    } else {
      billingLabels[i].setAttribute("class", "billing-label disabled-label");
    }
  }
}
```

It uses the `change` event to let the user enable/disable the billing fields, and toggle the styling of the associated labels.

You can see the example in action below (also see it live here, and see the source code):

### Read-only and read-write

In a similar manner to `:disabled` and `:enabled`, the `:read-only` and `:read-write` pseudo-classes target two states that form inputs toggle between. Read-only inputs have their values submitted to the server, but the user can't edit them, whereas read-write means they can be edited — their default state.

An input is set to read-only using the `readonly` attribute. As an example, imagine a confirmation page where the developer has sent the details filled in on previous pages over to this page, with the aim of getting the user to check them all in one place, add any final data that is needed, and then confirm the order by submitting. At this point, all the final form data can be sent to the server in one go.

Let's look at what a form might look like (see readonly-confirmation.html for the live example; also see the source code).

A fragment of the HTML is as follows — note the readonly attribute:

```html
<div>
  <label for="name">Name: </label>
  <input id="name" name="name" type="text" value="Mr Soft" readonly />
</div>
```

If you try the live example, you'll see that the top set of form elements are not focusable, however, the values are submitted when the form is submitted. We've styled the form controls using the `:read-only` and `:read-write` pseudo-classes, like so:

```css
input:read-only,
textarea:read-only {
  border: 0;
  box-shadow: none;
  background-color: white;
}

textarea:read-write {
  box-shadow: inset 1px 1px 3px #ccc;
  border-radius: 5px;
}
```

The full example looks like this:

**Note:** `:enabled` and `:read-write` are two more pseudo-classes that you'll probably rarely use, given that they describe the default states of input elements.

Radio and checkbox states — checked, default, indeterminate
-----------------------------------------------------------

As we've seen in earlier articles in the module, radio buttons and checkboxes can be checked or unchecked. But there are a couple of other states to consider too:

* `:default`: Matches radios/checkboxes that are checked by default, on page load (i.e. by setting the `checked` attribute on them). These match the `:default` pseudo-class, even if the user unchecks them.
* `:indeterminate`: When radios/checkboxes are neither checked nor unchecked, they are considered *indeterminate* and will match the `:indeterminate` pseudo-class. More on what this means below.
### :checked

When checked, they will be matched by the `:checked` pseudo-class.

The most common use of this is to add a different style onto the checkbox or radio button when it is checked, in cases where you've removed the system default styling with `appearance: none;` and want to build the styles back up yourself. We saw examples of this in the previous article when we talked about Using `appearance: none` on radios/checkboxes.

As a recap, the `:checked` code from our Styled radio buttons example looks like so:

```css
input[type="radio"]::before {
  display: block;
  content: " ";
  width: 10px;
  height: 10px;
  border-radius: 6px;
  background-color: red;
  font-size: 1.2em;
  transform: translate(3px, 3px) scale(0);
  transform-origin: center;
  transition: all 0.3s ease-in;
}

input[type="radio"]:checked::before {
  transform: translate(3px, 3px) scale(1);
  transition: all 0.3s cubic-bezier(0.25, 0.25, 0.56, 2);
}
```

You can try it out here:

Basically, we build the styling for a radio button's "inner circle" using the `::before` pseudo-element, but set a `scale(0)` `transform` on it. We then use a `transition` to make the generated content on the label nicely animate into view when the radio is selected/checked. The advantage of using a transform rather than transitioning `width`/`height` is that you can use `transform-origin` to make it grow from the center of the circle, rather than having it appear to grow from the circle's corner, and there is no jumping behavior as no box model property values are updated.

### :default and :indeterminate

As mentioned above, the `:default` pseudo-class matches radios/checkboxes that are checked by default, on page load, even when unchecked. This could be useful for adding an indicator to a list of options to remind the user what the defaults (or starting options) were, in case they want to reset their choices.

Also, the radios/checkboxes mentioned above will be matched by the `:indeterminate` pseudo-class when they are in a state where they are neither checked nor unchecked. But what does this mean? Elements that are indeterminate include:

* `<input/radio>` inputs, when all radio buttons in a same-named group are unchecked
* `<input/checkbox>` inputs whose `indeterminate` property is set to `true` via JavaScript
* `<progress>` elements that have no value.

This isn't something you'll likely use very often. One use case could be an indicator to tell users that they really need to select a radio button before they move on.

Let's look at a couple of modified versions of the previous example that remind the user what the default option was, and style the labels of radio buttons when indeterminate. Both of these have the following HTML structure for the inputs:

```html
<p>
  <input type="radio" name="fruit" value="cherry" id="cherry" />
  <label for="cherry">Cherry</label>
  <span></span>
</p>
```

For the `:default` example, we've added the `checked` attribute to the middle radio button input, so it will be selected by default when loaded. We then style this with the following CSS:

```css
input ~ span {
  position: relative;
}

input:default ~ span::after {
  font-size: 0.7rem;
  position: absolute;
  content: "Default";
  color: white;
  background-color: black;
  padding: 5px 10px;
  right: -65px;
  top: -3px;
}
```

This provides a little "Default" label on the item that was originally selected when the page loaded. Note here we are using the subsequent-sibling combinator (`~`) rather than the Next-sibling combinator (`+`) — we need to do this because the `<span>` does not come right after the `<input>` in the source order.

See the live result below:

**Note:** You can also find the example live on GitHub at radios-checked-default.html (also see the source code.)

For the `:indeterminate` example, we've got no default selected radio button — this is important — if there was, then there would be no indeterminate state to style. We style the indeterminate radio buttons with the following CSS:

```css
input[type="radio"]:indeterminate {
  outline: 2px solid red;
  animation: 0.4s linear infinite alternate outline-pulse;
}

@keyframes outline-pulse {
  from {
    outline: 2px solid red;
  }

  to {
    outline: 6px solid red;
  }
}
```

This creates a fun little animated outline on the radio buttons, which hopefully indicates that you need to select one of them!

See the live result below:

**Note:** You can also find the example live on GitHub at radios-checked-indeterminate.html (also see the source code.)

**Note:** You can find an interesting example involving `indeterminate` states on the `<input type="checkbox">` reference page.

More pseudo-classes
-------------------

There are a number of other pseudo-classes of interest, and we don't have space to write about them all in detail here. Let's talk about a few more that you should take the time to investigate.

* The `:focus-within` pseudo-class matches an element that has received focus or *contains* an element that has received focus. This is useful if you want a whole form to highlight in some way when an input inside it is focused.
* The `:focus-visible` pseudo-class matches focused elements that received focus via keyboard interaction (rather than touch or mouse) — useful if you want to show a different style for keyboard focus compared to mouse (or other) focus.
* The `:placeholder-shown` pseudo-class matches `<input>` and `<textarea>` elements that have their placeholder showing (i.e. the contents of the `placeholder` attribute) because the value of the element is empty.

The following are also interesting, but as yet not well-supported in browsers:

* The `:blank` pseudo-class selects empty form controls. `:empty` also matches elements that have no children, like `<input>`, but it is more general — it also matches other void elements like `<br>` and `<hr>`. `:empty` has reasonable browser support; the `:blank` pseudo-class's specification is not yet finished, so it is not yet supported in any browser.
* The `:user-invalid` pseudo-class, when supported, will be similar to `:invalid`, but with better user experience. If the value is valid when the input receives focus, the element may match `:invalid` as the user enters data if the value is temporarily invalid, but will only match `:user-invalid` when the element loses focus. If the value was originally invalid, it will match both `:invalid` and `:user-invalid` for the whole duration of the focus. In a similar manner to `:invalid`, it will stop matching `:user-invalid` if the value does become valid.
Test your skills!
-----------------

You've reached the end of this article, but can you remember the most important information? You can find some further tests to verify that you've retained this information before you move on — see Test your skills: Advanced styling.

Summary
-------

This completes our look at UI pseudo-classes that relate to form inputs. Keep playing with them, and create some fun form styles! Next up, we'll move on to something different — client-side form validation.

* Previous
* Overview: Forms
* Next
### Advanced Topics

* How to build custom form controls
* Sending forms through JavaScript
* Property compatibility table for form widgets


Basic native form controls - Learn web development

Basic native form controls
==========================

* Previous
* Overview: Forms
* Next

In the previous article, we marked up a functional web form example, introducing some form controls and common structural elements, and focusing on accessibility best practices. Next, we will look at the functionality of the different form controls, or widgets, in detail — studying all the different options available to collect different types of data. In this particular article, we will look at the original set of form controls, available in all browsers since the early days of the web.

|  |  |
| --- | --- |
| Prerequisites: |
 A basic
 understanding of HTML.
  |
| Objective: |
 To understand in detail the original set of native form widgets
 available in browsers for collecting data, and how to implement them
 using HTML.
  |

You've already met some form elements, including `<form>`, `<fieldset>`, `<legend>`, `<textarea>`, `<label>`, `<button>`, and `<input>`. This article covers:

* The common input types button, checkbox, file, hidden, image, password, radio, reset, submit, and text.
* Some of the attributes that are common to all form controls.

**Note:** We cover additional, more powerful form controls in the next two articles. If you want a more advanced reference, you should consult our HTML forms element reference, and in particular our extensive `<input>` types reference.

Text input fields
-----------------

Text `<input>` fields are the most basic form widgets. They are a very convenient way to let the user enter any kind of data, and we've already seen a few simple examples.

**Note:** HTML form text fields are simple plain text input controls. This means that you cannot use them to perform rich text editing (bold, italic, etc.). All rich text editors you'll encounter are custom widgets created with HTML, CSS, and JavaScript.

All basic text controls share some common behaviors:

* They can be marked as `readonly` (the user cannot modify the input value but it is still sent with the rest of the form data) or `disabled` (the input value can't be modified and is never sent with the rest of the form data).
* They can have a `placeholder`; this is the text that appears inside the text input box that should be used to briefly describe the purpose of the box.
* They can be constrained in `size` (the physical size of the box) and `maxlength` (the maximum number of characters that can be entered into the box).
* They can benefit from spell checking (using the `spellcheck` attribute), if the browser supports it.

**Note:** The `<input>` element is unique amongst HTML elements because it can take many forms depending on its `type` attribute value. It is used for creating most types of form widgets including single line text fields, time and date controls, controls without text input like checkboxes, radio buttons, and color pickers, and buttons.

### Single line text fields

A single line text field is created using an `<input>` element whose `type` attribute value is set to `text`, or by omitting the `type` attribute altogether (`text` is the default value). The value `text` for this attribute is also the fallback value if the value you specify for the `type` attribute is unknown by the browser (for example if you specify `type="color"` and the browser doesn't support native color pickers).

**Note:** You can find examples of all the single line text field types on GitHub at single-line-text-fields.html (see it live also).

Here is a basic single line text field example:

```html
<input type="text" id="comment" name="comment" value="I'm a text field" />
```

Single line text fields have only one true constraint: if you type text with line breaks, the browser removes those line breaks before sending the data to the server.

The screenshot below shows a text input in default, focused, and disabled states. Most browsers indicate the focused state using a focus ring around the control and the disabled state using grey text or a faded/semi-opaque control.

![Screenshot of the default, focused and disabled states text input in Chrome on macOS](/en-US/docs/Learn/Forms/Basic_native_form_controls/disabled.png)

The screenshots used in this document were taken in the Chrome browser on macOS. There may be minor variations in these fields/buttons across different browsers, but the basic highlighting technique remains similar.

**Note:** We discuss values for the `type` attribute that enforce specific validation constraints including color, email, and url input types, in the next article, The HTML5 input types.

#### Password field

One of the original input types was the `password` text field type:

```html
<input type="password" id="pwd" name="pwd" />
```

The following screenshot shows Password input field in which each input character is shown as a dot.

![Password field in chrome 115 on macOS](/en-US/docs/Learn/Forms/Basic_native_form_controls/password.png)

The `password` value doesn't add any special constraints to the entered text, but it does obscure the value entered into the field (e.g. with dots or asterisks) so it can't be easily read by others.

Keep in mind this is just a user interface feature; unless you submit your form securely, it will get sent in plain text, which is bad for security — a malicious party could intercept your data and steal passwords, credit card details, or whatever else you've submitted. The best way to protect users from this is to host any pages involving forms over a secure connection (i.e. located at an `https://` address), so the data is encrypted before it is sent.

Browsers recognize the security implications of sending form data over an insecure connection, and have warnings to deter users from using insecure forms. For more information on what Firefox implements, see Insecure passwords.

### Hidden content

Another original text control is the `hidden` input type. This is used to create a form control that is invisible to the user, but is still sent to the server along with the rest of the form data once submitted — for example you might want to submit a timestamp to the server stating when an order was placed. Because it is hidden, the user can not see nor intentionally edit the value, it will never receive focus, and a screen reader will not notice it either.

```html
<input type="hidden" id="timestamp" name="timestamp" value="1286705410" />
```

If you create such an element, it's required to set its `name` and `value` attributes. The value can be dynamically set via JavaScript. The `hidden` input type should not have an associated label.

Other text input types, like search, url, and tel, will be covered in the next tutorial, HTML5 input types.

Checkable items: checkboxes and radio buttons
---------------------------------------------

Checkable items are controls whose state you can change by clicking on them or their associated labels. There are two kinds of checkable items: the checkbox and the radio button. Both use the `checked` attribute to indicate whether the widget is checked by default or not.

It's worth noting that these widgets do not behave exactly like other form widgets. For most form widgets, once the form is submitted all widgets that have a `name` attribute are sent, even if no value has been filled out. In the case of checkable items, their values are sent only if they are checked. If they are not checked, nothing is sent, not even their name. If they are checked but have no value, the name is sent with a value of *on.*

**Note:** You can find the examples from this section on GitHub as checkable-items.html (see it live also).

For maximum usability/accessibility, you are advised to surround each list of related items in a `<fieldset>`, with a `<legend>` providing an overall description of the list. Each individual pair of `<label>`/`<input>` elements should be contained in its own list item (or similar). The associated `<label>` is generally placed immediately before or after the radio button or checkbox, with the instructions for the group of radio button or checkboxes generally being the content of the `<legend>`. See the examples linked above for structural examples.

### Checkbox

A checkbox is created using the `<input>` element with a `type` attribute set to the value checkbox.

```html
<input type="checkbox" id="questionOne" name="subscribe" value="yes" checked />
```

Related checkbox items should use the same `name` attribute. Including the `checked` attribute makes the checkbox checked automatically when the page loads. Clicking the checkbox or its associated label toggles the checkbox on and off.

```html
<fieldset>
  <legend>Choose all the vegetables you like to eat</legend>
  <ul>
    <li>
      <label for="carrots">Carrots</label>
      <input
 type="checkbox"
 id="carrots"
 name="vegetable"
 value="carrots"
 checked />
    </li>
    <li>
      <label for="peas">Peas</label>
      <input type="checkbox" id="peas" name="vegetable" value="peas" />
    </li>
    <li>
      <label for="cabbage">Cabbage</label>
      <input type="checkbox" id="cabbage" name="vegetable" value="cabbage" />
    </li>
  </ul>
</fieldset>
```

The following screenshot shows checkboxes in the default, focused, and disabled states. Checkboxes in the default and disabled states appear checked, whereas in the focused state, the checkbox is unchecked, with focus ring around it.

![Default, focused and disabled Checkboxes in chrome 115 on macOS](/en-US/docs/Learn/Forms/Basic_native_form_controls/checkboxes.png)

**Note:** Any checkboxes and radio buttons with the `checked` attribute on load match the `:default` pseudo-class, even if they are no longer checked. Any that are currently checked match the `:checked` pseudo-class.

Due to the on-off nature of checkboxes, the checkbox is considered a toggle button, with many developers and designers expanding on the default checkbox styling to create buttons that look like toggle switches. You can see an example in action here (also see the source code).

### Radio button

A radio button is created using the `<input>` element with its `type` attribute set to the value `radio`:

```html
<input type="radio" id="soup" name="meal" value="soup" checked />
```

Several radio buttons can be tied together. If they share the same value for their `name` attribute, they will be considered to be in the same group of buttons. Only one button in a given group may be checked at a time; this means that when one of them is checked all the others automatically get unchecked. When the form is sent, only the value of the checked radio button is sent. If none of them are checked, the whole pool of radio buttons is considered to be in an unknown state and no value is sent with the form. Once one of the radio buttons in a same-named group of buttons is checked, it is not possible for the user to uncheck all the buttons without resetting the form.

```html
<fieldset>
  <legend>What is your favorite meal?</legend>
  <ul>
    <li>
      <label for="soup">Soup</label>
      <input type="radio" id="soup" name="meal" value="soup" checked />
    </li>
    <li>
      <label for="curry">Curry</label>
      <input type="radio" id="curry" name="meal" value="curry" />
    </li>
    <li>
      <label for="pizza">Pizza</label>
      <input type="radio" id="pizza" name="meal" value="pizza" />
    </li>
  </ul>
</fieldset>
```

The following screenshot shows default and disabled radio buttons in the checked state, along with focused a radio button in the unchecked state.

![Default, focused and disabled Radio buttons in chrome 115 on macOS](/en-US/docs/Learn/Forms/Basic_native_form_controls/radios.png)

Actual buttons
--------------

The radio button isn't actually a button, despite its name; let's move on and look at actual buttons! There are three input types that produce buttons:

`submit`

Sends the form data to the server. For `<button>` elements, omitting the `type` attribute (or an invalid value of `type`) results in a submit button.

`reset`

Resets all form widgets to their default values.

`button`

Buttons that have no automatic effect but can be customized using JavaScript code.

Then we also have the `<button>` element itself. This can take a `type` attribute of value `submit`, `reset`, or `button` to mimic the behavior of the three `<input>` types mentioned above. The main difference between the two is that actual `<button>` elements are much easier to style.

```html
<input type="submit" value="Submit this form" />
<input type="reset" value="Reset this form" />
<input type="button" value="Do Nothing without JavaScript" />

<button type="submit">Submit this form</button>
<button type="reset">Reset this form</button>
<button type="button">Do Nothing without JavaScript</button>
```

```
<div class="buttondemo">
  <p>Using <input></p>
  <p>
    <input type="submit" value="Submit this form" />
    <input type="reset" value="Reset this form" />
    <input type="button" value="Do Nothing without JavaScript" />
  </p>
  <p>Using <button></p>
  <p>
    <button type="submit">Submit this form</button>
    <button type="reset">Reset this form</button>
    <button type="button">Do Nothing without JavaScript</button>
  </p>
</div>
```

```
button,
input {
  display: none;
}
.buttondemo button,
.buttondemo input {
  all: revert;
}
```

**Note:** The `image` input type also renders as a button. We'll cover that later too.

**Note:** You can find the examples from this section on GitHub as button-examples.html (see it live also).

Below you can find examples of each button `<input>` type, along with the equivalent `<button>` type.

### submit

```html
<button type="submit">This is a <strong>submit button</strong></button>

<input type="submit" value="This is a submit button" />
```

### reset

```html
<button type="reset">This is a <strong>reset button</strong></button>

<input type="reset" value="This is a reset button" />
```

### anonymous

```html
<button type="button">This is an <strong>anonymous button</strong></button>

<input type="button" value="This is an anonymous button" />
```

Buttons always behave the same whether you use a `<button>` element or an `<input>` element. As you can see from the examples, however, `<button>` elements let you use HTML in their content, which is inserted between the opening and closing `<button>` tags. `<input>` elements on the other hand are void elements; their displayed content is inserted inside the `value` attribute, and therefore only accepts plain text as content.

The following screenshot shows a button in the default, focused, and disabled states. In the focused state, there is a focus ring around the button, and in the disabled state, the button is greyed out.

![Default, focus, and disabled button states in chrome 115 on macOS](/en-US/docs/Learn/Forms/Basic_native_form_controls/buttons.png)

### Image button

The **image button** control is rendered exactly like an `<img>` element, except that when the user clicks on it, it behaves like a submit button.

An image button is created using an `<input>` element with its `type` attribute set to the value `image`. This element supports exactly the same set of attributes as the `<img>` element, plus all the attributes supported by other form buttons.

```html
<input type="image" alt="Click me!" src="my-img.png" width="80" height="30" />
```

If the image button is used to submit the form, this control doesn't submit its value — instead, the X and Y coordinates of the click on the image are submitted (the coordinates are relative to the image, meaning that the upper-left corner of the image represents the coordinate (0, 0)). The coordinates are sent as two key/value pairs:

* The X value key is the value of the `name` attribute followed by the string "*.x*".
* The Y value key is the value of the `name` attribute followed by the string "*.y*".

So for example when you click on the image at coordinate (123, 456) and it submits via the `get` method, you'll see the values appended to the URL as follows:

```url
http://foo.com?pos.x=123&pos.y=456
```

This is a very convenient way to build a "hot map". How these values are sent and retrieved is detailed in the Sending form data article.

File picker
-----------

There is one last `<input>` type that came to us in early HTML: the file input type. Forms are able to send files to a server (this specific action is also detailed in the Sending form data article). The file picker widget can be used to choose one or more files to send.

To create a file picker widget, you use the `<input>` element with its `type` attribute set to `file`. The types of files that are accepted can be constrained using the `accept` attribute. In addition, if you want to let the user pick more than one file, you can do so by adding the `multiple` attribute.

### Example

In this example, a file picker is created that requests graphic image files. The user is allowed to select multiple files in this case.

```html
<input type="file" name="file" id="file" accept="image/\*" multiple />
```

On some mobile devices, the file picker can access photos, videos, and audio captured directly by the device's camera and microphone by adding capture information to the `accept` attribute like so:

```html
<input type="file" accept="image/\*;capture=camera" />
<input type="file" accept="video/\*;capture=camcorder" />
<input type="file" accept="audio/\*;capture=microphone" />
```

The following screenshot shows the file picker widget in the default, focus, and disabled states when no file is selected.

![File picker widget in default, focus, and disabled states in chrome 115 on macOS](/en-US/docs/Learn/Forms/Basic_native_form_controls/filepickers.png)

Common attributes
-----------------

Many of the elements used to define form controls have some of their own specific attributes. However, there is a set of attributes common to all form elements. You've met some of these already, but below is a list of those common attributes, for your reference:

| Attribute name | Default value | Description |
| --- | --- | --- |
| `autofocus` | false |
 This Boolean attribute lets you specify that the element should
 automatically have input focus when the page loads. Only one
 form-associated element in a document can have this attribute specified.
  |
| `disabled` | false |
 This Boolean attribute indicates that the user cannot interact with the
 element. If this attribute is not specified, the element inherits its
 setting from the containing element, for example,
 `<fieldset>`; if there is no containing element
 with the `disabled` attribute set, then the element is
 enabled.
  |
| `form` |  |
 The `<form>` element that the widget is associated with,
 used if it is not nested within that form. The value of the attribute
 must be the `id` attribute of a
 `<form>` element in the same document. This lets
 you associate a form control with a form it is outside of, even if it is
 inside a different form element.
  |
| `name` |  | The name of the element; this is submitted with the form data. |
| `value` |  | The element's initial value. |

Test your skills!
-----------------

You've reached the end of this article, but can you remember the most important information? You can find some further tests to verify that you've retained this information before you move on — see Test your skills: Basic controls.

Summary
-------

This article has covered the older input types — the original set introduced in the early days of HTML that is well-supported in all browsers. In the next section, we'll take a look at the more modern values of the `type` attribute.

* Previous
* Overview: Forms
* Next
### Advanced Topics

* How to build custom form controls
* Sending forms through JavaScript
* Property compatibility table for form widgets


Test your skills: Styling basics - Learn web development

Test your skills: Styling basics
================================

The aim of this skill test is to assess whether you've understood our Styling web forms article.

**Note:** You can try solutions in the interactive editors on this page or in an online editor such as CodePen, JSFiddle, or Glitch.

If you get stuck, you can reach out to us in one of our communication channels.

Styling basics 1
----------------

Our basic form styling assessment is fairly free-form, and you have a lot of flexibility over what you end up doing here. But your CSS should aim to fulfill the following requirements:

1. Add some kind of lightweight "reset" to make fonts, padding, margin, and sizing more consistent to begin with.
2. On top of that, add in some nice, consistent styling for the inputs and button.
3. Use some kind of layout technique to make the inputs and labels line up neatly.

Download the starting point for this task to work in your own editor or in an online editor.


Advanced form styling - Learn web development

Advanced form styling
=====================

* Previous
* Overview: Forms
* Next

In this article, we will see what can be done with CSS to style the types of form control that are more difficult to style — the "bad" and "ugly" categories. As we saw in the previous article, text fields and buttons are perfectly easy to style; now we will dig into styling the more problematic bits.

|  |  |
| --- | --- |
| Prerequisites: |
 A basic understanding of
 HTML and
 CSS.
  |
| Objective: |
 To understand what parts of forms are hard to style, and why; to learn
 what can be done to customize them.
  |

To recap what we said in the previous article, we have:

**The bad**: Some elements are more difficult to style, requiring more complex CSS or some more specific tricks:

* Checkboxes and radio buttons
* `<input type="search">`

**The ugly**: Some elements can't be styled thoroughly using CSS. These include:

* Elements involved in creating dropdown widgets, including `<select>`, `<option>`, `<optgroup>` and `<datalist>`.
* `<input type="color">`
* Date-related controls such as `<input type="datetime-local">`
* `<input type="range">`
* `<input type="file">`
* `<progress>` and `<meter>`

Let's first talk about the `appearance` property, which is pretty useful for making all of the above more stylable.

appearance: controlling OS-level styling
----------------------------------------

In the previous article we said that historically, the styling of web form controls was largely taken from the underlying operating system, which is part of the problem with customizing the look of these controls.

The `appearance` property was created as a way to control what OS- or system-level styling was applied to web form controls. By far the most helpful value, and probably the only one you'll use, is `none`. This stops any control you apply it to from using system-level styling, as much as possible, and lets you build up the styles yourself using CSS.

For example, let's take the following controls:

```html
<form>
  <p>
    <label for="search">search: </label>
    <input id="search" name="search" type="search" />
  </p>
  <p>
    <label for="text">text: </label>
    <input id="text" name="text" type="text" />
  </p>
  <p>
    <label for="date">date: </label>
    <input id="date" name="date" type="datetime-local" />
  </p>
  <p>
    <label for="radio">radio: </label>
    <input id="radio" name="radio" type="radio" />
  </p>
  <p>
    <label for="checkbox">checkbox: </label>
    <input id="checkbox" name="checkbox" type="checkbox" />
  </p>
  <p><input type="submit" value="submit" /></p>
  <p><input type="button" value="button" /></p>
</form>
```

Applying the following CSS to them removes system-level styling.

```css
input {
  appearance: none;
}
```

The following live example shows you what they look like in your system — default on the left, and with the above CSS applied on the right (find it here also if you want to test it on other systems).

In most cases, the effect is to remove the stylized border, which makes CSS styling a bit easier, but isn't really essential. In a couple of cases — search and radio buttons/checkboxes, it becomes way more useful. We'll look at those now.

### Taming search boxes

`<input type="search">` is basically just a text input, so why is `appearance: none;` useful here? The answer is that Safari search boxes have some styling restrictions — you can't adjust their `height` or `font-size` freely, for example.

This can be fixed using our friend `appearance: none;`, which disables the default appearance:

```css
input[type="search"] {
  appearance: none;
}
```

In the example below, you can see two identical styled search boxes. The right one has `appearance: none;` applied, and the left one doesn't. If you look at it in Safari on macOS you'll see that the left one isn't sized properly.

Interestingly, setting border/background on the search field also fixes this problem. The following styled search doesn't have `appearance: none;` applied, but it doesn't suffer from the same problem in Safari as the previous example.

**Note:** You may have noticed that in the search field, the "x" delete icon, which appears when the value of the search is not null, disappears when the input loses focus in Edge and Chrome, but stays put in Safari. To remove via CSS, you can use `input[type="search"]:not(:focus, :active)::-webkit-search-cancel-button { display: none; }`.

### Styling checkboxes and radio buttons

Styling a checkbox or a radio button is tricky by default. The sizes of checkboxes and radio buttons are not meant to be changed with their default designs, and browsers react very differently when you try.

For example, consider this simple test case:

```html
<label
 ><span><input type="checkbox" name="q5" value="true" /></span> True</label
>
<label
 ><span><input type="checkbox" name="q5" value="false" /></span> False</label
>
```

```css
span {
  display: inline-block;
  background: red;
}

input[type="checkbox"] {
  width: 100px;
  height: 100px;
}
```

Different browsers handle the checkbox and span differently, often ugly ways:

| Browser | Rendering |
| --- | --- |
| Firefox 71 (macOS) | Rounded corners and 1px light grey border |
| Firefox 57 (Windows 10) | Rectangular corners with 1px medium grey border |
| Chrome 77 (macOS), Safari 13, Opera | Rounded corner with 1px medium grey border |
| Chrome 63 (Windows 10) | Rectangular borders with slightly greyish background instead of white. |
| Edge 16 (Windows 10) | Rectangular borders with slightly greyish background instead of white. |

#### Using appearance: none on radios/checkboxes

As we showed before, you can remove the default appearance of a checkbox or radio button altogether with `appearance``:none;` Let's take this example HTML:

```html
<form>
  <fieldset>
    <legend>Fruit preferences</legend>

    <p>
      <label>
        <input type="checkbox" name="fruit" value="cherry" />
        I like cherry
      </label>
    </p>
    <p>
      <label>
        <input type="checkbox" name="fruit" value="banana" disabled />
        I can't like banana
      </label>
    </p>
    <p>
      <label>
        <input type="checkbox" name="fruit" value="strawberry" />
        I like strawberry
      </label>
    </p>
  </fieldset>
</form>
```

Now, let's style these with a custom checkbox design. Let's start by unstyling the original check boxes:

```css
input[type="checkbox"] {
  appearance: none;
}
```

We can use the `:checked` and `:disabled` pseudo-classes to change the appearance of our custom checkbox as its state changes:

```css
input[type="checkbox"] {
  position: relative;
  width: 1em;
  height: 1em;
  border: 1px solid gray;
  /\* Adjusts the position of the checkboxes on the text baseline \*/
  vertical-align: -2px;
  /\* Set here so that Windows' High-Contrast Mode can override \*/
  color: green;
}

input[type="checkbox"]::before {
  content: "✔";
  position: absolute;
  font-size: 1.2em;
  right: -1px;
  top: -0.3em;
  visibility: hidden;
}

input[type="checkbox"]:checked::before {
  /\* Use `visibility` instead of `display` to avoid recalculating layout \*/
  visibility: visible;
}

input[type="checkbox"]:disabled {
  border-color: black;
  background: #ddd;
  color: gray;
}
```

You'll find out more about such pseudo-classes and more in the next article; the above ones do the following:

* `:checked` — the checkbox (or radio button) is in a checked state — the user has clicked/activated it.
* `:disabled` — the checkbox (or radio button) is in a disabled state — it cannot be interacted with.

You can see the live result:

We've also created a couple of other examples to give you more ideas:

* Styled radio buttons: Custom radio button styling.
* Toggle switch example: A checkbox styled to look like a toggle switch.

If you view these checkboxes in a browser that doesn't support `appearance`, your custom design will be lost, but they will still look like checkboxes and be usable.

What can be done about the "ugly" elements?
-------------------------------------------

Now let's turn our attention to the "ugly" controls — the ones that are really hard to thoroughly style. In short, these are drop-down boxes, complex control types like `color` and `datetime-local`, and feedback—oriented controls like `<progress>` and `<meter>`.

The problem is that these elements have very different default looks across browsers, and while you can style them in some ways, some parts of their internals are literally impossible to style.

If you are prepared to live with some differences in look and feel, you can get away with some simple styling to make sizing consistent, uniform styling of things like background-colors, and usage of appearance to get rid of some system-level styling.

Take the following example, which shows a number of the "ugly" form features in action:

This example has the following CSS applied to it:

```css
body {
  font-family: "Josefin Sans", sans-serif;
  margin: 20px auto;
  max-width: 400px;
}

form > div {
  margin-bottom: 20px;
}

select {
  appearance: none;
  width: 100%;
  height: 100%;
}

.select-wrapper {
  position: relative;
}

.select-wrapper::after {
  content: "▼";
  font-size: 1rem;
  top: 3px;
  right: 10px;
  position: absolute;
}

button,
label,
input,
select,
progress,
meter {
  display: block;
  font-family: inherit;
  font-size: 100%;
  margin: 0;
  box-sizing: border-box;
  width: 100%;
  padding: 5px;
  height: 30px;
}

input[type="text"],
input[type="datetime-local"],
input[type="color"],
select {
  box-shadow: inset 1px 1px 3px #ccc;
  border-radius: 5px;
}

label {
  margin-bottom: 5px;
}

button {
  width: 60%;
  margin: 0 auto;
}
```

**Note:** If you want to test these examples across a number of browsers simultaneously, you can find it live here (also see here for the source code).

Also bear in mind that we've added some JavaScript to the page that lists the files selected by the file picker, below the control itself. This is a simplified version of the example found on the `<input type="file">` reference page.

As you can see, we've done fairly well at getting these to look uniform across modern browsers.

We've applied some global normalizing CSS to all the controls and their labels, to get them to size in the same way, adopt their parent font, etc., as mentioned in the previous article:

```css
button,
label,
input,
select,
progress,
meter {
  display: block;
  font-family: inherit;
  font-size: 100%;
  margin: 0;
  box-sizing: border-box;
  width: 100%;
  padding: 5px;
  height: 30px;
}
```

We also added some uniform shadow and rounded corners to the controls on which it made sense:

```css
input[type="text"],
input[type="datetime-local"],
input[type="color"],
select {
  box-shadow: inset 1px 1px 3px #ccc;
  border-radius: 5px;
}
```

On other controls like range types, progress bars, and meters they just add an ugly box around the control area, so it doesn't make sense.

Let's talk about some specifics of each of these types of control, highlighting difficulties along the way.

### Selects and datalists

In modern browsers, selects and datalists are generally not too bad to style provided you don't want to vary the look and feel too much from the defaults.

We've managed to get the basic look of the boxes looking pretty uniform and consistent. The datalist control is `<input type="text">` anyway, so we knew this wouldn't be a problem.

Two things are slightly more problematic. First of all, the select's "arrow" icon that indicates it is a dropdown differs across browsers. It also tends to change if you increase the size of the select box, or resize in an ugly fashion. To fix this in our example we first used our old friend `appearance: none` to get rid of the icon altogether:

```css
select {
  appearance: none;
}
```

We then created our own icon using generated content. We put an extra wrapper around the control, because `::before`/`::after` don't work on `<select>` elements (this is because generated content is placed relative to an element's formatting box, but form inputs work more like replaced elements — their display is generated by the browser and put in place — and therefore don't have one):

```html
<label for="select">Select a fruit</label>
<div class="select-wrapper">
  <select id="select" name="select">
    <option>Banana</option>
    <option>Cherry</option>
    <option>Lemon</option>
  </select>
</div>
```

We then use generated content to generate a little down arrow, and put it in the right place using positioning:

```css
.select-wrapper {
  position: relative;
}

.select-wrapper::after {
  content: "▼";
  font-size: 1rem;
  top: 6px;
  right: 10px;
  position: absolute;
}
```

The second, slightly more important issue is that you don't have control over the box that appears containing the options when you click on the `<select>` box to open it. You can inherit the font set on the parent, but you won't be able to set things like spacing and colors. The same is true for the autocomplete list that appears with `<datalist>`.

If you really need full control over the option styling, you'll have to either use some kind of library to generate a custom control, or build your own custom control, or in the case of select use the `multiple` attribute, which makes all the options appear on the page, sidestepping this particular problem:

```html
<label for="select">Select fruits</label>
<select id="select" name="select" multiple>
  …
</select>
```

Of course, this might also not fit in with the design you are going for, but it's worth noting!

### Date input types

The date/time input types (`datetime-local`, `time`, `week`, `month`) all have the same major associated issue. The actual containing box is as easy to style as any text input, and what we've got in this demo looks fine.

However, the internal parts of the control (e.g. the popup calendar that you use to pick a date, the spinner that you can use to increment/decrement values) are not stylable at all, and you can't get rid of them using `appearance: none;`. If you really need full control over the styling, you'll have to either use some kind of library to generate a custom control, or build your own.

**Note:** It is worth mentioning `<input type="number">` here too — this also has a spinner that you can use to increment/decrement values, so potentially suffers from the same problem. However, in the case of the `number` type the data being collected is simpler, and it is easy to just use a `tel` input type instead which has the appearance of `text`, but displays the numeric keypad in devices with touch keyboards.

### Range input types

`<input type="range">` is annoying to style. You can use something like the following to remove the default slider track completely and replace it with a custom style (a thin red track, in this case):

```css
input[type="range"] {
  appearance: none;
  background: red;
  height: 2px;
  padding: 0;
  outline: 1px solid transparent;
}
```

However, it is very difficult to customize the style of the range control's drag handle — to get full control over range styling you'll need to use a whole bunch of complex CSS code, including multiple non-standard, browser-specific pseudo-elements. Check out Styling Cross-Browser Compatible Range Inputs with CSS on CSS tricks for a detailed write-up of what's needed.

### Color input types

Input controls of type color are not too bad. In supporting browsers, they tend to just give you a block of solid color with a small border.

You can remove the border, just leaving the block of color, using something like this:

```css
input[type="color"] {
  border: 0;
  padding: 0;
}
```

However, a custom solution is the only way to get anything significantly different.

### File input types

Inputs of type file are generally OK — as you saw in our example, it is fairly easy to create something that fits in OK with the rest of the page — the output line that is part of the control will inherit the parent font if you tell the input to do so, and you can style the custom list of file names and sizes in any way you want; we created it after all.

The only problem with file pickers is that the button provided that you press to open the file picker is completely unstylable — it can't be sized or colored, and it won't even accept a different font.

One way around this is to take advantage of the fact that if you have a label associated with a form control, clicking the label will activate the control. So you could hide the actual form input using something like this:

```css
input[type="file"] {
  height: 0;
  padding: 0;
  opacity: 0;
}
```

And then style the label to act like a button, which when pressed will open the file picker as expected:

```css
label[for="file"] {
  box-shadow: 1px 1px 3px #ccc;
  background: linear-gradient(to bottom, #eee, #ccc);
  border: 1px solid rgb(169, 169, 169);
  border-radius: 5px;
  text-align: center;
  line-height: 1.5;
}

label[for="file"]:hover {
  background: linear-gradient(to bottom, #fff, #ddd);
}

label[for="file"]:active {
  box-shadow: inset 1px 1px 3px #ccc;
}
```

You can see the result of the above CSS styling in the below live example (see also styled-file-picker.html live, and the source code).

### Meters and progress bars

`<meter>` and `<progress>` are possibly the worst of the lot. As you saw in the earlier example, we can set them to the desired width relatively accurately. But beyond that, they are really difficult to style in any way. They don't handle height settings consistently between each other and between browsers, you can color the background, but not the foreground bar, and setting `appearance: none` on them makes things worse, not better.

It is easier to just create your own custom solution for these features, if you want to be able to control the styling, or use a third-party solution such as progressbar.js.

The article How to build custom form controls provides an example of how to build a custom designed select with HTML, CSS, and JavaScript.

Summary
-------

While there are still difficulties using CSS with HTML forms, there are ways to get around many of the problems. There are no clean, universal solutions, but modern browsers offer new possibilities. For now, the best solution is to learn more about the way the different browsers support CSS when applied to HTML form controls.

In the next article of this module, we will explore the different UI pseudo-classes available to us in modern browsers for styling forms in different states.

* Previous
* Overview: Forms
* Next
### Advanced Topics

* How to build custom form controls
* Sending forms through JavaScript
* Property compatibility table for form widgets


Sending forms through JavaScript - Learn web development

Sending forms through JavaScript
================================

When a user submits an HTML form, for example by clicking the submit button, the browser makes an HTTP request to send the data in the form. But instead of this declarative approach, web apps sometimes use JavaScript APIs such as `fetch()` to send data programmatically to an endpoint that expects a form submission. This article explains why this is an important use case and how to do it.

Why use JavaScript to submit form data?
---------------------------------------

Standard HTML form submission, as described in our article on sending form data, loads the URL where the data was sent, which means the browser window navigates with a full page load.

However, many web apps, especially progressive web apps and single-page apps, use JavaScript APIs to request data from the server and update the relevant parts of the page, avoiding the overhead of a full page load.

For this reason, when these web apps want to submit form data, they use HTML forms only to collect input from the user, but not for data submission. When the user tries to send the data, the application takes control and sends the data using a JavaScript API such as `fetch()`.

The problem with JavaScript form submission
-------------------------------------------

If the server endpoint to which the web app sends the form data is under the web app developer's control, then they can send the form data in any way they choose: for example, as a JSON object.

However, if the server endpoint is expecting a form submission, the web app must encode the data in a particular way. For example, if the data is just textual, it is made of URL-encoded lists of key/value pairs and sent with a `Content-Type` of `application/x-www-form-urlencoded`. If the form includes binary data, it must be sent using the `multipart/form-data` content type.

The `FormData` interface takes care of the process of encoding data in this way, and in the rest of this article we'll provide a quick introduction to `FormData`. For more details, see our guide to Using FormData objects.

Building a `FormData` object manually
-------------------------------------

You can populate a `FormData` object by calling the object's `append()` method for each field you want to add, passing in the field's name and value. The value can be a string, for text fields, or a `Blob`, for binary fields, including `File` objects.

In the following example we send data as a form submission when the user clicks a button:

```js
async function sendData(data) {
  // Construct a FormData instance
  const formData = new FormData();

  // Add a text field
  formData.append("name", "Pomegranate");

  // Add a file
  const selection = await window.showOpenFilePicker();
  if (selection.length > 0) {
    const file = await selection[0].getFile();
    formData.append("file", file);
  }

  try {
    const response = await fetch("https://example.org/post", {
      method: "POST",
      // Set the FormData instance as the request body
      body: formData,
    });
    console.log(await response.json());
  } catch (e) {
    console.error(e);
  }
}

const send = document.querySelector("#send");
send.addEventListener("click", sendData);
```

1. We first construct a new, empty, `FormData` object.
2. Next, we call `append()` twice, to add two items to the `FormData` object: a text field and a file.
3. Finally, we make a `POST` request using the `fetch()` API, setting the `FormData` object as the request body.

Note that we don't have to set the `Content-Type` header: the correct header is automatically set when we pass a `FormData` object into `fetch()`.

Associating a `FormData` object and a `<form>`
----------------------------------------------

If the data you're submitting is really coming from a `<form>`, you can populate the `FormData` instance by passing the form into the `FormData` constructor.

Suppose our HTML declares a `<form>` element:

```html
<form id="userinfo">
  <div>
    <label for="username">Enter your name:</label>
    <input type="text" id="username" name="username" value="Dominic" />
  </div>

  <div>
    <label for="avatar">Select an avatar</label>
    <input type="file" id="avatar" name="avatar" required />
  </div>
  <input type="submit" value="Submit" />
</form>
```

The form includes a text input, a file input, and a submit button.

The JavaScript is as follows:

```js
const form = document.querySelector("#userinfo");

async function sendData() {
  // Associate the FormData object with the form element
  const formData = new FormData(form);

  try {
    const response = await fetch("https://example.org/post", {
      method: "POST",
      // Set the FormData instance as the request body
      body: formData,
    });
    console.log(await response.json());
  } catch (e) {
    console.error(e);
  }
}

// Take over form submission
form.addEventListener("submit", (event) => {
  event.preventDefault();
  sendData();
});
```

We add a submit event handler for the form element. This first calls `preventDefault()` to prevent the browser's built-in form submission, so we can take over. Then we call `sendData()`, which retrieves the form element and passes it into the `FormData` constructor.

After that, we send the `FormData` instance as an HTTP `POST` request, using `fetch()`.

See also
--------

### Learning path

* Your first HTML form
* How to structure an HTML form
* The native form widgets
* HTML5 input types
* Additional form controls
* UI pseudo-classes
* Styling HTML forms
* Form data validation
* Sending form data
### Advanced Topics

* **Sending forms through JavaScript**
* How to build custom form widgets
* HTML forms in legacy browsers
* Advanced styling for HTML forms
* Property compatibility table for form widgets


Test your skills: Form validation - Learn web development

Test your skills: Form validation
=================================

The aim of this skill test is to assess whether you've understood our Client-side form validation article.

**Note:** You can try solutions in the interactive editors on this page or in an online editor such as CodePen, JSFiddle, or Glitch.

If you get stuck, you can reach out to us in one of our communication channels.

Form validation 1
-----------------

In this task, we are providing you with a simple support query form, and we want you to add some validation features to it:

1. Make all of the input fields mandatory to complete before the form can be submitted.
2. Change the type of the "Email address" and "Phone number" fields to make the browser apply some more specific validation suitable for the data being asked for.
3. Give the "User name" field a required length of between 5 and 20 characters, the "Phone number" field a maximum length of 15 characters, and the "Comment" field a maximum length of 200 characters.

Try submitting your form — it should refuse to submit until the above constraints are followed, and give suitable error messages. To help, you might want to consider adding some simple CSS to show when a form field is valid or invalid.

Download the starting point for this task to work in your own editor or in an online editor.

Form validation 2
-----------------

Now we want you to take the same form you saw in the previous task (use your previous answer if you want to), and add some more specific pattern validation to the first three fields using regular expressions.

1. All of the user names in our application consist of a single letter, followed by a dot, followed by three or more letters or numbers. All letters should be lowercase.
2. All of the email addresses for our users consist of one or more letters (lower or upper case) or numbers, followed by "@bigcorp.eu".
3. Remove the length validation from the phone number field if it is present, and set it so that it accepts 10 digits — either 10 digits in a row, or a pattern of three digits, three digits, then four digits, separated by either spaces, dashes, or dots.

**Note:** Regular expressions are really challenging if you are new to them, but don't despair — have a go and see where you get to; there is no shame in asking for some help. You can find everything you need to answer these questions at our regular expression reference, and by searching on Stack Overflow.

Again, to help you might want to consider adding some simple CSS to show when a form field is valid or invalid.

Download the starting point for this task to work in your own editor or in an online editor.

Form validation 3
-----------------

In our final task for this set, we are providing you with a similar example to what you saw in the accompanying article — a simple email address entry input. We would like you to use the constraint validation API, plus some form validation attributes, to program some custom error messages.

1. Make the input mandatory to fill in, and give it a minimum length of 10 characters.
2. Add an event listener that checks whether the inputted value is an email address, and whether it is long enough. If it doesn't look like an email address or is too short, provide the user with appropriate custom error messages.

Download the starting point for this task to work in your own editor or in an online editor.


Your first form - Learn web development

Your first form
===============

* Overview: Forms
* Next

 The first article in our series provides you with your very first experience of creating a web form, including designing a simple form, implementing it using the right HTML form controls and other HTML elements, adding some very simple styling via CSS, and describing how data is sent to a server.
 We'll expand on each of these subtopics in more detail later on in the module.

|  |  |
| --- | --- |
| Prerequisites: |
 A basic
 understanding of HTML.
  |
| Objective: |
 To gain familiarity with what web forms are, what they are used for, how
 to think about designing them, and the basic HTML elements you'll need
 for simple cases.
  |

What are web forms?
-------------------

**Web forms** are one of the main points of interaction between a user and a website or application.
 Forms allow users to enter data, which is generally sent to a web server for processing and storage (see Sending form data later in the module), or used on the client-side to immediately update the interface in some way (for example, add another item to a list, or show or hide a UI feature).

 A web form's HTML is made up of one or more **form controls** (sometimes called **widgets**), plus some additional elements to help structure the overall form — they are often referred to as **HTML forms**.
 The controls can be single or multi-line text fields, dropdown boxes, buttons, checkboxes, or radio buttons, and are mostly created using the `<input>` element, although there are some other elements to learn about too.

Form controls can also be programmed to enforce specific formats or values to be entered (**form validation**), and paired with text labels that describe their purpose to both sighted and visually impaired users.

Designing your form
-------------------

Before starting to code, it's always better to step back and take the time to think about your form. Designing a quick mockup will help you to define the right set of data you want to ask your user to enter. From a user experience (UX) point of view, it's important to remember that the bigger your form, the more you risk frustrating people and losing users. Keep it simple and stay focused: ask only for the data you absolutely need.

 Designing forms is an important step when you are building a site or application.
 It's beyond the scope of this article to cover the user experience of forms, but if you want to dig into that topic you should read the following articles:

* Smashing Magazine has some good articles about forms UX, including an older but still relevant Extensive Guide To Web Form Usability article.
* UXMatters is also a very thoughtful resource with good advice from basic best practices to complex concerns such as multipage forms.

In this article, we'll build a simple contact form. Let's make a rough sketch.

![The form to build, roughly sketch](/en-US/docs/Learn/Forms/Your_first_form/form-sketch-low.jpg)

Our form will contain three text fields and one button. We are asking the user for their name, their email and the message they want to send. Hitting the button will send their data to a web server.

Active learning: Implementing our form HTML
-------------------------------------------

Ok, let's have a go at creating the HTML for our form. We will use the following HTML elements: `<form>`, `<label>`, `<input>`, `<textarea>`, and `<button>`.

Before you go any further, make a local copy of our simple HTML template — you'll enter your form HTML into here.

### The `<form>` element

All forms start with a `<form>` element, like this:

```html
<form action="/my-handling-form-page" method="post">…</form>
```

This element formally defines a form. It's a container element like a `<section>` or `<footer>` element, but specifically for containing forms; it also supports some specific attributes to configure the way the form behaves. All of its attributes are optional, but it's standard practice to always set at least the `action` and `method` attributes:

* The `action` attribute defines the location (URL) where the form's collected data should be sent when it is submitted.
* The `method` attribute defines which HTTP method to send the data with (usually `get` or `post`).

**Note:** We'll look at how those attributes work in our Sending form data article later on.

For now, add the above `<form>` element into your HTML `<body>`.

### The `<label>`, `<input>`, and `<textarea>` elements

Our contact form is not complex: the data entry portion contains three text fields, each with a corresponding `<label>`:

* The input field for the name is a single-line text field.
* The input field for the email is an input of type email: a single-line text field that accepts only email addresses.
* The input field for the message is a `<textarea>`; a multiline text field.

In terms of HTML code we need something like the following to implement these form widgets:

```html
<form action="/my-handling-form-page" method="post">
  <ul>
    <li>
      <label for="name">Name:</label>
      <input type="text" id="name" name="user\_name" />
    </li>
    <li>
      <label for="mail">Email:</label>
      <input type="email" id="mail" name="user\_email" />
    </li>
    <li>
      <label for="msg">Message:</label>
      <textarea id="msg" name="user\_message"></textarea>
    </li>
  </ul>
</form>
```

Update your form code to look like the above.

 The `<li>` elements are there to conveniently structure our code and make styling easier (see later in the article).
 For usability and accessibility, we include an explicit label for each form control.
 Note the use of the `for` attribute on all `<label>` elements, which takes as its value the `id` of the form control with which it is associated — this is how you associate a form control with its label.

 There is great benefit to doing this — it associates the label with the form control, enabling mouse, trackpad, and touch device users to click on the label to activate the corresponding control, and it also provides an accessible name for screen readers to read out to their users.
 You'll find further details of form labels in How to structure a web form.

 On the `<input>` element, the most important attribute is the `type` attribute.
 This attribute is extremely important because it defines the way the `<input>` element appears and behaves.
 You'll find more about this in the Basic native form controls article later on.

* In our simple example, we use the value text for the first input — the default value for this attribute.
 It represents a basic single-line text field that accepts any kind of text input.
* For the second input, we use the value email, which defines a single-line text field that only accepts a well-formed email address.
 This turns a basic text field into a kind of "intelligent" field that will perform some validation checks on the data typed by the user.
 It also causes a more appropriate keyboard layout for entering email addresses (e.g. with an @ symbol by default) to appear on devices with dynamic keyboards, like smartphones.
 You'll find out more about form validation in the client-side form validation article later on.

 Last but not least, note the syntax of `<input>` vs. `<textarea></textarea>`.
 This is one of the oddities of HTML.
 The `<input>` tag is a void element, meaning that it doesn't need a closing tag.
 `<textarea>` is not a void element, meaning it should be closed with the proper ending tag.
 This has an impact on a specific feature of forms: the way you define the default value.
 To define the default value of an `<input>` element you have to use the `value` attribute like this:

```html
<input type="text" value="by default this element is filled with this text" />
```

On the other hand, if you want to define a default value for a `<textarea>`, you put it between the opening and closing tags of the `<textarea>` element, like this:

```html
<textarea>
by default this element is filled with this text
</textarea>
```

### The `<button>` element

 The markup for our form is almost complete; we just need to add a button to allow the user to send, or "submit", their data once they have filled out the form.
 This is done by using the `<button>` element; add the following just above the closing `</ul>` tag:

```html
<li class="button">
  <button type="submit">Send your message</button>
</li>
```

The `<button>` element also accepts a `type` attribute — this accepts one of three values: `submit`, `reset`, or `button`.

* A click on a `submit` button (the default value) sends the form's data to the web page defined by the `action` attribute of the `<form>` element.
* A click on a `reset` button resets all the form widgets to their default value immediately. From a UX point of view, this is considered bad practice, so you should avoid using this type of button unless you really have a good reason to include one.
* A click on a `button` button does *nothing*! That sounds silly, but it's amazingly useful for building custom buttons — you can define their chosen functionality with JavaScript.

**Note:** You can also use the `<input>` element with the corresponding `type` to produce a button, for example `<input type="submit">`. The main advantage of the `<button>` element is that the `<input>` element only allows plain text in its label whereas the `<button>` element allows full HTML content, allowing more complex, creative button content.

Basic form styling
------------------

Now that you have finished writing your form's HTML code, try saving it and looking at it in a browser. At the moment, you'll see that it looks rather ugly.

**Note:** If you don't think you've got the HTML code right, try comparing it with our finished example — see first-form.html (also see it live).

Forms are notoriously tricky to style nicely. It is beyond the scope of this article to teach you form styling in detail, so for the moment we will just get you to add some CSS to make it look OK.

First of all, add a `<style>` element to your page, inside your HTML head. It should look like so:

```html
<style>
 …
</style>
```

Inside the `style` tags, add the following CSS:

```css
form {
  /\* Center the form on the page \*/
  margin: 0 auto;
  width: 400px;
  /\* Form outline \*/
  padding: 1em;
  border: 1px solid #ccc;
  border-radius: 1em;
}

ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

form li + li {
  margin-top: 1em;
}

label {
  /\* Uniform size & alignment \*/
  display: inline-block;
  width: 90px;
  text-align: right;
}

input,
textarea {
  /\* To make sure that all text fields have the same font settings
 By default, textareas have a monospace font \*/
  font: 1em sans-serif;

  /\* Uniform text field size \*/
  width: 300px;
  box-sizing: border-box;

  /\* Match form field borders \*/
  border: 1px solid #999;
}

input:focus,
textarea:focus {
  /\* Additional highlight for focused elements \*/
  border-color: #000;
}

textarea {
  /\* Align multiline text fields with their labels \*/
  vertical-align: top;

  /\* Provide space to type some text \*/
  height: 5em;
}

.button {
  /\* Align buttons with the text fields \*/
  padding-left: 90px; /\* same size as the label elements \*/
}

button {
  /\* This extra margin represent roughly the same space as the space
 between the labels and their text fields \*/
  margin-left: 0.5em;
}
```

Save and reload, and you'll see that your form should look much less ugly.

**Note:** You can find our version on GitHub at first-form-styled.html (also see it live).

Sending form data to your web server
------------------------------------

 The last part, and perhaps the trickiest, is to handle form data on the server side.
 The `<form>` element defines where and how to send the data thanks to the `action` and `method` attributes.

 We provide a `name` attribute for each form control.
 The names are important on both the client- and server-side; they tell the browser which name to give each piece of data and, on the server side, they let the server handle each piece of data by name.
 The form data is sent to the server as name/value pairs.

 To name the data in a form, you need to use the `name` attribute on each form widget that will collect a specific piece of data.
 Let's look at some of our form code again:

```html
<form action="/my-handling-form-page" method="post">
  <ul>
    <li>
      <label for="name">Name:</label>
      <input type="text" id="name" name="user\_name" />
    </li>
    <li>
      <label for="mail">Email:</label>
      <input type="email" id="mail" name="user\_email" />
    </li>
    <li>
      <label for="msg">Message:</label>
      <textarea id="msg" name="user\_message"></textarea>
    </li>

    …
  </ul>
</form>
```

 In our example, the form will send 3 pieces of data named "`user_name`", "`user_email`", and "`user_message`".
 That data will be sent to the URL "`/my-handling-form-page`" using the HTTP `POST` method.

 On the server side, the script at the URL "`/my-handling-form-page`" will receive the data as a list of 3 key/value items contained in the HTTP request.
 The way this script will handle that data is up to you.
 Each server-side language (PHP, Python, Ruby, Java, C#, etc.) has its own mechanism of handling form data.
 It's beyond the scope of this guide to go deeply into that subject, but if you want to know more, we have provided some examples in our Sending form data article later on.

Summary
-------

Congratulations, you've built your first web form. It looks like this live:
```

<form action="/my-handling-form-page" method="post">
  <div>
    <label for="name">Name:</label>
    <input type="text" id="name" name="user\_name" />
  </div>

  <div>
    <label for="mail">Email:</label>
    <input type="email" id="mail" name="user\_email" />
  </div>

  <div>
    <label for="msg">Message:</label>
    <textarea id="msg" name="user\_message"></textarea>
  </div>

  <div class="button">
    <button type="submit">Send your message</button>
  </div>
</form>
```

```
form {
  /\* Just to center the form on the page \*/
  margin: 0 auto;
  width: 400px;

  /\* To see the limits of the form \*/
  padding: 1em;
  border: 1px solid #ccc;
  border-radius: 1em;
}

div + div {
  margin-top: 1em;
}

label {
  /\* To make sure that all label have the same size and are properly align \*/
  display: inline-block;
  width: 90px;
  text-align: right;
}

input,
textarea {
  /\* To make sure that all text field have the same font settings
 By default, textarea are set with a monospace font \*/
  font: 1em sans-serif;

  /\* To give the same size to all text field \*/
  width: 300px;

  -moz-box-sizing: border-box;
  box-sizing: border-box;

  /\* To harmonize the look & feel of text field border \*/
  border: 1px solid #999;
}

input:focus,
textarea:focus {
  /\* To give a little highlight on active elements \*/
  border-color: #000;
}

textarea {
  /\* To properly align multiline text field with their label \*/
  vertical-align: top;

  /\* To give enough room to type some text \*/
  height: 5em;

  /\* To allow users to resize any textarea vertically
 It works only on Chrome, Firefox and Safari \*/
  resize: vertical;
}

.button {
  /\* To position the buttons to the same position of the text fields \*/
  padding-left: 90px; /\* same size as the label elements \*/
}

button {
  /\* This extra margin represent the same space as the space between
 the labels and their text fields \*/
  margin-left: 0.5em;
}
```

That's only the beginning, however — now it's time to take a deeper look. Forms have way more power than what we saw here and the other articles in this module will help you to master the rest.

* Overview: Forms
* Next
### Advanced Topics

* How to build custom form controls
* Sending forms through JavaScript
* Property compatibility table for form widgets


Test your skills: HTML5 controls - Learn web development

Test your skills: HTML5 controls
================================

The aim of this skill test is to assess whether you've understood our The HTML5 input types article.

**Note:** You can try solutions in the interactive editors on this page or in an online editor such as CodePen, JSFiddle, or Glitch.

If you get stuck, you can reach out to us in one of our communication channels.

HTML controls 1
---------------

First, let's explore some input types. Create appropriate inputs for a user to update their details for:

1. Email
2. Website
3. Phone number
4. Favorite color

Try updating the live code below to recreate the finished example:

Download the starting point for this task to work in your own editor or in an online editor.

HTML controls 2
---------------

Next, we want you to implement a slider control to allow the user to choose a maximum number of people to invite to their party.

1. Implement a basic slider control to go along with the provided label.
2. Give it a minimum value of 1, maximum value of 30, initial value of 10 and element `id` of `max-invite`.
3. Create a corresponding output element to put the current value of the slider into. Give it a class of `invite-output`, and semantically associate it with the input. If you do this correctly, the JavaScript included on the page will automatically update the output value when the slider is moved.

Try updating the live code below to recreate the finished example:

Download the starting point for this task to work in your own editor or in an online editor.