Building up a form takes time, but should be a simple case of combining all the elements here in a sensible way.

The basic unit in forms is the form-element. This is a molecule, made up of one or more atoms. The atoms can be an input, a textarea, a number of checkbox or radio buttons, or a select dropdown. It combines a label with these form elements and boxes them all up in a handy-sized div.

Firstly, a few different input types (note the hidden type at the end):

<div class="c-form__element">
  <label class="c-form__label" for="a">Name</label>
  <input class="c-form__input c-form__input--text" type="text" id="a" name="a" placeholder="Enter your name" />
</div>
<div class="c-form__element">
  <label class="c-form__label" for="b">Email</label>
  <input class="c-form__input c-form__input--email" type="email" id="b" name="b" />
</div>
<div class="c-form__element">
  <label class="c-form__label" for="c">Image</label>
  <input class="c-form__input c-form__input--file" type="file" id="c" name="c" />
</div>
<div class="c-form__element">
  <label class="c-form__label" for="d">Password</label>
  <input class="c-form__input c-form__input--password" type="password" id="d" name="d" />
</div>
<div class="c-form__element">
  <label class="c-form__label" for="e">Website</label>
  <input class="c-form__input c-form__input--url" type="url" id="e" name="e" value="http://" />
</div>
<div class="c-form__element">
  <label class="c-form__label" for="f">Phone</label>
  <input class="c-form__input c-form__input--tel" type="tel" id="f" name="f" />
</div>
<div class="c-form__element">
  <label class="c-form__label" for="f2">Search</label>
  <input class="c-form__input c-form__input--search" type="search" id="f2" name="f2" />
</div>
<div class="c-form__element">
  <label class="c-form__label" for="g">Your Comment</label>
  <textarea class="c-form__input c-form__input--textarea" id="g" name="g" placeholder="Please add a well-written, grammatically correct comment"></textarea>
</div>
<div class="c-form__element">
  <label class="c-form__label" for="g">Your Comment</label>
  <textarea class="c-form__input c-form__input--textarea c-form__input--textarea--double" id="g" name="g" placeholder="Please add a slightly longer well-written, grammatically correct comment"></textarea>
</div>
<div class="c-form__element">
  <label class="c-form__label" for="g">Your Comment</label>
  <textarea class="c-form__input c-form__input--textarea c-form__input--textarea--treble" id="g" name="g" placeholder="Please add a very long well-written, grammatically correct comment"></textarea>
</div>
<div class="c-form__element">
  <input class="c-form__input c-form__input--hidden" type="hidden" id="h" name="h" value="this is a secret value" />
</div>

Of course, you're not just going to need inputs and textareas. Checkbox lists, select dropdowns and radio lists are molecules, made up of an array of checkbox, option or radio atoms.

<div class="c-form__element c-form__element--select">
  <label class="c-form__label" for="i">What is your favourite colour?</label>
  <div class="c-form__input c-form__input--select">
    <select class="c-form__select" name="i" id="i">
      <option value="red">Red</option>
      <option value="blue">Blue</option>
      <option value="green">Green</option>
      <option value="yellow">Yellow</option>
    </select>
  </div>
</div>
<div class="c-form__element">
  <label class="c-form__label" for="j">What instruments do you play?</label>
  <div class="c-form__element-group" id="j">
    <div class="c-form__checkbox-group">
      <input class="c-form__checkbox" type="checkbox" id="j-ukulele" name="j" value="ukulele" />
      <label for="j-ukulele" class="c-form__label">Ukulele</label>
    </div>
    <div class="c-form__checkbox-group">
      <input class="c-form__checkbox" type="checkbox" id="j-mandolin" name="j" value="mandolin" />
      <label for="j-mandolin" class="c-form__label">Mandolin</label>
    </div>
    <div class="c-form__checkbox-group">
      <input class="c-form__checkbox" type="checkbox" id="j-banjo" name="j" value="banjo" checked />
      <label for="j-banjo" class="c-form__label">Banjo</label>
    </div>
    <div class="c-form__checkbox-group">
      <input class="c-form__checkbox" type="checkbox" id="j-guitar" name="j" value="guitar" />
      <label for="j-guitar" class="c-form__label">Guitar</label>
    </div>
  </div>
