Forms

Contents:

Missing.css aims to style HTML nicely without authors needing to concern themselves over anything other than using HTML tags with correct meanings, but this is not always feasible. Forms are a particularly complex part of HTML, with multiple ways to mark up the same semantics. For instance, you can label an element in multiple ways:

<form>
  <label>Name <input></label>
  <!-- or... -->
  <label for=adr>Address</label> <input id=adr>
</form>

Because of this, it's not really possible to write a stylesheet that will work with any HTML form.

Missing.css will work best on forms that follow these markup conventions:

§ Inputs and labels

Inputs inside labels will be display:inline. Inputs outside labels will be display:block.

Input placeholders are styled with text-align:end to better distinguish them from actual input.

Example: Placeholder markup
<form class="flex-row">
  <div>
    <label for=category>Category:</label>
    <select id=category placeholder="Select a category...">
      <option>Blues</option>
      <!-- ... -->
    </select>
  </div>
  <div>
    <label for=search>Search:</label>
    <input id=search type=search placeholder="Search...">
  </div>
  <div>
    <label for=text>Text:</label>
    <input id=text type=text placeholder="Type...">
  </div>
</div>

§ Buttons

Wrap a <button> in a <strong> tag to get a primary button. Buttons support the aria-pressed and aria-expanded attributes.

Buttons, .<button> masquerades, and <input type=file> all support colorways as well.

Example: Button markup
<script>
  const toggle = el => (el.ariaPressed = (el.ariaPressed !== 'true'))
</script>

<section tabindex=0 class="overflow:auto">
  <table id=button-table class="table">
  <caption>Button demonstration</caption>
  <thead>
    <tr><th><th><th><code>.info</code><th><code>.ok</code><th><code>.warn</code><th><code>.bad</code>
  <tbody>
    <tr><th scope=row><code>&lt;button&gt;</code>
        <td><button>Plain</button>
        <td><button class="ok">Open</button>
        <!-- ... -->
    <tr><th scope=row class="padding-inline-start"><code>:disabled</code>
        <td><button disabled>Plain</button>
        <td><button disabled class="ok">Open</button>
        <!-- ... -->
    <tr><th scope=row class="padding-inline-start"><code>[aria-pressed=true]</code>
        <td><button aria-pressed=true onclick="toggle(this)">Plain</button>
        <td><button aria-pressed=true class="ok" onclick="toggle(this)">Open</button>
        <!-- ... -->
    <tr><th scope=row><code>&lt;strong&gt;&lt;button&gt;</code>
        <td><strong><button>Plain</button></strong>
        <td><strong><button class="ok">Open</button></strong>
        <!-- ... -->
    <tr><th scope=row class="padding-inline-start"><code>:disabled</code>
        <td><strong><button disabled>Plain</button></strong>
        <td><strong><button disabled class="ok">Open</button></strong>
        <!-- ... -->
    <tr><th scope=row class="padding-inline-start"><code>[aria-pressed=true]</code>
        <td><strong><button aria-pressed=true onclick="toggle(this)">Plain</button></strong>
        <td><strong><button aria-pressed=true class="ok" onclick="toggle(this)">Open</button></strong>
        <!-- ... -->
    <tr><th scope=row><code>&lt;a class="&lt;button&gt;"&gt;</code>
        <td><a href=#button-table class="<button>">Plain</button>
        <td><a href=#button-table class="ok <button>">Open</button>
        <!-- ... -->
  </table>
</section>

Button demonstration
.info.ok.warn.bad
<button>
:disabled
[aria-pressed=true]
<strong><button>
:disabled
[aria-pressed=true]
<a class="<button>"> Plain Info Open Reset Close
Example: File input button markup

§ Tabular forms

You can use the .table and .rows classes to create a form with inputs lined up like cells of a table.

Example: Tabular form markup
<form class="table rows">
  <p><label for=inp>Label</label> <input id=inp></p>
  ...

§ Labeling radio buttons

The accepted way to label a group of radio buttons is to use <fieldset> and <legend>:

<fieldset>
  <legend>Color</legend>
  <ul>
    <li><label><input type=radio name=color value="ff0000">Red</label>
    <li><label><input type=radio name=color value="00ff00">Green</label>
    <li><label><input type=radio name=color value="0000ff">Blue</label>
  </ul>
</fieldset>

This works in missing.css, but these two elements are [notorious] for being hard to style. You can use the following pattern instead, which will work with tabular forms. Notice that the wrapper has role=radiogroup and its aria-labelledby value refers to the id of the label for the whole radiogroup.

Example: Radio group markup for tabular forms
<div role=radiogroup aria-labelledby=color-lbl>
  <span id=color-lbl>Color</span>
  <div>
    <div><label><input type=radio name=color value="ff0000"> Red</label></div>
    <div><label><input type=radio name=color value="00ff00"> Green</label></div>
    <div><label><input type=radio name=color value="0000ff"> Blue</label></div>
  </div>
