Security News
Fluent Assertions Faces Backlash After Abandoning Open Source Licensing
Fluent Assertions is facing backlash after dropping the Apache license for a commercial model, leaving users blindsided and questioning contributor rights.
A Torchbox-flavoured template pack for django-crispy-forms, adapted from crispy-forms-gds
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.
>=3.8.1,<4.0
>=3.2
>=2.1,<3.0
>=2.15
if using WagtailBaseForm
>=1.33.0
if building the sass yourself[!NOTE] govuk-frontend will not, and does not need to, be installed to use this package.
All form-related styles from
govuk-frontend==5.4.1
have been copied into this project with the prepended "govuk-" replaced with "tbxforms-", e.g..govuk-button
to.tbxforms-button
and@mixin govuk-clearfix
to@mixin tbxforms-clearfix
.
For non-government projects, installing the complete GOV.UK Frontend package unnecessarily increases the bundle size as we only need form-related styles.
For government projects, this increases the bundle size as both tbxforms
and
govuk-frontend
must be installed. However, these projects are less common, so
they are not prioritised.
You must install both the Python package and the NPM 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 tbxforms
:
CRISPY_ALLOWED_TEMPLATE_PACKS = ["tbx"]
CRISPY_TEMPLATE_PACK = "tbx"
Install using NPM:
npm install tbxforms
Note: This package uses the Element.closest
, NodeList.forEach
, and
Array.includes
APIs. You will need to install and configure polyfills for
legacy browser support if you need to.
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 without any customisations:
@use 'node_modules/tbxforms/dist/style.css';
...Or as Sass to customise variables:
@use 'node_modules/tbxforms/tbxforms.scss' with (
$tbxforms-text-colour: #000,
$tbxforms-error-colour: #f00,
);
tbxforms
provides out-of-the-box GOV.UK Design System styles for everything
except buttons, as styles for these probably exist within your project.
You will need to write button styles for the following classes:
.tbxforms-button
.tbxforms-button.tbxforms-button--primary
.tbxforms-button.tbxforms-button--secondary
.tbxforms-button.tbxforms-button--warning
tbxforms
can be used for coded Django forms and editor-controlled Wagtail forms.
All forms must inherit the TbxFormsMixin
mixin, as well as specifying a Django base form class (e.g. forms.Form
or forms.ModelForm
)
from django import forms
from tbxforms.forms import TbxFormsMixin
class ExampleForm(TbxFormsMixin, forms.Form):
...
class ExampleModelForm(TbxFormsMixin, forms.ModelForm):
...
Wagtail forms must inherit from TbxFormsMixin
and WagtailBaseForm
.
from wagtail.contrib.forms.forms import BaseForm as WagtailBaseForm
from tbxforms.forms import TbxFormsMixin
class ExampleWagtailForm(TbxFormsMixin, WagtailBaseForm):
...
In your form 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)
And in your form page models (e.g. models.py):
from path.to.your.forms import WagtailFormBuilder
class ExampleFormPage(...):
...
form_builder = WagtailFormBuilder
...
Just like Django Crispy Forms, you need to pass your form object to the
{% crispy ... %}
template tag, e.g.:
{% load crispy_forms_tags %}
<html>
<body>
{% crispy your_sexy_form %}
</body>
</html>
FormHelper
sA FormHelper allows you to alter the rendering behaviour of forms.
Every form that inherits from TbxFormsMixin
(i.e. every form within tbxforms
)
will have a FormHelper
with the following default attributes:
html5_required = True
label_size = Size.MEDIUM
legend_size = Size.MEDIUM
form_error_title = _("There is a problem with your submission")
These can be changed during instantiation or on the go - examples below.
Submit buttons are not automatically added to forms. To add one, you can extend
the form.helper.layout
(examples below).
Extend during instantiation:
from django import forms
from tbxforms.forms import TbxFormsMixin
from tbxforms.layout import Button
class YourSexyForm(TbxFormsMixin, forms.Form):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper.layout.extend([
Button.primary(
name="submit",
type="submit",
value="Submit",
)
])
Or afterwards:
from tbxforms.layout import Button
form = YourSexyForm()
form.helper.layout.extend([
Button.primary(
name="submit",
type="submit",
value="Submit",
)
])
tbxforms
can show/hide parts of the layout
depending on a given value. For
example, you could show (and require) an email address field only when the user
chooses to sign up to a newsletter (examples below).
You can apply this logic to field
, div
, and fieldset
elements.
Note: any field names included within the
conditional_fields_to_show_as_required()
method will appear on the frontend
as required, though will technically be required=False
.
Field example:
from django import forms
from django.core.exceptions import ValidationError
from tbxforms.choices import Choice
from tbxforms.forms import TbxFormsMixin
from tbxforms.layout import Field, Layout
class ExampleForm(TbxFormsMixin, 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)
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper.layout = Layout(
# Add our newsletter sign-up field.
Field.text("newsletter_signup"),
# Add our email field and define the conditional logic.
Field.text(
"email",
data_conditional={
"field_name": "newsletter_signup", # Field to inspect.
"values": ["yes"], # Value(s) to cause this field to show.
},
),
)
@staticmethod
def conditional_fields_to_show_as_required() -> [str]:
# Non-required fields that should show as required to the user.
return [
"email",
]
def clean(self):
cleaned_data = super().clean()
newsletter_signup = cleaned_data.get("newsletter_signup")
email = cleaned_data.get("email")
# Fields included within `conditional_fields_to_show_as_required()` will
# be shown as required but not enforced - i.e. they will not have the
# HTML5 `required` attribute set.
# Thus we need to write our own check to enforce the value exists.
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.:
from tbxforms.layout import HTML, Div, Field, Layout
Layout(
Div(
HTML("<p>Some relevant text.</p>"),
Field.text("some_other_field"),
Field.text("email"),
data_conditional={
"field_name": "newsletter_signup",
"values": ["yes"],
},
),
)
If TBXFORMS_HIGHLIGHT_REQUIRED_FIELDS=False
(or unset), optional fields will
have "(optional)" appended to their labels. This is the default behaviour and
recommended by GDS.
If TBXFORMS_HIGHLIGHT_REQUIRED_FIELDS=True
, required fields will have an
asterisk appended to their labels and optional fields will not be highlighted.
You can also style these markers by targeting these CSS classes:
.tbxforms-field_marker--required
.tbxforms-field_marker--optional
Possible values for the label_size
and legend_size
:
SMALL
MEDIUM
(default)LARGE
EXTRA_LARGE
FAQs
A Torchbox-flavoured template pack for django-crispy-forms, adapted from crispy-forms-gds
We found that tbxforms demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Fluent Assertions is facing backlash after dropping the Apache license for a commercial model, leaving users blindsided and questioning contributor rights.
Research
Security News
Socket researchers uncover the risks of a malicious Python package targeting Discord developers.
Security News
The UK is proposing a bold ban on ransomware payments by public entities to disrupt cybercrime, protect critical services, and lead global cybersecurity efforts.