</div>
<div class="c-form__element">
  <label class="c-form__label" for="k">Do you know the way to San Jose?</label>
  <div class="c-form__element-group" id="k">
    <div class="c-form__radio-group">
      <input class="c-form__radio" type="radio" id="k-yes" name="k" value="yes" />
      <label for="k-yes" class="c-form__label">Yes</label>
    </div>
    <div class="c-form__radio-group">
      <input class="c-form__radio" type="radio" id="k-no" name="k" value="no" />
      <label for="k-no" class="c-form__label">No</label>
    </div>
    <div class="c-form__radio-group">
      <input class="c-form__radio" type="radio" id="k-unsure" name="k" value="unsure" />
      <label for="k-unsure" class="c-form__label">Not sure</label>
    </div>
  </div>
</div>

Form hints

You can add a hint to any form-element, to give users more information about a form field.

Must contain a letter, a number, a hieroglyph and at least two Cyrillic characters
<div class="c-form__element">
  <label class="c-form__label" for="l">Password</label>
  <input class="c-form__input c-form__input--password" type="password" id="l" name="l" />
  <small class="c-form__hint">Must contain a letter, a number, a hieroglyph and at least two Cyrillic characters</small>
</div>

You can put these together in the usual grid system: a grid-row can be form-elements that are three thirds, two halfs, a half and two quarters, and so on.

<div class="o-grid__row">
  <div class="o-grid__box o-grid__box--third">
    <div class="c-form__element">
      <label class="c-form__label" for="l2">Bippity</label>
      <input class="c-form__input c-form__input--text" type="text" id="l2" name="l2" />
    </div>
  </div>
  <div class="o-grid__box o-grid__box--third">
    <div class="c-form__element">
      <label class="c-form__label" for="m">Boppity</label>
      <input class="c-form__input c-form__input--text" type="text" id="m" name="m" />
    </div>
  </div>
  <div class="o-grid__box o-grid__box--third">
    <div class="c-form__element">
      <label class="c-form__label" for="n">Boo</label>
      <input class="c-form__input c-form__input--text" type="text" id="n" name="n" />
    </div>
  </div>
</div>

And finally, the form organism: a load of grid-rows. The default style is form-stacked.

