Checkboxes & Switches
A guide of how we use checkboxes and switches in HQ.
On this page
Overview
HQ typically doesn't use checkboxes to select options from a list, but we do frequently use single checkboxes for true or false values. In the past we didn't have switches available, so checkboxes were often used to indicate whether we wanted to turn a setting on or off.
However, with the introduction of switches in Bootstrap 5, we should move toward using switches for on/off settings and checkboxes to indicate whether a statement is true or false.
Checkboxes
Checkboxes and their labels should get wrapped in a form-check
classed div
element.
See Bootstrap's documentation for a more complete checkbox deep dive.
<div class="form-check"> <input id="id-flex-check-default" class="form-check-input" type="checkbox" value="" /> <label for="id-flex-check-default" class="form-check-label" > Default checkbox </label> </div> <div class="form-check"> <input id="id-flex-check-checked" class="form-check-input" type="checkbox" value="" checked /> <label for="id-flex-check-checked" class="form-check-label" > Checked checkbox </label> </div>
Checkbox Usage in Crispy Forms
Checkboxes in form-horizontal
classed crispy forms
can be challenging to style. Checkboxes are the default representation for a BooleanField
, but they're
displayed with the label to the right of the checkbox, instead of displaying the label on the
left as for other fields.
To get a label to appear on the left, checkboxes are sometimes displayed as a single-element you must use the
BootstrapCheckboxInput
widget
and the CheckboxField
crispy forms layout element
as shown below.
If you want to display a checkbox without an additional left-hand label, the default Field
layout element
works perfectly fine.
from django import forms from django.utils.translation import gettext_lazy, gettext as _ from crispy_forms import ( bootstrap as twbscrispy, layout as crispy, ) from corehq.apps.hqwebapp import crispy as hqcrispy from corehq.apps.hqwebapp.widgets import BootstrapCheckboxInput class CheckboxDemoForm(forms.Form): height = forms.CharField( label=gettext_lazy("Height (cm)"), ) smoking_status = forms.BooleanField( label=gettext_lazy("Smoking Status"), required=False, widget=BootstrapCheckboxInput( inline_label=gettext_lazy( "Patient has smoked on a habitual basis in the past 5 years" ), ), help_text=gettext_lazy( "*Habitual basis equates to at least five cigarettes a week." ), ) heart_rate = forms.CharField( label=gettext_lazy("Heart Rate (bpm)"), required=False, ) forward_results = forms.BooleanField( label=gettext_lazy("Forward results to GP"), required=False, ) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.helper = hqcrispy.HQFormHelper() self.helper.form_method = 'POST' self.helper.form_action = '#' self.helper.layout = crispy.Layout( crispy.Fieldset( _("Basic Information"), 'height', # Functions the same as crispy.Field below hqcrispy.CheckboxField('smoking_status'), crispy.Field('heart_rate'), 'forward_results', ), hqcrispy.FormActions( twbscrispy.StrictButton( _("Save"), type="submit", css_class="btn btn-primary", ), hqcrispy.LinkButton( _("Cancel"), '#', css_class="btn btn-outline-primary", ), ), )
Checkbox Usage in Standard HTML Forms
As mentioned above, when checkbox labels are used, they should be statements about what the value means.
<form> <div class="mb-3"> <label for="id-message-input" class="form-label">Message</label> <textarea id="id-message-input" class="form-control" name="message" rows="3" ></textarea> </div> <div class="mb-3"> <div class="form-check"> <input id="id-tos-agree-input" class="form-check-input" type="checkbox" name="tosAgree" /> <label for="id-tos-agree-input" class="form-check-label" > I agree to the terms of service </label> </div> </div> <div class="mb-3"> <button type="submit" class="btn btn-primary"> Submit </button> </div> </form>
Checkbox Usage in Horizontal Forms
Checkboxes that appear in larger horizontal forms often have a separate label in addition to the label next to the checkbox. The label on the left should be a short description of that checkbox (often the name of the field). The label next to the checkbox should be a statement that expands on what that checkbox means.
<form> <div class="mb-3 row"> <label for="id-height-input" class="field-label"> Height (cm) </label> <div class="field-control"> <input id="id-height-input" class="form-control" type="text" name="height" /> </div> </div> <div class="mb-3 row"> <label class="field-label"> Smoking status </label> <div class="field-control"> <div class="form-check"> <input id="id-is-smoker-input" class="form-check-input" type="checkbox" name="is_smoker" checked /> <label for="id-is-smoker-input" class="form-check-label" > Patient has smoked on a habitual basis in the past 5 years </label> </div> </div> </div> <div class="mb-3 row"> <label for="id-heart-rate-input" class="field-label"> Heart Rate (bpm) </label> <div class="field-control"> <input id="id-heart-rate-input" class="form-control" type="text" name="heart_rate" /> </div> </div> </form>
Switches
Switches are new as of Bootstrap 5. Use switches for indicating whether a particular setting is turned on or off. Switches are for settings, checkboxes are for statements.
<div class="form-check form-switch"> <input id="id-flex-switch-check-default" class="form-check-input" type="checkbox" role="switch" /> <label for="id-flex-switch-check-default" class="form-check-label"> Default switch checkbox input </label> </div> <div class="form-check form-switch"> <input id="id-flex-switch-check-checked" class="form-check-input" type="checkbox" role="switch" checked /> <label for="id-flex-switch-check-checked" class="form-check-label"> Checked switch checkbox input </label> </div> <div class="form-check form-switch"> <input id="id-flex-switch-check-disabled" class="form-check-input" type="checkbox" role="switch" disabled /> <label for="id-flex-switch-check-disabled" class="form-check-label"> Disabled switch checkbox input </label> </div> <div class="form-check form-switch"> <input id="id-flex-switch-check-checked-disabled" class="form-check-input" type="checkbox" role="switch" checked disabled /> <label for="id-flex-switch-check-checked-disabled" class="form-check-label"> Disabled checked switch checkbox input </label> </div>
Switch Usage in Crispy Forms
Switches can also be used in crispy forms for BooleanField
s using a combination of the
BootstrapSwitchInput
widget
and the CheckboxField
crispy
forms layout element as shown below.
from django import forms from django.utils.translation import gettext_lazy, gettext as _ from crispy_forms import ( bootstrap as twbscrispy, layout as crispy, ) from corehq.apps.hqwebapp import crispy as hqcrispy from corehq.apps.hqwebapp.widgets import BootstrapSwitchInput class SwitchDemoForm(forms.Form): email = forms.CharField( label=gettext_lazy("Email"), ) enable_tracking = forms.BooleanField( label=gettext_lazy("Enable Tracking"), required=False, widget=BootstrapSwitchInput( inline_label=gettext_lazy( "Allow Dimagi to collect usage information to improve CommCare." ), ), help_text=gettext_lazy( "You can learn more about the information we collect and the ways we use it in our privacy policy" ), ) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.helper = hqcrispy.HQFormHelper() self.helper.form_method = 'POST' self.helper.form_action = '#' self.helper.layout = crispy.Layout( crispy.Fieldset( _("Basic Information"), 'email', hqcrispy.CheckboxField('enable_tracking'), ), hqcrispy.FormActions( twbscrispy.StrictButton( _("Update Settings"), type="submit", css_class="btn btn-primary", ), hqcrispy.LinkButton( _("Cancel"), '#', css_class="btn btn-outline-primary", ), ), )