Accessible Form - bare

In this example below you will see how to do a Accessible Form - bare with some HTML / CSS and Javascript

Thumbnail
This awesome code was written by jcozzo, you can see more from this user in the personal repository.
You can find the original code on Codepen.io
Copyright jcozzo ©

Technologies

  • HTML
  • CSS
  • JavaScript
<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">
  <title>Accessible Form - bare</title>
  
  
  
      <link rel="stylesheet" href="css/style.css">

  
</head>

<body>

  <form id="ch_form" class="ch-form" method="post" action="" novalidate="novalidate">
  <div class="contact-info">
    <div class="ch-form-item">
      <label for="first_name">First Name<abbr title="required">*</abbr>:</label>
      <input type="text" id="first_name" name="first_name" title="Please enter your first name" required="" aria-required="true" value="">
    </div> <!-- use required + aria-required="true" https://www.w3.org/WAI/tutorials/forms/validation/#validating-required-input -->

    <div class="ch-form-item">
      <label for="last_name">Last Name<abbr title="required">*</abbr>:</label>
      <input type="text" id="last_name" name="last_name" title="Please enter your last name" required="" aria-required="true" value="">
    </div>

    <div class="ch-form-item">
      <label for="address1">Address line 1<abbr title="required">*</abbr>:</label>
      <span id="address1_ex">Street address, P.O. box, company name, c/o</span>
      <input type="text" id="address1" name="address1" title="Please enter your address" required="" aria-describedby="address1_ex" aria-required="true" value="">
    </div>

    <!-- aria-describedby http://webaim.org/techniques/forms/advanced#describedby -->

    <div class="ch-form-item">
      <label for="address2">Address line 2:</label>
      <span id="address2_ex">Apartment, suite, unit, building, floor, etc.</span>
      <input type="text" id="address2" name="address2" aria-describedby="address2_ex" value="">
    </div>

    <div class="ch-form-item">
      <label for="city">City<abbr title="required">*</abbr>:</label>
      <input type="text" id="city" name="city" title="Please enter your city" required="" aria-required="true" value="">
    </div>

    <!-- Fallback if no JS -->
    <div class="ch-form-item" style="display: none;">
      <label for="states">State<abbr title="required">*</abbr>:</label>
      <select id="states" name="states" title="Please enter your state" value="">
        <option value="AL">Alabama</option>
        <option value="AK">Alaska</option>
        <option value="AZ">Arizona</option>
        <option value="AR">Arkansas</option>
        <option value="CA">California</option>
        <option value="CO">Colorado</option>
        <option value="CT">Connecticut</option>
        <option value="DE">Delaware</option>
        <option value="DC">District Of Columbia</option>
        <option value="FL">Florida</option>
        <option value="GA">Georgia</option>
        <option value="HI">Hawaii</option>
        <option value="ID">Idaho</option>
        <option value="IL">Illinois</option>
        <option value="IN">Indiana</option>
        <option value="IA">Iowa</option>
        <option value="KS">Kansas</option>
        <option value="KY">Kentucky</option>
        <option value="LA">Louisiana</option>
        <option value="ME">Maine</option>
        <option value="MD">Maryland</option>
        <option value="MA">Massachusetts</option>
        <option value="MI">Michigan</option>
        <option value="MN">Minnesota</option>
        <option value="MS">Mississippi</option>
        <option value="MO">Missouri</option>
        <option value="MT">Montana</option>
        <option value="NE">Nebraska</option>
        <option value="NV">Nevada</option>
        <option value="NH">New Hampshire</option>
        <option value="NJ">New Jersey</option>
        <option value="NM">New Mexico</option>
        <option value="NY">New York</option>
        <option value="NC">North Carolina</option>
        <option value="ND">North Dakota</option>
        <option value="OH">Ohio</option>
        <option value="OK">Oklahoma</option>
        <option value="OR">Oregon</option>
        <option value="PA">Pennsylvania</option>
        <option value="RI">Rhode Island</option>
        <option value="SC">South Carolina</option>
        <option value="SD">South Dakota</option>
        <option value="TN">Tennessee</option>
        <option value="TX">Texas</option>
        <option value="UT">Utah</option>
        <option value="VT">Vermont</option>
        <option value="VA">Virginia</option>
        <option value="WA">Washington</option>
        <option value="WV">West Virginia</option>
        <option value="WI">Wisconsin</option>
        <option value="WY">Wyoming</option>
      </select>
    </div>

    <!-- JS only: only displayed if JS, hide states drop-down div -->
    <div class="ch-form-item" style="">
      <div class="ui-widget">
        <label for="state">State<abbr title="required">*</abbr>: </label>
        <input id="state" type="text" name="state" title="Please enter your state" required="required" aria-required="true" class="ui-autocomplete-input" autocomplete="off">
      </div>
    </div>
    <!-- end JS only -->

    <!-- Use type="text" for zip codes https://www.w3.org/TR/html5/forms.html#number-state-%28type=number%29 -->
    <!-- Pattern is for American postal codes http://html5pattern.com/Postal_Codes -->

    <div class="ch-form-item">
      <label for="zip">ZIP<abbr title="required">*</abbr>:</label>
      <input type="text" id="zip" name="zip" title="Please enter a valid 5-digit zip code" pattern="(\d{5}([\-]\d{4})?)" required="" aria-required="true" value="">
    </div>


    <!-- Input masks can do weird things to screen readers: https://css-tricks.com/input-masking/#article-header-id-2