</div>

Color

§ Select

Missing.css will attempt to style <select> elements consistently across browsers. Colorway support is limited until browser support for custom selects improves.

Example: Select dropdown markup
<form class="flex-switch">
  <div>
  <label for=none>None:</label>
  <select id=none>
    <option>One</option>
    <option>Two</option>
    <option>Three</option>
  </select>
  </div>
  <!-- ... -->
  <div>
  <label for=bad>Bad:</label>
  <select id=bad class="bad">
    <option>One</option>
    <option>Two</option>
    <option>Three</option>
  </select>
  </div>
</form>

<span class="aestheticbreak"></span>

<form class="flex-switch">
  <!-- ... -->
  <label for=info>Info:
  <select id=info class="info color bg">
    <option>One</option>
    <option>Two</option>
    <option>Three</option>
  </select>
  <-- ... -->
</form>


§ Progress bar

Create a progress bar using the <progress> element. This element should be used to represent how much of a specific, ongoing process has been completed. Be sure to add a <label> for accessibility (in conjunction with .vh or <v-h> if you like).

The element can be put in an indeterminate state by not including the value attribute. Indeterminate <progress> elements will show a pending animation if the user does not have @prefers-reduced-motion set.

The element can be styled by setting --border-width, --border-style, and --border-radius variables directly on the <progress> element. When not explicitly set, the element inherits from --interactive-border-width, --interactive-border-style, and --tab-border-radius.

For full-width progress bars, use the .width:100% utility class. Colorways are supported.

Example: Progress bar markup
<div class="flex-column">
   
  <label for=p1 class="vh">Upload progress...</label>
  <progress id=p1 value=0.5 class="width:100%"></progress>

  <label for=p2>LCARS Scan...</label>
  <progress id=p2 class="ok width:100%" value=0.25 style="height: 1.5em; --border-width: 6px; --border-style: double; --border-radius: 0 .5em"></progress>

  <label for=p3>Virus progress...</label>
  <progress id=p3 class="warn width:100%" value=0.75 style="--border-width: 3px; --border-style: inset; --border-radius: 0 .5rem .5rem .5rem"></progress>

  <label for=p4>Indeterminate Cylon</label>
  <progress id=p4 class="bad" style="width: 3em;">Indeterminate Cylon</progress>

</div>

Indeterminate Cylon

§ Meter

Use the <meter> element to create a meter guage. This element is used to indicate a measurement within a known range and is semantically differen from the <progress> element.

Similar to the <progress> element, you can style a <meter> by setting --border-width, --border-style, and --border-radius directly on the element. The <meter> element derives its colors from the .ok, .warn, and .bad colorways.

Warning: Due to cross-browser implementation differences, colorways are only fully supported in browsers that pass the @supports (selector(:-moz-meter-optimum)) check. The color of the meter bar is correctly set in all browsers according to the values of --ok-fg, --warn-fg, and --bad-fg. However, only browsers passing the @supports rule will also have the appropriate colorway background and border colors.

A suitable fallback choice has been made for these colors (--plain-bg for the background and --interactive-bg for the border) until browser support improves.

Example: Value in optimum range
<strong>Disk usage (optimum is a medium amount of usage)</strong>
<label for=disk1>60GB Used:</label>
<meter id=disk1 min=0 max=100 value=60 low=30 high=70 optimum=50>60GB of 100GB</meter>

<strong>Battery level (optimum is full)</strong>
<label for=battery1>85% Charged:</label>
<meter id=battery1 min=0 max=100 value=85 low=20 high=70 optimum=100>85% charged</meter>

<strong>Temperature (optimum is low)</strong>
<label for=temp1>15°C:</label>
<meter id=temp1 min=0 max=50 value=15 low=20 high=30 optimum=0>15°C</meter>

Disk usage (optimum is a medium amount of usage) 60GB of 100GB

Battery level (optimum is full) 85% charged

Temperature (optimum is low) 15°C

Example: Value in sub-optimum range
<strong>Disk usage (getting full)</strong>
<label for=disk2>80GB Used:</label>
<meter id=disk2 min=0 max=100 value=80 low=30 high=70 optimum=50>80GB of 100GB</meter>

<strong>Battery level (getting low)</strong>
<label for=battery2>25% Charged:</label>
<meter id=battery2 min=0 max=100 value=25 low=20 high=70 optimum=100>15% charged</meter>

<strong>Temperature (overheating)</strong>
<label for=temp2>40°C:</label>
<meter id=temp2 min=0 max=50 value=40 low=10 high=30 optimum=0>40°C</meter>

<strong>Exam score (failing)</strong>
<label for=exam1>20% Score:</label>
<meter id=exam1 min=0 max=100 value=20 low=40 high=80 optimum=100>20% score</meter>

Disk usage (getting full) 80GB of 100GB

Battery level (getting low) 15% charged

Temperature (overheating) 40°C

Exam score (failing) 20% score