Fill in this form
Must contain a letter, a number, a hieroglyph and at least two Cyrillic characters
<form action="#" method="get" class="c-form c-form--stacked">
  <fieldset>
    <legend class="c-form__legend">Fill in this form</legend>
    <div class="o-grid">
      <div class="o-grid__row">
        <div class="o-grid__box o-grid__box--third">
          <div class="c-form__element">
            <label class="c-form__label" for="sa">Text input</label>
            <input class="c-form__input c-form__input--text" type="text" id="sa" name="sa" />
          </div>
        </div>
        <div class="o-grid__box o-grid__box--third">
          <div class="c-form__element">
            <label class="c-form__label" for="sb">File input</label>
            <input class="c-form__input c-form__input--file" type="file" id="sb" name="sb" />
          </div>
        </div>
        <div class="o-grid__box o-grid__box--third">
          <div class="c-form__element">
            <label class="c-form__label" for="sc">Password</label>
            <input class="c-form__input c-form__input--password" type="password" id="sc" name="sc" />
            <small class="c-form__hint">Must contain a letter, a number, a hieroglyph and at least two Cyrillic characters</small>
          </div>
        </div>
      </div>
      <div class="o-grid__row">
        <div class="o-grid__box o-grid__box--third">
          <div class="c-form__element">
            <label class="c-form__label" for="sd">Email</label>
            <input class="c-form__input c-form__input--email" type="email" id="sd" name="sd" />
          </div>
        </div>
        <div class="o-grid__box o-grid__box--third">
          <div class="c-form__element">
            <label class="c-form__label" for="se">URL</label>
            <input class="c-form__input c-form__input--url" type="url" id="se" name="se" />
          </div>
        </div>
        <div class="o-grid__box o-grid__box--third">
          <div class="c-form__element">
            <label class="c-form__label" for="sf">Telephone</label>
            <input class="c-form__input c-form__input--tel" type="tel" id="sf" name="sf" />
          </div>
        </div>
      </div>
      <div class="o-grid__row">
        <div class="o-grid__box o-grid__box--third">
          <div class="c-form__element c-form__element--select">
            <label class="c-form__label" for="sg">Select</label>
            <div class="c-form__input c-form__input--select">
              <select class="c-form__select" name="sg" id="sg">
                <option value="red">Red</option>
                <option value="blue">Blue</option>
                <option value="green">Green</option>
                <option value="yellow">Yellow</option>
              </select>
            </div>
          </div>
        </div>
        <div class="o-grid__box o-grid__box--third">
          <div class="c-form__element">
            <label class="c-form__label" for="sh">Radio</label>
            <div class="c-form__element-group" id="sh">
              <div class="c-form__radio-group">
                <input class="c-form__radio" type="radio" id="sh-yes" name="sh" value="yes" />
                <label for="sh-yes" class="c-form__label">Yes</label>
              </div>
              <div class="c-form__radio-group">
                <input class="c-form__radio" type="radio" id="sh-no" name="sh" value="no" />
                <label for="sh-no" class="c-form__label">No</label>
              </div>
              <div class="c-form__radio-group">
                <input class="c-form__radio" type="radio" id="sh-unsure" name="sh" value="unsure" />
                <label for="sh-unsure" class="c-form__label">Not sure</label>
              </div>
            </div>
          </div>
        </div>
        <div class="o-grid__box o-grid__box--third">
          <div class="c-form__element">
            <label class="c-form__label" for="si">Checkbox</label>
            <div class="c-form__element-group" id="si">
              <div class="c-form__checkbox-group">
                <input class="c-form__checkbox" type="checkbox" id="si-ukulele" name="si" value="ukulele" />
                <label for="si-ukulele" class="c-form__label">Ukulele</label>
              </div>
              <div class="c-form__checkbox-group">
                <input class="c-form__checkbox" type="checkbox" id="si-mandolin" name="si" value="mandolin" />
                <label for="si-mandolin" class="c-form__label">Mandolin</label>
              </div>
              <div class="c-form__checkbox-group">
                <input class="c-form__checkbox" type="checkbox" id="si-banjo" name="si" value="banjo" checked />
                <label for="si-banjo" class="c-form__label">Banjo</label>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div class="o-grid__row">
        <div class="o-grid__box o-grid__box--full">
          <div class="c-form__element">
            <label class="c-form__label" for="sj">Textarea</label>
            <textarea class="c-form__input c-form__input--textarea" id="sj" name="sj"></textarea>
          </div>
        </div>
      </div>
      <div class="o-grid__row">
        <div class="o-grid__box o-grid__box--full">
          <button class="c-btn c-btn--medium">Submit</button>
        </div>
      </div>
    </div>
  </fieldset>
</form>

Inline forms

Inline forms have the label and the input on the same line. By default, the label is 25% of the width of the row, and the input is the remaining 75%. Because of this it's not recommended to put inline forms into quarter- or third-width grid boxes. Here is the same form as above but as a form-inline version.

