W3docs

CSS :optional Pseudo Class

Use the :optional CSS pseudo-class for selecting the elements that are optional. Read about the pseudo-class and practice with examples.

The :optional pseudo-class matches every form control that the user is not required to fill in. It is the exact opposite of :required: a control matches one or the other, never both.

A form control is "optional" simply because it lacks the required attribute. This page explains which elements :optional applies to, how it differs from related pseudo-classes, and how to use it to give users a visual hint about which fields they can safely skip.

Which elements does :optional match?

Only the three form controls that accept the required attribute can match :optional:

  • <input> (except type="hidden", type="range", type="color", buttons, and similar types that can never be required)
  • <select>
  • <textarea>

Any of these without a required attribute is matched by :optional. Elements that cannot be required at all — such as <div>, <p>, or a submit <button> — are never matched.

:optional vs :required

These two pseudo-classes partition every requirable control:

ControlMatched by :requiredMatched by :optional
<input required>yesno
<input>noyes
<select required>yesno
<textarea>noyes

Because the two never overlap, a common pattern is to leave optional fields neutral and highlight only required ones — or, as in the example below, fade optional fields so they recede visually.

Syntax

:optional {
  /* CSS declarations */
}

You can chain :optional with other selectors and pseudo-classes (e.g. :hover, :focus) and with pseudo-elements (e.g. ::after) to build richer states:

input:optional:focus {
  outline: 2px solid #1c87c9;
}

Example

The example below styles optional inputs with a muted, semi-transparent look that brightens on hover, while required inputs get a bold bottom border so the difference is obvious at a glance:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
    <style>
      .example {
        margin: 40px auto;
        max-width: 400px;
      }
      label,
      button {
        display: block;
        width: 100%;
        margin-bottom: 1.5em;
      }
      input,
      select,
      button {
        padding: .4em 1em;
      }
      input,
      select {
        border: 1px solid #666666;
      }
      input:optional,
      select:optional {
        background-color: #eeeeee;
        color: #666666;
        opacity: 0.5;
        transition: .3s;
      }
      input:optional:hover,
      select:optional:hover {
        opacity: 1;
      }
      input:required,
      textarea:required {
        border-bottom: 3px solid #1c87c9;
      }
    </style>
  </head>
  <body>
    <h2>:optional selector example</h2>
    <div class="example">
      <form action="#">
        <label>
          <input type="text" required />Name *
        </label>
        <label>
          <input type="email" required />Email *
        </label>
        <label>
          <input type="tel" />Phone (optional)
        </label>
        <label>
          <input type="url" />Address (optional)
        </label>
      </form>
    </div>
  </body>
</html>

Here both :optional and :required are used together so the two field types are easy to tell apart.

Gotchas

  • Submit buttons are not optional. A <button> or <input type="submit"> cannot be required, so it never matches :optional. Style buttons with their own selector.
  • Validation states are separate. :optional only reports whether a field is required — not whether its value is valid. For that, use :valid and :invalid.
  • It updates live. If you toggle the required attribute with JavaScript, the browser re-evaluates :optional/:required immediately, so the styling follows.

Practice

Practice
Which form controls are matched by the CSS :optional pseudo-class?
Which form controls are matched by the CSS :optional pseudo-class?
Was this page helpful?