A Torchbox-flavoured template pack for django-crispy-forms, adapted from crispy-forms-gds
Project description
Torchbox Forms
A Torchbox-flavoured template pack for django-crispy-forms, adapted from crispy-forms-gds.
Out of the box, forms created with tbxforms
will look like the
GOV.UK Design System, though many
variables can be customised.
Contents
Installation
You must install both a Python package and an NPM package.
Install the Python package
Install using pip:
pip install tbxforms
Add django-crispy-forms
and tbxforms
to your installed apps:
INSTALLED_APPS = [
...
'crispy_forms', # django-crispy-forms
'tbxforms',
]
Now add the following settings to tell django-crispy-forms
to use this theme:
CRISPY_ALLOWED_TEMPLATE_PACKS = ["tbx"]
CRISPY_TEMPLATE_PACK = "tbx"
Install the NPM package
Install using NPM:
npm install tbxforms
Instantiate your forms:
import TbxForms from 'tbxforms';
document.addEventListener('DOMContentLoaded', () => {
for (const form of document.querySelectorAll(TbxForms.selector())) {
new TbxForms(form);
}
});
Import the styles into your project, either as CSS:
// Either as CSS without any customisations:
@use 'node_modules/tbxforms/style.css';
Or as Sass, to customise variables:
// Or as Sass, with variables to customise:
@use 'node_modules/tbxforms/tbxforms.scss' with (
$tbxforms-error-colour: #f00,
$tbxforms-text-colour: #000,
);
Variables can also be defined in a centralised variables SCSS file, too.
See tbxforms/static/sass/abstracts/_variables.scss for customisable variables.
Usage
Create a Django form
from tbxforms.forms import BaseForm as TbxFormsBaseForm
class ExampleForm(TbxFormsBaseForm, forms.Form):
# < Your field definitions >
class ExampleModelForm(TbxFormsBaseForm, forms.ModelForm):
# < Your field definitions and ModelForm config >
Create a Wagtail form
Two parts are required for this to work:
- Add a
helper
property to the Wagtail form - Instruct a Wagtail Page model to use the newly created form
Add a helper
property to the Wagtail form
from wagtail.contrib.forms.forms import BaseForm as WagtailBaseForm
from tbxforms.forms import BaseForm as TbxFormsBaseForm
class ExampleWagtailForm(TbxFormsBaseForm, WagtailBaseForm):
# Extend the `TbxFormsBaseForm.helper()` to add a submit button.
@property
def helper(self):
fh = super().helper
fh.add_input(
Button.primary(
name="submit",
type="submit",
value=_("Submit"),
)
)
return fh
Instruct a Wagtail Page model to use the newly created form
# -----------------------------------------------------------------------------
# in your forms definitions (e.g. forms.py)
from tbxforms.forms import BaseWagtailFormBuilder as TbxFormsBaseWagtailFormBuilder
from path.to.your.forms import ExampleWagtailForm
class WagtailFormBuilder(TbxFormsBaseWagtailFormBuilder):
def get_form_class(self):
return type(str("WagtailForm"), (ExampleWagtailForm,), self.formfields)
# -----------------------------------------------------------------------------
# in your page models (e.g. models.py)
from path.to.your.forms import WagtailFormBuilder
class ExampleFormPage(...):
...
form_builder = WagtailFormBuilder
...
Render a form
Just like Django Crispy Forms, you need to pass your form object to the
{% crispy ... %}
template tag, e.g.:
{% load crispy_forms_tags %}
{% crispy your_form %}
Customise a form's attributes (via the helper
property)
By default, every form that inherits from TbxFormsBaseForm
will have the following
attributes set:
html5_required = True
label_size = Size.MEDIUM
legend_size = Size.MEDIUM
form_error_title = _("There is a problem with your submission")
- Plus everything from django-crispy-forms' default attributes.
These can be overridden (and/or additional attributes from the above list defined) just like you would do with any other inherited class, e.g.:
class YourSexyForm(TbxFormsBaseForm, forms.Form):
@property
def helper(self):
fh = super().helper
fh.html5_required = False
fh.label_size = Size.SMALL
fh.form_error_title = _("Something's wrong, yo.")
return fh
Possible values for the label_size
and legend_size
:
SMALL
MEDIUM
(default)LARGE
EXTRA_LARGE
Conditionally-required fields
tbxforms
supports hiding/showing of fields and/or div
/fieldset
elements
based on the values of a given input field.
Field example:
class ExampleForm(TbxFormsBaseForm, forms.Form):
NEWSLETTER_CHOICES = (
Choice("yes", "Yes please", hint="Receive occasional email newsletters."),
Choice("no", "No thanks"),
)
newsletter_signup = forms.ChoiceField(
choices=NEWSLETTER_CHOICES
)
email = forms.EmailField(
widget=forms.EmailInput(required=False)
)
@staticmethod
def conditional_fields_to_show_as_required() -> [str]:
return [
"email", # Include any fields that should show as required to the user.
]
@property
def helper(self):
fh = super().helper
# Override what is rendered for this form.
fh.layout = Layout(
# Add our newsletter sign-up field.
Field("newsletter_signup"),
# Add our email field, and define the conditional 'show' logic.
Field(
"email",
data_conditional={
"field_name": "newsletter_signup", # Field to inspect.
"values": ["yes"], # Value(s) to cause this field to show.
},
),
)
return fh
def clean(self):
cleaned_data = super().clean()
newsletter_signup = cleaned_data.get("newsletter_signup")
email = cleaned_data.get("email")
# Assuming `form.helper.html5_required == True`, tbxforms will toggle the
# html5 'required' attribute when a conditionally-required field is shown,
# though it is recommended to also check the value in your clean() method.
if newsletter_signup == "yes" and not email:
raise ValidationError(
{
"email": _("This field is required."),
}
)
# The tbxforms JS will attempt to clear any redundant data upon submission,
# though it is recommended to also handle this in your clean() method.
elif newsletter_signup == "no" and email:
del cleaned_data['email']
return cleaned_data
Container example:
When you have multiple fields/elements that you want to show/hide together, you
can use the exact same data_conditional
definition as above but on a div
or
fieldset
element, e.g.:
Div(
HTML("<p>Some relevant text.</p>"),
Field("some_other_field"),
Field("email"),
data_conditional={
"field_name": "newsletter_signup",
"values": ["yes"],
},
),
Further reading
- Download the PyPi package
- Download the NPM package
- Learn more about Django Crispy Forms
- Learn more about Crispy Forms GDS
- Learn more about GOV.UK Design System
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.