This formatter was build with accessibility in mind: http://firstopinion.github.io/formatter.js/index.html -->

    <div class="ch-form-item">
      <label for="phone">Phone number:</label>
      <input type="tel" id="phone" name="phone" pattern=".*\d{3}.*\d{3}.*\d{4}" placeholder="(   ) -" title="Please enter a valid phone number">
    </div>

    <!-- Email pattern https://html.spec.whatwg.org/#e-mail-state-(type=email) -->

    <div class="ch-form-item">
      <label for="email">Email:</label>
      <input type="email" id="email" name="email" pattern="^[a-zA-Z0-9.!#$%&amp;'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$" title="Please enter your email address" value="">
    </div>

    <div class="ch-form-item">
      <label for="dob">Date of Birth:</label>
      <span id="dob_help">MM/DD/YYYY</span>
      <input type="date" id="dob" aria-describedby="dob_help" name="dob" value="">
    </div>

    <div class="ch-form-item">
      <label for="textarea">Textarea:</label>
      <textarea id="textarea" name="textarea"></textarea>
    </div>
  </div>

  <fieldset aria-required="true">
    <legend>Checkboxes (check all that apply)</legend>
    <div class="ch-form-item">
      <input id="opt1" type="checkbox" name="checkbox" value="Option1">
      <label for="opt1">Checkbox option 1</label>
    </div>
    <div class="ch-form-item">
      <input id="opt2" type="checkbox" name="checkbox" value="Option2">
      <label for="opt2">Checkbox option 2</label>
    </div>
    <div class="ch-form-item">
      <input id="other" type="checkbox" name="checkbox" value="Other">
      <label for="other">Checkbox other: </label>
      <input type="text" id="textother" name="checkbox" data-checkbox="other" aria-labelledby="other" value="">
    </div>
  </fieldset>

  <fieldset aria-required="true">
    <legend>Radio</legend>
    <div class="ch-form-item">
      <input id="rad1" type="radio" name="radio" value="Radio1">
      <label for="rad1">Radio option 1</label>
    </div>
    <div class="ch-form-item">
      <input id="rad2" type="radio" name="radio" value="Radio2">
      <label for="rad2">Radio option 2</label>
    </div>
    <div class="ch-form-item">
      <input id="rad3" type="radio" name="radio" value="Radio3">
      <label for="rad3">Radio option 3</label>
    </div>
  </fieldset>

  <fieldset aria-required="true">
    <legend>Radio buttons in a table (responsive)</legend>
    <table class="multi-label responsive-form"> <!-- multiple inputs for one label http://webaim.org/techniques/forms/advanced#multiple -->
      <tbody>
        <tr class="hidden-small">
          <th class="hidden-visually" scope="col">Hidden Header</th> <!-- hidden label http://webaim.org/techniques/forms/advanced#hiddenlabel -->
          <th id="never" scope="col">Never</th>
          <th id="some" scope="col">Sometimes</th>
          <th id="many" scope="col">Often</th>
        </tr>
        <tr>
          <th id="a_1" scope="row">Radio label 1</th>
          <td data-label="Never">
            <input id="a1" type="radio" name="a_1" aria-labelledby="a_1 never" value="Never">
            <label for="a1"></label>
          </td>
          <td data-label="Sometimes">
            <input id="a2" type="radio" name="a_1" aria-labelledby="a_1 some" value="Sometimes">
            <label for="a2"></label>
          </td>
          <td data-label="Often">
            <input id="a3" type="radio" name="a_1" aria-labelledby="a_1 many" value="Often">
            <label for="a3"></label>
          </td>
        </tr>

        <tr>
          <th id="b_1" scope="row">Radio label 2</th>
          <td data-label="Never">
            <input id="b1" type="radio" name="b_1" aria-labelledby="b_1 never" value="Never">
            <label for="b1"></label>
          </td>
          <td data-label="Sometimes">
            <input id="b2" type="radio" name="b_1" aria-labelledby="b_1 some" value="Sometimes">
            <label for="b2"></label>
          </td>
          <td data-label="Often">
            <input id="b3" type="radio" name="b_1" aria-labelledby="b_1 many" value="Often">
            <label for="b3"></label>
          </td>
        </tr>

        <tr>
          <th id="c_1" scope="row">Radio label 3</th>
          <td data-label="Never">
            <input id="c1" type="radio" name="c_1" aria-labelledby="c_1 never" value="Never">
            <label for="c1"></label>
          </td>
          <td data-label="Sometimes">
            <input id="c2" type="radio" name="c_1" aria-labelledby="c_1 some" value="Sometimes">
            <label for="c2"></label>
          </td>
          <td data-label="Often">
            <input id="c3" type="radio" name="c_1" aria-labelledby="c_1 many" value="Often">
            <label for="c3"></label>
          </td>
        </tr>
      </tbody>
    </table>
  </fieldset>

  <input type="submit" name="submit" value="Submit" class="btn">

