Repository: cal-itp/benefits

Issue:
Enhance form rendering: Radio button list
This is a follow-on to #322, to enhance how forms are rendered in the [`page` template](https://github.com/cal-itp/benefits/blob/dev/benefits/core/templates/core/page.html)

@angela-tran [notes](https://github.com/cal-itp/benefits/pull/337#issuecomment-1076882758):

> `RadioSelect` in Django 3.2 renders as `<li>` elements. We probably don't want that? Should we add something to `page.html` so that we have more granular control over how radio buttons are shown? (Django docs have an [example](https://docs.djangoproject.com/en/3.2/ref/forms/widgets/#radioselect) of looping over the widgets.)

![image](https://user-images.githubusercontent.com/1783439/160215029-07dadd9d-e422-49ea-91b3-533485236daa.png)

The [State Template form components](https://template.webstandards.ca.gov/sample/form.html) has some example HTML for what might work here?

```html
<!--Bootstrap4 Custom Radios-->
<div class="form-check">
    <input class="form-check-input" type="radio" name="flexRadioDefault" id="customRadio1">
    <label class="form-check-label" for="customRadio1">
        Toggle this custom radio
    </label>
</div>
<div class="form-check">
    <input class="form-check-input" type="radio" name="flexRadioDefault" id="customRadio2" checked="">
    <label class="form-check-label" for="customRadio2">
        Or toggle this other custom radio
    </label>
</div>
```

The comment indicates this is just [Bootstrap 4 radios](https://getbootstrap.com/docs/4.0/components/forms/#radios)?

@angela-tran [suggests](https://github.com/cal-itp/benefits/pull/337#issuecomment-1076882758):

> Rendering the `selection_label_description` may involve adding some HTML to the display value in our `choices` tuple. My first step would be to try out the approach in https://stackoverflow.com/questions/2204696/setting-help-text-for-each-choice-in-a-radioselect.

![image](https://user-images.githubusercontent.com/1783439/160215069-abd2c18b-0ebf-4d78-a202-be7947e70ab5.png)



Discussion:

Resolving patch:
diff --git a/benefits/core/widgets.py b/benefits/core/widgets.py
--- a/benefits/core/widgets.py
+++ b/benefits/core/widgets.py
@@ -1,6 +1,7 @@
 """
 The core application: Helper form widgets.
 """
+import copy
 from django.forms import widgets
 
 
@@ -15,3 +16,25 @@ def __init__(self, pattern=None, placeholder=None, **kwargs):
             self.attrs.update({"pattern": pattern})
         if placeholder:
             self.attrs.update({"placeholder": placeholder})
+
+
+class RadioSelect(widgets.RadioSelect):
+    template_name = "core/widgets/radio_select.html"
+    option_template_name = "core/widgets/radio_select_option.html"
+
+    def __init__(self, choice_descriptions=(), *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.choice_descriptions = list(choice_descriptions)
+
+    def __deepcopy__(self, memo):
+        obj = super().__deepcopy__(memo)
+        obj.choice_descriptions = copy.copy(self.choice_descriptions)
+        return obj
+
+    def create_option(self, name, value, label, selected, index, subindex, attrs):
+        option = super().create_option(name, value, label, selected, index, subindex, attrs)
+        # this implementation does not support groups from ChoiceWidget.optgroups
+        if value in self.choice_descriptions:
+            option.update({"description": self.choice_descriptions[value]})
+
+        return option
diff --git a/benefits/eligibility/forms.py b/benefits/eligibility/forms.py
--- a/benefits/eligibility/forms.py
+++ b/benefits/eligibility/forms.py
@@ -18,14 +18,18 @@ class EligibilityVerifierSelectionForm(forms.Form):
     action_url = "eligibility:index"
     method = "POST"
 
-    verifier = forms.ChoiceField(label="", widget=forms.RadioSelect)
+    verifier = forms.ChoiceField(label="", widget=widgets.RadioSelect)
 
     submit_value = _("eligibility.buttons.continue")
 
     def __init__(self, agency: models.TransitAgency, *args, **kwargs):
         super().__init__(*args, **kwargs)
-        choices = [(v.id, _(v.selection_label)) for v in agency.eligibility_verifiers.all()]
-        self.fields["verifier"].choices = choices
+        verifiers = agency.eligibility_verifiers.all()
+
+        self.fields["verifier"].choices = [(v.id, _(v.selection_label)) for v in verifiers]
+        self.fields["verifier"].widget.choice_descriptions = {
+            v.id: _(v.selection_label_description) for v in verifiers if v.selection_label_description
+        }
 
 
 class EligibilityVerificationForm(forms.Form):


Test patch: