Bootstrap radio buttons and checkboxes in columns, with contextual text fields

We recently did a project with the following requirements:

  • Touch-friendly interface (translation: big touch targets);
  • Bootstrap;
  • Radio and checkboxes need to highlight when selected;
  • When a radio button or checkbox is selected, sometimes a little additional information is required.

See the demo to get a clear idea of what I’m talking about.

To accomplish this, we did several things:

  1. Used Bootstrap “radio-inline” and “checkbox-inline” classes;
  2. Wrapped each radio/checkbox in a label, styled the label to look like a touch target, and set it so clicking on the label selected the radio/checkbox.
  3. Created a “column” class to make the labels form columns;
  4. Used jQuery to add a “checked” class to each label when its radio/checkbox is selected.
  5. Created an “additional-info-wrap” class to associate a contextual text field with any radio/checkbox we needed.

Sounds complicated, but it’s really not. The actual code is pretty simple.

HTML

<form class="form-horizontal">
        <div class="form-group">
              <label class="col-md-2 control-label" for="Checkboxes">Checkboxes</label>  

              <div class="col-md-10 columns">
                    <label class="checkbox-inline" for="Checkboxes_Apple">
                      <input type="checkbox" name="Checkboxes" id="Checkboxes_Apple" value="Apple">
                      Apple
                    </label>
                    <label class="checkbox-inline" for="Checkboxes_Orange">
                      <input type="checkbox" name="Checkboxes" id="Checkboxes_Orange" value="Orange">
                      Orange
                    </label>
                    <label class="checkbox-inline" for="Checkboxes_Bananas">
                      <input type="checkbox" name="Checkboxes" id="Checkboxes_Bananas" value="Bananas">
                      Banana
                    </label>
                    <label class="checkbox-inline" for="Checkboxes_Kumquats">
                      <input type="checkbox" name="Checkboxes" id="Checkboxes_Kumquats" value="Kumquats">
                      Kumquat
                    </label>
                    <span class="additional-info-wrap">
                        <label class="checkbox-inline" for="Checkboxes_Grape">
                          <input type="checkbox" name="Checkboxes" id="Checkboxes_Grape" value="Grape">
                          Grape
                        </label>
                        <div class="additional-info hide">
                              <input type="text" id="CheckboxesNameOfGrape" name="CheckboxesNameOfGrape" placeholder="Name of Grape" class="form-control" disabled="">
                        </div>
                    </span>
                    <span class="additional-info-wrap">
                        <label class="checkbox-inline" for="Checkboxes_Other">
                          <input type="checkbox" name="Checkboxes" id="Checkboxes_Other" value="Other">
                          Other
                        </label>
                        <div class="additional-info hide">
                              <input type="text" id="CheckboxesOther" name="CheckboxesOther" placeholder="Describe" class="form-control" disabled="">
                        </div>
                    </span>
                </div>
            </div>
        <div class="form-group">
              <label class="col-md-2 control-label" for="Radios">Radio buttons</label>  

              <div class="col-md-10 columns">
                    <label class="radio-inline" for="Radios_Apple">
                      <input type="radio" name="Radios" id="Radios_Apple" value="Apple">
                      Apple
                    </label>
                    <label class="radio-inline" for="Radios_Orange">
                      <input type="radio" name="Radios" id="Radios_Orange" value="Orange">
                      Orange
                    </label>
                    <label class="radio-inline" for="Radios_Bananas">
                      <input type="radio" name="Radios" id="Radios_Bananas" value="Bananas">
                      Banana
                    </label>
                    <label class="radio-inline" for="Radios_Kumquats">
                      <input type="radio" name="Radios" id="Radios_Kumquats" value="Kumquats">
                      Kumquat
                    </label>
                    <span class="additional-info-wrap">
                        <label class="radio-inline" for="Radios_Grape">
                          <input type="radio" name="Radios" id="Radios_Grape" value="Grape">
                          Grape
                        </label>
                        <div class="additional-info hide">
                              <input type="text" id="RadiosNameOfGrape" name="RadiosNameOfGrape" placeholder="Name of Grape" class="form-control" disabled="">
                        </div>
                    </span>
                    <span class="additional-info-wrap">
                        <label class="radio-inline" for="Radios_Other">
                          <input type="radio" name="Radios" id="Radios_Other" value="Other">
                          Other
                        </label>
                        <div class="additional-info hide">
                              <input type="text" id="RadiosOther" name="RadiosOther" placeholder="Describe" class="form-control" disabled="">
                        </div>
                    </span>
                </div>
            </div>
    </form>