Fill in this form
Must contain a letter, a number, a hieroglyph and at least two Cyrillic characters
<form action="#" method="get" class="c-form c-form--inline">
  <fieldset>
    <legend class="c-form__legend">Fill in this form</legend>
    <div class="o-grid">
      <div class="o-grid__row">
        <div class="o-grid__box o-grid__box--full">
          <div class="c-form__element">
            <label class="c-form__label" for="ia">Text input</label>
            <input class="c-form__input c-form__input--text" type="text" id="ia" name="ia" />
          </div>
        </div>
      </div>
      <div class="o-grid__row">
        <div class="o-grid__box o-grid__box--full">
          <div class="c-form__element">
            <label class="c-form__label" for="ib">File input</label>
            <input class="c-form__input c-form__input--file" type="file" id="ib" name="ib" />
          </div>
        </div>
      </div>
      <div class="o-grid__row">
        <div class="o-grid__box o-grid__box--full">
          <div class="c-form__element">
            <label class="c-form__label" for="ic">Password</label>
            <input class="c-form__input c-form__input--password" type="password" id="ic" name="ic" />
            <small class="c-form__hint">Must contain a letter, a number, a hieroglyph and at least two Cyrillic characters</small>
          </div>
        </div>
      </div>
      <div class="o-grid__row">
        <div class="o-grid__box o-grid__box--full">
          <div class="c-form__element">
            <label class="c-form__label" for="id">Email</label>
            <input class="c-form__input c-form__input--email" type="email" id="id" name="id" />
          </div>
        </div>
      </div>
      <div class="o-grid__row">
        <div class="o-grid__box o-grid__box--full">
          <div class="c-form__element">
            <label class="c-form__label" for="ie">URL</label>
            <input class="c-form__input c-form__input--url" type="url" id="ie" name="ie" />
          </div>
        </div>
      </div>
      <div class="o-grid__row">
        <div class="o-grid__box o-grid__box--full">
          <div class="c-form__element">
            <label class="c-form__label" for="if">Telephone</label>
            <input class="c-form__input c-form__input--tel" type="tel" id="if" name="if" />
          </div>
        </div>
      </div>
      <div class="o-grid__row">
        <div class="o-grid__box o-grid__box--full">
          <div class="c-form__element c-form__element--select">
            <label class="c-form__label" for="ig">Select</label>
            <div class="c-form__input c-form__input--select">
              <select class="c-form__select" name="ig" id="ig">
                <option value="red">Red</option>
                <option value="blue">Blue</option>
                <option value="green">Green</option>
                <option value="yellow">Yellow</option>
              </select>
            </div>
          </div>
        </div>
      </div>
      <div class="o-grid__row">
        <div class="o-grid__box o-grid__box--full">
          <div class="c-form__element">
            <label class="c-form__label" for="ih">Radio</label>
            <div class="c-form__element-group" id="ih">
              <div class="c-form__radio-group">
                <input class="c-form__radio" type="radio" id="j-yes" name="j" value="yes" />
                <label for="j-yes" class="c-form__label">Yes</label>
              </div>
              <div class="c-form__radio-group">
                <input class="c-form__radio" type="radio" id="j-no" name="j" value="no" />
                <label for="j-no" class="c-form__label">No</label>
              </div>
              <div class="c-form__radio-group">
                <input class="c-form__radio" type="radio" id="j-unsure" name="j" value="unsure" />
                <label for="j-unsure" class="c-form__label">Not sure</label>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div class="o-grid__row">
        <div class="o-grid__box o-grid__box--full">
          <div class="c-form__element">
            <label class="c-form__label" for="ii">Checkbox</label>
            <div class="c-form__element-group" id="ii">
              <div class="c-form__checkbox-group">
                <input class="c-form__checkbox" type="checkbox" id="j-ukulele" name="j" value="ukulele" />
                <label for="j-ukulele" class="c-form__label">Ukulele</label>
              </div>
              <div class="c-form__checkbox-group">
                <input class="c-form__checkbox" type="checkbox" id="j-mandolin" name="j" value="mandolin" />
                <label for="j-mandolin" class="c-form__label">Mandolin</label>
              </div>
              <div class="c-form__checkbox-group">
                <input class="c-form__checkbox" type="checkbox" id="j-banjo" name="j" value="banjo" checked />
                <label for="j-banjo" class="c-form__label">Banjo</label>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div class="o-grid__row">
        <div class="o-grid__box o-grid__box--full">
          <div class="c-form__element">
            <label class="c-form__label" for="ij">Textarea</label>
            <textarea class="c-form__input c-form__input--textarea" id="ij" name="ij"></textarea>
          </div>
        </div>
      </div>
      <div class="o-grid__row">
        <div class="o-grid__box o-grid__box--full">
          <button class="c-btn c-btn--medium">Submit</button>
        </div>
      </div>
    </div>
  </fieldset>
</form>

Joined forms

