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-switch">
  <div>
    <label for=category>Category:</label>
    <select id=category placeholder="Select a category...">
      <option>Blues
      <!-- ... -->
    </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></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>&lt;button></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>"></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. Tabular forms default to wide inputs, but can be overridden with the .narrow-inputs utility class.

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
<form class="table rows narrow-inputs">
  <div>
    <label for=item>Item</label>
    <select id=item>
      <option>Wallet
      ...
    </select>
  </div>
  <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>
</form>