{"id":13742060,"url":"https://github.com/LandRegistry/govuk-frontend-wtf","last_synced_at":"2025-05-08T22:33:03.085Z","repository":{"id":39993344,"uuid":"335013090","full_name":"LandRegistry/govuk-frontend-wtf","owner":"LandRegistry","description":"GOV.UK Frontend WTForms Widgets","archived":false,"fork":false,"pushed_at":"2025-03-06T08:51:52.000Z","size":216,"stargazers_count":17,"open_issues_count":13,"forks_count":7,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-04-23T22:46:33.627Z","etag":null,"topics":["components","flask","frontend","govuk","govuk-frontend","jinja","python","widgets","wtforms"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/govuk-frontend-wtf/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LandRegistry.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-02-01T16:31:30.000Z","updated_at":"2025-01-13T11:46:25.000Z","dependencies_parsed_at":"2023-02-13T00:15:50.707Z","dependency_job_id":"2a1ad439-f992-4ab2-93a8-2cb5d9aad5a2","html_url":"https://github.com/LandRegistry/govuk-frontend-wtf","commit_stats":{"total_commits":207,"total_committers":10,"mean_commits":20.7,"dds":"0.18840579710144922","last_synced_commit":"3701b80dd4f7d44c2a06a3a4de694fce427d6143"},"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LandRegistry%2Fgovuk-frontend-wtf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LandRegistry%2Fgovuk-frontend-wtf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LandRegistry%2Fgovuk-frontend-wtf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LandRegistry%2Fgovuk-frontend-wtf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LandRegistry","download_url":"https://codeload.github.com/LandRegistry/govuk-frontend-wtf/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253158689,"owners_count":21863358,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["components","flask","frontend","govuk","govuk-frontend","jinja","python","widgets","wtforms"],"created_at":"2024-08-03T04:01:06.449Z","updated_at":"2025-05-08T22:33:03.069Z","avatar_url":"https://github.com/LandRegistry.png","language":"Python","funding_links":[],"categories":["Uncategorized"],"sub_categories":["Uncategorized"],"readme":"# GOV.UK Frontend WTForms Widgets\n\n[![PyPI version](https://badge.fury.io/py/govuk-frontend-wtf.svg)](https://pypi.org/project/govuk-frontend-wtf/)\n![govuk-frontend 5.7.1](https://img.shields.io/badge/govuk--frontend%20version-5.7.1-005EA5?logo=gov.uk\u0026style=flat)\n[![Python package](https://github.com/LandRegistry/govuk-frontend-wtf/actions/workflows/python-package.yml/badge.svg)](https://github.com/LandRegistry/govuk-frontend-wtf/actions/workflows/python-package.yml)\n\n**GOV.UK Frontend WTForms is a [community tool](https://design-system.service.gov.uk/community/resources-and-tools/) of the [GOV.UK Design System](https://design-system.service.gov.uk/). The Design System team is not responsible for it and cannot support you with using it. Contact the [maintainers](#contributors) directly if you need [help](#support) or you want to request a feature.**\n\nThis repository contains a set of [WTForms widgets](https://wtforms.readthedocs.io/en/3.1.x/widgets/) used to render [WTForm fields](https://wtforms.readthedocs.io/en/3.1.x/fields/) using [GOV.UK Frontend](https://design-system.service.gov.uk/) component styling. This is done using Jinja macros from the [GOV.UK Frontend Jinja](https://github.com/LandRegistry/govuk-frontend-jinja) port of the original GOV.UK Frontend Nunjucks macros. These are kept up-to-date with GOV.UK Frontend releases, are thoroughly tested and produce 100% equivalent markup.\n\nThis approach also renders the associated error messages in the appropriate place, shows the error summary component at the top of the page and sets all related accessibility ARIA attributes. Adding the appropriate [widget](#widgets) to your existing form Python class, along with far simpler templates, makes it quick and easy to produce fully GOV.UK compliant forms.\n\nIf you are looking to build a fully featured Flask app that integrates with [GOV.UK Frontend Jinja](https://github.com/LandRegistry/govuk-frontend-jinja) and [GOV.UK Frontend WTForms](https://github.com/LandRegistry/govuk-frontend-wtf) please use the [GOV.UK Frontend Flask](https://github.com/LandRegistry/govuk-frontend-flask) template repository to [generate your app](https://github.com/LandRegistry/govuk-frontend-flask/generate).\n\n## How to use\n\nFor more detailed examples please refer to the [demo app source code](https://github.com/LandRegistry/govuk-frontend-wtf-demo).\n\nAfter running `pip install govuk-frontend-wtf`, ensure that you tell Jinja where to load the templates from using the `PackageLoader`, register `WTFormsHelpers`, then set an environment variable for `SECRET_KEY`.\n\n`app/__init__.py`:\n\n```python\nfrom flask import Flask\nfrom govuk_frontend_wtf.main import WTFormsHelpers\nfrom jinja2 import ChoiceLoader, PackageLoader, PrefixLoader\n\napp = Flask(__name__)\napp.config[\"SECRET_KEY\"] = os.environ.get(\"SECRET_KEY\")\n\napp.jinja_loader = ChoiceLoader(\n    [\n        PackageLoader(\"app\"),\n        PrefixLoader(\n            {\n                \"govuk_frontend_jinja\": PackageLoader(\"govuk_frontend_jinja\"),\n                \"govuk_frontend_wtf\": PackageLoader(\"govuk_frontend_wtf\"),\n            }\n        ),\n    ]\n)\n\nWTFormsHelpers(app)\n```\n\nImport and include the relevant widget on each field in your form class (see [table below](#widgets)). Note that in this example `widget=GovTextInput()` is the only difference relative to a standard Flask-WTF form definition.\n\n`app/forms.py`:\n\n```python\nfrom flask_wtf import FlaskForm\nfrom govuk_frontend_wtf.wtforms_widgets import GovSubmitInput, GovTextInput\nfrom wtforms import StringField, SubmitField\nfrom wtforms.validators import Email, InputRequired, Length\n\n\nclass ExampleForm(FlaskForm):\n    email_address = StringField(\n        \"Email address\",\n        widget=GovTextInput(),\n        validators=[\n            InputRequired(message=\"Enter an email address\"),\n            Length(max=256, message=\"Email address must be 256 characters or fewer\"),\n            Email(message=\"Enter an email address in the correct format, like name@example.com\"),\n        ],\n        description=\"We’ll only use this to send you a receipt\",\n    )\n\n    submit = SubmitField(\"Continue\", widget=GovSubmitInput())\n```\n\nCreate a route to serve your form and template.\n\n`app/routes.py`:\n\n```python\nfrom flask import redirect, render_template, url_for\n\nfrom app import app\nfrom app.forms import ExampleForm\n\n@app.route(\"/\")\ndef index():\n    return render_template(\"index.html\")\n\n\n@app.route(\"/example-form\", methods=[\"GET\", \"POST\"])\ndef example():\n    form = ExampleForm()\n    if form.validate_on_submit():\n        return redirect(url_for(\"index\"))\n    return render_template(\"example_form.html\", form=form)\n```\n\nFinally, in your template set the page title appropriately if there are any form validation errors, as per [GOV.UK Design System guidance](https://design-system.service.gov.uk/components/error-summary/#how-it-works). Include the `govukErrorSummary()` component at the start of the `content` block. Pass parameters in a dictionary to your form field as per the associated [component macro options](https://design-system.service.gov.uk/components/).\n\n`app/templates/example_form.html`:\n\n```html\n{% extends \"base.html\" %}\n\n{%- from 'govuk_frontend_jinja/components/error-summary/macro.html' import govukErrorSummary -%}\n\n{% block pageTitle %}{%- if form and form.errors %}Error: {% endif -%}Example form – GOV.UK Frontend WTForms Demo{% endblock %}\n\n{% block content %}\n\u003cdiv class=\"govuk-grid-row\"\u003e\n    \u003cdiv class=\"govuk-grid-column-two-thirds\"\u003e\n        {% if form.errors %}\n            {{ govukErrorSummary(wtforms_errors(form)) }}\n        {% endif %}\n\n        \u003ch1 class=\"govuk-heading-xl\"\u003eExample form\u003c/h1\u003e\n\n        \u003cform action=\"\" method=\"post\" novalidate\u003e\n            {{ form.csrf_token }}\n            \n            {{ form.email_address(params={\n              'type': 'email',\n              'autocomplete': 'email',\n              'spellcheck': false\n            }) }}\n            \n            {{ form.submit }}\n        \u003c/form\u003e\n    \u003c/div\u003e\n\u003c/div\u003e\n{% endblock %}\n```\n\n## Widgets\n\nThe available widgets and their corresponding Flask-WTF field types are as follows:\n\n| WTForms Field                                                                                             | GOV.​UK Widget(s)              | Notes                                                                                                                                      |\n| --------------------------------------------------------------------------------------------------------- | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ |\n| [BooleanField](https://wtforms.readthedocs.io/en/3.1.x/fields/#wtforms.fields.BooleanField)               | GovCheckboxInput               |                                                                                                                                            |\n| [DateField](https://wtforms.readthedocs.io/en/3.1.x/fields/#wtforms.fields.DateField)                     | GovDateInput                   |                                                                                                                                            |\n| [DateTimeField](https://wtforms.readthedocs.io/en/3.1.x/fields/#wtforms.fields.DateTimeField)             | GovDateInput                   |                                                                                                                                            |\n| [DecimalField](https://wtforms.readthedocs.io/en/3.1.x/fields/#wtforms.fields.DecimalField)               | GovTextInput                   |                                                                                                                                            |\n| [FileField](https://wtforms.readthedocs.io/en/3.1.x/fields/#wtforms.fields.FileField)                     | GovFileInput                   |                                                                                                                                            |\n| [MultipleFileField](https://wtforms.readthedocs.io/en/3.1.x/fields/#wtforms.fields.MultipleFileField)     | GovFileInput(multiple=True)    | Note that you need to specify `multiple=True` when invoking the widget in your form class. _Not_ when you render it in the Jinja template. |\n| [FloatField](https://wtforms.readthedocs.io/en/3.1.x/fields/#wtforms.fields.FloatField)                   | GovTextInput                   |                                                                                                                                            |\n| [IntegerField](https://wtforms.readthedocs.io/en/3.1.x/fields/#wtforms.fields.IntegerField)               | GovTextInput                   | Use `params` to specify a `type` if you need to use HTML5 number elements. This will not happen automatically.                             |\n| [PasswordField](https://wtforms.readthedocs.io/en/3.1.x/fields/#wtforms.fields.PasswordField)             | GovPasswordInput               |                                                                                                                                            |\n| [RadioField](https://wtforms.readthedocs.io/en/3.1.x/fields/#wtforms.fields.RadioField)                   | GovRadioInput                  |                                                                                                                                            |\n| [SelectField](https://wtforms.readthedocs.io/en/3.1.x/fields/#wtforms.fields.SelectField)                 | GovSelect                      |                                                                                                                                            |\n| [SelectMultipleField](https://wtforms.readthedocs.io/en/3.1.x/fields/#wtforms.fields.SelectMultipleField) | GovCheckboxesInput             | Note that this renders checkboxes as `\u003cselect multiple\u003e` elements are frowned upon.                                                        |\n| [SubmitField](https://wtforms.readthedocs.io/en/3.1.x/fields/#wtforms.fields.SubmitField)                 | GovSubmitInput                 |                                                                                                                                            |\n| [StringField](https://wtforms.readthedocs.io/en/3.1.x/fields/#wtforms.fields.StringField)                 | GovTextInput                   |                                                                                                                                            |\n| [TextAreaField](https://wtforms.readthedocs.io/en/3.1.x/fields/#wtforms.fields.TextAreaField)             | GovTextArea, GovCharacterCount |                                                                                                                                            |\n\nIn order to generate things like email fields using `GovTextInput` you will need to pass additional params through when rendering it as follows:\n\n```html\n{{ form.email_address(params={'type': 'email', 'autocomplete': 'email', 'spellcheck': false}) }}\n```\n\n## Running the tests\n\n```shell\npython3 -m venv venv\nsource venv/bin/activate\npip install -r tests/requirements.txt\npytest --cov=govuk_frontend_wtf --cov-report=term-missing --cov-branch\n```\n\n## Versioning\n\nWe use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/LandRegistry/govuk-frontend-wtf/tags).\n\n## How to contribute\n\nWe welcome contribution from the community. If you want to contribute to this project, please review the [code of conduct](CODE_OF_CONDUCT.md) and [contribution guidelines](CONTRIBUTING.md).\n\n## Contributors\n\n- [Matt Shaw](https://github.com/matthew-shaw) (Primary maintainer)\n- [Andy Mantell](https://github.com/andymantell) (Original author)\n\nSee the full list of [contributors on GitHub](https://github.com/LandRegistry/govuk-frontend-wtf/graphs/contributors)\n\n## Support\n\nThis software is provided _\"as-is\"_ without warranty. Support is provided on a _\"best endeavours\"_ basis by the maintainers and open source community.\n\nIf you are a civil servant you can sign up to the [UK Government Digital Slack](https://ukgovernmentdigital.slack.com/signup) workspace to contact the maintainers listed [above](#contributors) and the community of people using this project in the [#govuk-design-system](https://ukgovernmentdigital.slack.com/archives/C6DMEH5R6) channel.\n\nOtherwise, please see the [contribution guidelines](CONTRIBUTING.md) for how to raise a bug report or feature request.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FLandRegistry%2Fgovuk-frontend-wtf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FLandRegistry%2Fgovuk-frontend-wtf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FLandRegistry%2Fgovuk-frontend-wtf/lists"}