A joined form is a single-field form with the submit button joined to the end. It must be a text-style input that is joined to the button (or it won't fit). No label is required.

A joined form and button
<form action="#" method="get" class="c-form c-form--joined">
  <fieldset>
    <legend class="c-form__legend">A joined form and button</legend>
    <div class="o-grid">
      <div class="o-grid__row">
        <div class="o-grid__box o-grid__box--full">
          <div class="c-form__element">
            <input class="c-form__input c-form__input--text" type="text" id="ja" name="ja" placeholder="Enter your search term here" aria-label="Search" />
            <button type="submit" class="c-btn c-btn--medium">Search<i class="c-icon c-icon--search c-icon--after"></i></button>
          </div>
        </div>
      </div>
    </div>
  </fieldset>
</form>

Form validation

Add an is-invalid class to the form-element div to flag it up as invalid its contents. You can also add a hint-invalid message to each invalid element, if required.

Fill in this form
This field cannot be empty
This field cannot be empty
Must contain a letter, a number, a hieroglyph and at least two Cyrillic characters This field cannot be empty
This field cannot be empty
This field cannot be empty
This field cannot be empty
This field cannot be empty
This field cannot be empty
This field cannot be empty
This field cannot be empty
<form action="#" method="get" class="c-form c-form--stacked">
  <fieldset>
    <legend class="c-form__legend">Fill in this form</legend>
    <div class="o-grid">
      <div class="o-grid__row">
        <div class="o-grid__box o-grid__box--third">
          <div class="c-form__element is-invalid">
            <label class="c-form__label" for="sa2">Text input</label>
            <input class="c-form__input c-form__input--text" type="text" id="sa2" name="sa2" />
            <small class="c-form__hint is-invalid">This field cannot be empty</small>
          </div>
        </div>
        <div class="o-grid__box o-grid__box--third">
          <div class="c-form__element is-invalid">
            <label class="c-form__label" for="sb2">File input</label>
            <input class="c-form__input c-form__input--file" type="file" id="sb2" name="sb2" />
            <small class="c-form__hint is-invalid">This field cannot be empty</small>
          </div>
        </div>
        <div class="o-grid__box o-grid__box--third">
          <div class="c-form__element is-invalid">
            <label class="c-form__label" for="sc2">Password</label>
            <input class="c-form__input c-form__input--password" type="password" id="sc2" name="sc2" />
            <small class="c-form__hint">Must contain a letter, a number, a hieroglyph and at least two Cyrillic characters</small>
            <small class="c-form__hint is-invalid">This field cannot be empty</small>
          </div>
        </div>
      </div>
      <div class="o-grid__row">
        <div class="o-grid__box o-grid__box--third">
          <div class="c-form__element is-invalid">
            <label class="c-form__label" for="sd2">Email</label>
            <input class="c-form__input c-form__input--email" type="email" id="sd2" name="sd2" />
            <small class="c-form__hint is-invalid">This field cannot be empty</small>
          </div>
        </div>
        <div class="o-grid__box o-grid__box--third">
          <div class="c-form__element is-invalid">
            <label class="c-form__label" for="se2">URL</label>
            <input class="c-form__input c-form__input--url" type="url" id="se2" name="se2" />
            <small class="c-form__hint is-invalid">This field cannot be empty</small>
          </div>
        </div>
        <div class="o-grid__box o-grid__box--third">
          <div class="c-form__element is-invalid">
            <label class="c-form__label" for="sf2">Telephone</label>
            <input class="c-form__input c-form__input--tel" type="tel" id="sf2" name="sf2" />
            <small class="c-form__hint is-invalid">This field cannot be empty</small>
          </div>
        </div>
      </div>
      <div class="o-grid__row">
        <div class="o-grid__box o-grid__box--third">
          <div class="c-form__element c-form__element--select is-invalid">
            <label class="c-form__label" for="sg2">Select</label>
            <div class="c-form__input c-form__input--select">
              <select class="c-form__select" name="sg2" id="sg2">
                <option value="red">Red</option>
                <option value="blue">Blue</option>
                <option value="green">Green</option>
                <option value="yellow">Yellow</option>
              </select>
            </div>
            <small class="c-form__hint is-invalid">This field cannot be empty</small>
          </div>
        </div>
        <div class="o-grid__box o-grid__box--third">
          <div class="c-form__element is-invalid">
            <label class="c-form__label" for="sh2">Radio</label>
            <div class="c-form__element-group" id="sh2">
              <div class="c-form__radio-group">
                <input class="c-form__radio" type="radio" id="sh2-yes" name="sh2" value="yes" />
                <label for="sh2-yes" class="c-form__label">Yes</label>
              </div>
              <div class="c-form__radio-group">
                <input class="c-form__radio" type="radio" id="sh2-no" name="sh2" value="no" />
                <label for="sh2-no" class="c-form__label">No</label>
              </div>
              <div class="c-form__radio-group">
                <input class="c-form__radio" type="radio" id="sh2-unsure" name="sh2" value="unsure" />
                <label for="sh2-unsure" class="c-form__label">Not sure</label>
              </div>
            </div>
            <small class="c-form__hint is-invalid">This field cannot be empty</small>
          </div>
        </div>
        <div class="o-grid__box o-grid__box--third">
          <div class="c-form__element is-invalid">
            <label class="c-form__label" for="si2">Checkbox</label>
            <div class="c-form__element-group" id="si2">
              <div class="c-form__checkbox-group">
                <input class="c-form__checkbox" type="checkbox" id="si2-ukulele" name="si2" value="ukulele" />
                <label for="si2-ukulele" class="c-form__label">Ukulele</label>
              </div>
              <div class="c-form__checkbox-group">
                <input class="c-form__checkbox" type="checkbox" id="si2-mandolin" name="si2" value="mandolin" />
                <label for="si2-mandolin" class="c-form__label">Mandolin</label>
              </div>
              <div class="c-form__checkbox-group">
                <input class="c-form__checkbox" type="checkbox" id="si2-banjo" name="si2" value="banjo" checked />
                <label for="si2-banjo" class="c-form__label">Banjo</label>
              </div>
            </div>
            <small class="c-form__hint is-invalid">This field cannot be empty</small>
          </div>
        </div>
      </div>
      <div class="o-grid__row">
        <div class="o-grid__box o-grid__box--full">
          <div class="c-form__element is-invalid">
            <label class="c-form__label" for="sj2">Textarea</label>
            <textarea class="c-form__input c-form__input--textarea" id="sj2" name="sj2"></textarea>
            <small class="c-form__hint is-invalid">This field cannot be empty</small>
          </div>
        </div>
      </div>
      <div class="o-grid__row">
        <div class="o-grid__box o-grid__box--full">
          <button class="c-btn c-btn--medium">Submit</button>
        </div>
      </div>
    </div>
  </fieldset>
</form>

Options

Atoms

  • input

    • type: one of text (default), file, hidden, password, email, url and tel
    • value: the default value of the input
    • placeholder: placeholder text (don't rely on this text being there - it's not supported in <IE10)
  • option

    • label: the text in the option field (required)
    • value: the value of the option (required)
  • checkbox

    • label: the text in the accompanying label field (required)
    • value: the value of the checkbox (required)
    • name: the `name attribute (must be the same for all checkboxes/radios) (required)
  • radio

    • label: the text in the accompanying label field (required)
    • value: the value of the radio (required)
    • name: the `name attribute (must be the same for all checkboxes/radios) (required)

Molecules

  • form-element
    • label: the label attached to the form element (required)
    • name: the name of the form field (required)
    • select: true if this is a select dropdown
    • size: one of half, quarter or third (leaving blank will render full-width)
    • hint: (string) Help users out with tricky form questions
    • invalid: (Boolean) (default false) whether the field is invalid or not
    • hint-invalid: (string) Error message for invalid fields
    • atoms: an array of atoms (multiple options, checkboxes or radios) or an atom object (i.e. one input). If this is missing a text input is added by default

Organisms

  • form
    • type: supported types are stacked (default), joined or inline
    • action: URL to submit the form to. Can be absolute or relative. Defaults to "#"
    • method: either post (default) or get
    • id: an _id_ to identify the form
    • legend: some text to go in the legend of the form. Default is to omit it altogether.
    • atoms: an array of grid-row molecules.

TODO

  • Add validation options? (as data-validation option)
  • Fancy select boxes?
  • Fancy file input?