</form>
  <script src='https://communicatehealth.github.io/examples/js/vendor/jquery.js'></script>
<script src='https://communicatehealth.github.io/examples/js/vendor/jquery-ui.min.js'></script>
<script src='https://communicatehealth.github.io/examples/js/vendor/jquery.formatter.min.js'></script>
<script src='https://communicatehealth.github.io/examples/js/vendor/jquery.validate.min.js'></script>
<script src='https://communicatehealth.github.io/examples/js/vendor/additional-methods.min.js'></script>

  

    <script  src="js/index.js"></script>




</body>

</html>

/*Downloaded from https://www.codeseek.co/jcozzo/accessible-form-bare-wqNjBy */
/* Content for screen readers only: http://webaim.org/techniques/css/invisiblecontent/#absolutepositioning */
.hidden-visually {
  position:absolute;
  left:-10000px;
  top:auto;
  width:1px;
  height:1px;
  overflow:hidden;
}

/* Form Validation Errors */
.ch-form input.error,
.ch-form select.error {
  background: #fcc;
}

.ch-form label.error {
  position: absolute;
  left: 1em;
  bottom: -1.75em;
  width: auto;
  font-weight: normal;
  text-align: left;
  background: #ffffff;
  padding: 0.25em 0.5em;
  border: 1px solid #d9d9d9;
  z-index: 1;
  box-shadow: 0px 4px 10px 0px rgba(0, 0, 0, 0.5);
}

.ch-form fieldset label.error {
  left: 1em;
  padding: 0.5em;
}

.ch-form label.error:before,
.ch-form label.error:after {
  content: '';
  position: absolute;
  border-left: 10px solid transparent;
  border-right: 10px solid transparent;
  bottom: 100%;
  left: 1.5em;
  margin-left: -10px;
}

.ch-form label.error:before {
  border-bottom: 10px solid #d9d9d9;
}

.ch-form label.error:after {
  border-bottom: 10px solid #fff;
  margin-bottom: -2px;
  z-index: 2;
}

/* https://techblog.livingsocial.com/blog/2015/04/06/responsive-tables-in-pure-css/ */
@media screen and (max-width: 24em) {
  .responsive-form {
    border: 0;
    display: table;
    max-width: 100%;
  }
  .responsive-form thead {
    display: none;
  }
  .responsive-form tr {
    margin-bottom: 1em;
    display: block;
  }
  .responsive-form tr.hidden-small {
    display: none;
  }
  .ch-form .multi-label.responsive-form th {
    font-weight: bold;
  }
  .ch-form .multi-label.responsive-form td  {
    display: block;
    text-align: left;
    position: relative;
  }
  .responsive-form td:last-child {
    border-bottom: 0;
  }
  .responsive-form td:after {
    content: attr(data-label);
    position: absolute;
    top: 0;
    left: 30px;
  }
  .responsive-form label {
    width: 100%;
    height: 20px;
  }
}

/* Presentation only, not needed for accessibility */
body {
  font-size: 16px;
  font-family: sans-serif;
}

abbr {
 text-decoration: none;
}

.contact-info label {
  display: block;
}

label + span {
  display: block;
  color: #666;
  font-size: 0.875em;
  padding: 0.25rem 0;
}

.ch-form-item,
fieldset {
  margin: 2em 0;
  position: relative;
}

fieldset .ch-form-item {
  margin: 0;
}

/*Downloaded from https://www.codeseek.co/jcozzo/accessible-form-bare-wqNjBy */
// Auto formats phone number (instead of using a mask) https://github.com/firstopinion/formatter.js
$('#phone').formatter({
  'pattern': '({{999}}) {{999}}-{{9999}}',
  'persistent': false //show pattern when user starts entering data "(###) ###-####"
});

$('#zip').formatter({
  'pattern': '{{99999}}',
});

// add cursor after opening "("
$('#phone').focus(function() {
  if($('#phone').val() === "") {
    $('#phone').val('(');
  }
});

// clear contents if user didn't enter anything to allow for validation
$('#phone').focusout(function() {
  if ($('#phone').val() === "(") {
    $('#phone').val('');
  }
});

// Form validation - https://jqueryvalidation.org/
$("#ch_form").validate();

// Autocomplete states (instead of really long dropdown select) - http://jqueryui.com/autocomplete/
$('#states').removeAttr('required').removeAttr('aria-required').parent().hide();

$('#state').attr('required', '').attr('aria-required', 'true').parent().parent().show();

$( function() {
  var availableStates = [
    "Alabama",
    "Alaska",
    "Arizona",
    "Arkansas",
    "California",
    "Colorado",
    "Connecticut",
    "Delaware",
    "Florida",
    "Georgia",
    "Hawaii",
    "Idaho",
    "Illinois",
    "Indiana",
    "Iowa",
    "Kansas",
    "Kentucky",
    "Louisiana",
    "Maine",
    "Maryland",
    "Massachusetts",
    "Michigan",
    "Minnesota",
    "Mississippi",
    "Missouri",
    "Montana",
    "Nebraska",
    "Nevada",
    "New Hampshire",
    "New Jersey",
    "New Mexico",
    "New York",
    "North Carolina",
    "North Dakota",
    "Ohio",
    "Oklahoma",
    "Oregon",
    "Pennsylvania",
    "Rhode Island",
    "South Carolina",
    "South Dakota",
    "Tennessee",
    "Texas",
    "Utah",
    "Vermont",
    "Virginia",
    "Washington",
    "West Virginia",
    "Wisconsin",
    "Wyoming"
  ];
  $( "#state" ).autocomplete({
    source: availableStates
  });
} );

Comments