From 6751c836e3c8dffe135a309b8d54929e975a312e Mon Sep 17 00:00:00 2001
From: Daniel Miller
Date: Tue, 10 Dec 2024 14:55:03 -0500
Subject: [PATCH 01/12] Document responsive form layout on Bootstrap 5
---
.../templates/styleguide/bootstrap5/organisms/forms.html | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/corehq/apps/styleguide/templates/styleguide/bootstrap5/organisms/forms.html b/corehq/apps/styleguide/templates/styleguide/bootstrap5/organisms/forms.html
index 604b659a84b0..43d6336dc849 100644
--- a/corehq/apps/styleguide/templates/styleguide/bootstrap5/organisms/forms.html
+++ b/corehq/apps/styleguide/templates/styleguide/bootstrap5/organisms/forms.html
@@ -60,9 +60,16 @@
Overview
Different parts of HQ use these two approaches, and you should always consider existing context
when deciding whether to use Crispy Forms or HTML.
+
+ Form layouts are responsive. On wide screens, labels are arranged in a column to the left and input fields are
+ arranged in a wider column to the right. In Bootstrap 5 this is referred to as
+ horizontal form layout. On
+ narrow screens such as mobile devices, the layout automatically collapses to a single column with each label
+ above its corresponding input control.
+
The benefit of Crispy Forms, and why you should opt for using it over bespoke HTML whenever possible,
- is that the HTML for each form component is controlled by templates. From HTML is often affected
+ is that the HTML for each form component is controlled by templates. Form HTML is often affected
during a front-end migration (like Bootstrap). If a bespoke HTML form was used, that HTML needs
to be re-examined everywhere.
However, for forms using Crispy Forms, the relevant HTML only has to be changed once in the templates,
From 3552c8f9e1031261b0ef720a681adf2e08b7d625 Mon Sep 17 00:00:00 2001
From: Daniel Miller
Date: Tue, 10 Dec 2024 14:59:34 -0500
Subject: [PATCH 02/12] B5 crispy horizontal forms
---
corehq/apps/hqwebapp/crispy.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/corehq/apps/hqwebapp/crispy.py b/corehq/apps/hqwebapp/crispy.py
index fceb944f7fa9..0957bb339719 100644
--- a/corehq/apps/hqwebapp/crispy.py
+++ b/corehq/apps/hqwebapp/crispy.py
@@ -34,7 +34,6 @@ def __init__(self, *args, **kwargs):
self.label_class = CSS_LABEL_CLASS_BOOTSTRAP5
self.field_class = CSS_FIELD_CLASS_BOOTSTRAP5
self.use_bootstrap5 = use_bootstrap5
- self.form_class = 'form'
if 'autocomplete' not in self.attrs:
self.attrs.update({
From 1cabe25b161ccd247ffe44bd85d708fc3010db61 Mon Sep 17 00:00:00 2001
From: Daniel Miller
Date: Tue, 10 Dec 2024 15:26:43 -0500
Subject: [PATCH 03/12] Remove redundant B5 form class assignemnts
---
corehq/apps/app_execution/forms.py | 1 -
corehq/apps/domain/forms.py | 1 -
corehq/motech/forms.py | 1 -
corehq/motech/repeaters/forms.py | 1 -
4 files changed, 4 deletions(-)
diff --git a/corehq/apps/app_execution/forms.py b/corehq/apps/app_execution/forms.py
index 317500f3c30e..7e6e40f0d1db 100644
--- a/corehq/apps/app_execution/forms.py
+++ b/corehq/apps/app_execution/forms.py
@@ -57,7 +57,6 @@ def __init__(self, request, *args, **kwargs):
if self.instance.id:
self.fields["username"].initial = self.instance.django_user.username
self.helper = hqcrispy.HQFormHelper()
- self.helper.form_class = "form-horizontal"
fields = [
"name",
diff --git a/corehq/apps/domain/forms.py b/corehq/apps/domain/forms.py
index c24ecc4f92d9..51a61cafbc61 100644
--- a/corehq/apps/domain/forms.py
+++ b/corehq/apps/domain/forms.py
@@ -1273,7 +1273,6 @@ def __init__(self, domain, can_edit_eula, *args, user, **kwargs):
)
self.helper = hqcrispy.HQFormHelper()
- self.helper.form_class = "form-horizontal"
self.helper.layout = crispy.Layout(
crispy.Fieldset(
_("Basic Information"),
diff --git a/corehq/motech/forms.py b/corehq/motech/forms.py
index 30e92b2773aa..fda4f35775c3 100644
--- a/corehq/motech/forms.py
+++ b/corehq/motech/forms.py
@@ -144,7 +144,6 @@ def helper(self):
from corehq.motech.views import ConnectionSettingsListView
helper = hqcrispy.HQFormHelper()
- helper.form_class = "form-horizontal"
helper.layout = crispy.Layout(
crispy.Field('name'),
crispy.Field('notify_addresses_str'),
diff --git a/corehq/motech/repeaters/forms.py b/corehq/motech/repeaters/forms.py
index 88c3b45e7135..0907c3822153 100644
--- a/corehq/motech/repeaters/forms.py
+++ b/corehq/motech/repeaters/forms.py
@@ -72,7 +72,6 @@ def set_extra_django_form_fields(self):
def _initialize_crispy_layout(self):
self.helper = hqcrispy.HQFormHelper(self)
- self.helper.form_class = 'form-horizontal'
self.helper.layout = crispy.Layout(
crispy.Fieldset(
From 1ac2e1fa390ef1dfbc46b885f0a63c6d6c6877a6 Mon Sep 17 00:00:00 2001
From: Daniel Miller
Date: Tue, 10 Dec 2024 15:06:40 -0500
Subject: [PATCH 04/12] Adjust column widths for crispy horizontal forms
Make it easier to associate label with field on wide screens.
Restore large-screen (lg) column widths used with Bootstrap 3.
Tweak medium-screen (md) column widths to improve consistency.
---
corehq/apps/hqwebapp/crispy.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/corehq/apps/hqwebapp/crispy.py b/corehq/apps/hqwebapp/crispy.py
index 0957bb339719..e3a064e2ae89 100644
--- a/corehq/apps/hqwebapp/crispy.py
+++ b/corehq/apps/hqwebapp/crispy.py
@@ -14,9 +14,9 @@
from crispy_forms.utils import flatatt, get_template_pack, render_field
CSS_LABEL_CLASS = 'col-xs-12 col-sm-4 col-md-4 col-lg-2'
-CSS_LABEL_CLASS_BOOTSTRAP5 = 'col-xs-12 col-sm-4 col-md-4 col-lg-3'
+CSS_LABEL_CLASS_BOOTSTRAP5 = 'col-xs-12 col-sm-4 col-md-3 col-lg-2'
CSS_FIELD_CLASS = 'col-xs-12 col-sm-8 col-md-8 col-lg-6'
-CSS_FIELD_CLASS_BOOTSTRAP5 = 'col-xs-12 col-sm-8 col-md-8 col-lg-9'
+CSS_FIELD_CLASS_BOOTSTRAP5 = 'col-xs-12 col-sm-8 col-md-9 col-lg-10'
CSS_ACTION_CLASS = CSS_FIELD_CLASS + ' col-sm-offset-4 col-md-offset-4 col-lg-offset-2'
From ba970600b7326e79308da3d868510619cc5324ea Mon Sep 17 00:00:00 2001
From: Daniel Miller
Date: Thu, 12 Dec 2024 11:10:07 -0500
Subject: [PATCH 05/12] Form style extensions to simplify field classes
Should reduce the overhead of future site-wide style changes such as when upgrading Bootstrap.
---
corehq/apps/hqwebapp/crispy.py | 6 +++---
.../static/hqwebapp/scss/commcarehq/_forms.scss | 13 +++++++++++++
2 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/corehq/apps/hqwebapp/crispy.py b/corehq/apps/hqwebapp/crispy.py
index e3a064e2ae89..602ec696c3f6 100644
--- a/corehq/apps/hqwebapp/crispy.py
+++ b/corehq/apps/hqwebapp/crispy.py
@@ -14,9 +14,9 @@
from crispy_forms.utils import flatatt, get_template_pack, render_field
CSS_LABEL_CLASS = 'col-xs-12 col-sm-4 col-md-4 col-lg-2'
-CSS_LABEL_CLASS_BOOTSTRAP5 = 'col-xs-12 col-sm-4 col-md-3 col-lg-2'
+CSS_LABEL_CLASS_BOOTSTRAP5 = 'field-label'
CSS_FIELD_CLASS = 'col-xs-12 col-sm-8 col-md-8 col-lg-6'
-CSS_FIELD_CLASS_BOOTSTRAP5 = 'col-xs-12 col-sm-8 col-md-9 col-lg-10'
+CSS_FIELD_CLASS_BOOTSTRAP5 = 'field-control'
CSS_ACTION_CLASS = CSS_FIELD_CLASS + ' col-sm-offset-4 col-md-offset-4 col-lg-offset-2'
@@ -76,7 +76,7 @@ class ErrorsOnlyField(Field):
def get_form_action_class():
"""This is only valid for bootstrap 5"""
- return CSS_LABEL_CLASS_BOOTSTRAP5.replace('col', 'offset') + ' ' + CSS_FIELD_CLASS_BOOTSTRAP5
+ return CSS_FIELD_CLASS_BOOTSTRAP5
def _get_offsets(context):
diff --git a/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq/_forms.scss b/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq/_forms.scss
index 481acf947bd2..2f7aef91a69d 100644
--- a/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq/_forms.scss
+++ b/corehq/apps/hqwebapp/static/hqwebapp/scss/commcarehq/_forms.scss
@@ -1,3 +1,16 @@
+.field-label {
+ @extend .col-form-label, .col-12, .col-sm-4, .col-md-3, .col-lg-2;
+}
+
+.field-label + .field-control {
+ @extend .col-12, .col-sm-8, .col-md-9, .col-lg-10;
+}
+
+:not(.field-label) + .field-control,
+.row > .field-control:first-child {
+ @extend .offset-sm-4, .offset-md-3, .offset-lg-2;
+}
+
.row > div > .form-check:first-child,
.row > div > .input-group > .form-check:first-child {
padding-top: add($input-padding-y, $input-border-width);
From af45509d3eff9846ef2c11df5ad4f87beec12872 Mon Sep 17 00:00:00 2001
From: Daniel Miller
Date: Thu, 12 Dec 2024 11:15:47 -0500
Subject: [PATCH 06/12] Simplify field classes in styleguide examples
---
.../bootstrap5/examples/basic_form.html | 23 ++++++-----------
.../examples/checkbox_horizontal_form.html | 12 ++++-----
.../bootstrap5/examples/disabled_fields.html | 25 ++++++++-----------
.../bootstrap5/examples/form_invalid.html | 15 +++++------
.../bootstrap5/examples/form_valid.html | 15 +++++------
.../examples/placeholder_help_text.html | 5 ++--
6 files changed, 37 insertions(+), 58 deletions(-)
diff --git a/corehq/apps/styleguide/templates/styleguide/bootstrap5/examples/basic_form.html b/corehq/apps/styleguide/templates/styleguide/bootstrap5/examples/basic_form.html
index b8141230cc9d..3adca1f544b0 100644
--- a/corehq/apps/styleguide/templates/styleguide/bootstrap5/examples/basic_form.html
+++ b/corehq/apps/styleguide/templates/styleguide/bootstrap5/examples/basic_form.html
@@ -4,15 +4,10 @@