Nothing too fancy here. Each radio/checkbox is wrapped in a label with a “for” attribute applied; this selects the radio/checkbox when its label is clicked.

Each group of labels is wrapped in a div with the class “column”.

The radios/checkboxes that have an extra text field are wrapped in a span with the class “additional-info-wrap”; the extra text field itself is in a div with the class “additional-info”, and with the Bootstrap “hide” class attached so it’s not displayed.

CSS

label.radio-inline, label.checkbox-inline {
  background-color: #dcdfd4;
  cursor: pointer;
  font-weight: 400;
  margin-bottom: 10px !important;
  margin-right: 2%;
  margin-left:0;
  padding: 10px 10px 10px 30px;
}
label.radio-inline.checked, label.checkbox-inline.checked {
  background-color: #266c8e;
  color: #fff !important;
  text-shadow: 1px 1px 2px #000 !important;
}
.checkbox-inline + .checkbox-inline, .radio-inline + .radio-inline {
  margin-left: 0;
}
.columns label.radio-inline, .columns label.checkbox-inline {
  min-width: 190px;
  vertical-align: top;
  width: 30%;
}
.additional-info-wrap {
  display: inline-block;
  margin: 0 2% 0 0;
  min-width: 190px;
  position: relative;
  vertical-align: top;
  width: 30%;
}
.additional-info-wrap label.checkbox-inline, .additional-info-wrap label.radio-inline {
  width: 100% !important;
}
.additional-info-wrap .additional-info {
  background-color: #266c8e;
  clear: both;
  color: #fff !important;
  margin-top: -10px;
  padding: 0 10px 10px;
  text-shadow: 1px 1px 2px #000 !important;
  width: 100%;
}

Again, fairly straightforward.

The first style turns the labels into touch targets, by giving them some padding and a gray background color.

The second style turns the labels blue, with white text, when the “checked” class is added.

The third style cancels some base Bootstrap margins that mess up our column layout.

The fourth style creates the columns, by setting a width and margin for each label. They stack up in three columns until the page gets too narrow, and then they stack in two columns.

The last three styles all handle the contextual text field.

“additional-info-wrap” is set to mimic the other labels,

The radio/checkbox inside “additional-info-wrap” is set to “width:100%” so it fills out the entire width.

Finally, “additional-info” wraps the contextual text field and gives it some padding, margin and the same background color as the labels.

JAVASCRIPT

$(document).ready(function() {

    //When checkboxes/radios checked/unchecked, toggle background color
    $('.form-group').on('click','input[type=radio]',function() {
        $(this).closest('.form-group').find('.radio-inline, .radio').removeClass('checked');
        $(this).closest('.radio-inline, .radio').addClass('checked');
    });
    $('.form-group').on('click','input[type=checkbox]',function() {
        $(this).closest('.checkbox-inline, .checkbox').toggleClass('checked');
    });

    //Show additional info text box when relevant checkbox checked
    $('.additional-info-wrap input[type=checkbox]').click(function() {
        if($(this).is(':checked')) {
            $(this).closest('.additional-info-wrap').find('.additional-info').removeClass('hide').find('input,select').removeAttr('disabled');
        }
        else {
            $(this).closest('.additional-info-wrap').find('.additional-info').addClass('hide').find('input,select').val('').attr('disabled','disabled');
        }
    });

    //Show additional info text box when relevant radio checked
    $('input[type=radio]').click(function() {
        $(this).closest('.form-group').find('.additional-info-wrap .additional-info').addClass('hide').find('input,select').val('').attr('disabled','disabled');
        if($(this).closest('.additional-info-wrap').length > 0) {
            $(this).closest('.additional-info-wrap').find('.additional-info').removeClass('hide').find('input,select').removeAttr('disabled');
        }        
    });
});

The first event listener adds/removes the “checked” class from a label when it is clicked. For checkboxes, it’s a simple toggle. For radios, it has to remove the “checked” class from all the other radios in the group before adding it to the selected radio.

The last two event listeners show/hide a contextual text field, if present, by removing/adding the Bootstrap “hide” class from the related “additional-info” div. You’ll see that the code is slightly different for radios vs. checkboxes, again because in a radio group you have to account for all the radios, while checkboxes can be treated individually.

 

Categories: App Development.