From the Old to the New: The Journey to Upgrade Support for GDS’s Design System

Some time ago we shared the story of how UX Forms upgraded our support for the Government Digital Service (GDS) Front End Toolkit to the latest version. Nothing lasts forever, and GDS have since created a new Design System. As our mission is to make building forms as painless as possible, we made it our priority to provide first-class support for this new design system too.

Screenshot of GDS Design System homepage
Screenshot of GDS Design System homepage
GDS Design System homepage

The new Design System templates are all hugely different, highly parameterised, and implemented in Nunjucks, which is a great templating language — but comes with constraints. In particular, key aspects of the JavaScript-based Nunjucks run counter to GDS’s own rules on usability and accessibility.

This approach works for throwaway prototypes that ultimately don’t see the light of day, but our question became: if the requirements are there to aid users, shouldn’t they aid those using prototypes, too?

The more we compared GDS’s old Elements to the new Design System, the more we realised just how different they are. So much so that our basic components, such as widget implementations, were no longer a good fit. So we embarked on a journey to build an entirely new set of widgets.

Due to the technical constraints of Nunjucks, we reviewed our options. Mustache is an excellent templating tool with mature and robust implementations in many languages. As our existing clients were already familiar with it, that made it our default choice.

The challenge now became how to best keep the new Design System in sync with GDS’s government-approved front-end. The good news was that we soon had an opportunity to check how easy it was to update things, as GDS had already released a few new versions.

The steps to follow were quite clear:

  1. Bump the version of GDS’s govuk-frontend that we depend on
  2. Use git to enumerate all of the differences in the govuk-frontend project between the two versions
  3. Apply all relevant template changes to our own Mustache templates
  4. Pull through any new behaviours into our corresponding widget implementations

Here is the full set of changes we needed, along with a supporting change to the Input widget in order to explicitly pass through the new template parameters.

Let’s look at the templates for a very simple component — inset text.

A screenshot of GDS’s Design System page describing their Inset Text component
A screenshot of GDS’s Design System page describing their Inset Text component
Inset Text page on GDS’s Design System

GDS’s Nunjucks template:

<div {%- if %} id=”{{ }}”{% endif %} 
class=”govuk-inset-text {%- if params.classes %} {{ params.classes }}{% endif %}”
{%- for attribute, value in params.attributes %} {{attribute}}=”{{value}}”{% endfor %}
{{ params.html | safe if params.html else params.text }}

Our Mustache template:

<div {{}}id=”{{ . }}”{{/}} 
class=”govuk-inset-text {{insetText.classes }}”
{{#insetText.attributes }} {{attribute}}=”{{value}}”{{/insetText.attributes}}
{{{ insetText.html }}}
{{ insetText.text }}

In short, this is a literal translation from one template language to another. Mustache doesn’t support anything like Nunjucks’ logic, but that’s a conscious design decision on their part. In this case the logic doesn’t really matter — if the insetText.classes value is empty, it will just write out an empty string. Likewise with the insetText.html and insetText.text.

But there is one important difference here — we want to allow form authors to write out html within our widgets if they so desire. Blocking that would prevent styling within an inset text component, so we choose to write out insetText.html without any html escaping, but insetText.text is escaped. That way the author can make a conscious decision on which is more appropriate for their specific need.

Then using our new InsetText widget in your form is as simple as adding this single line:

InsetText.insetText("itName", messages)

There’s no better way to show off what can be done with UX Forms than a form running in UX Forms, so we built a demo form to show off how our new widgets and theme can play together to deliver precisely the html and css that GDS have defined in their design system.

This is a living example — it shows all of the components, styles and patterns that we have implemented from GDS’s Design System, along with instructions for how to use them in your form. So over to you, and good luck!

A screenshot of UX Forms’ demo form that shows how to use GDS’s Design System in UX Forms
A screenshot of UX Forms’ demo form that shows how to use GDS’s Design System in UX Forms
UX Forms’ demo form, showing how to use patterns from GDS’s Design System

Everything that we did as part of this work to add support for this design system was all done with the same toolset that our customers have. The new theme built with a compile-time dependency on GDS’s govuk-frontend artifact, and the new library with the new supporting widgets, were all built without changing any of the internals of UX Forms itself. Our customers can build new widgets just like this, write new templates for custom HTML, and add whatever CSS, JavaScript and images they like to support the user journey they want. UX Forms is completely UI-agnostic, only in this case we’ve done the work to implement this particular design system so our customers don’t have to.

This is what makes UX Forms unique — the degree of power and flexibility that form authors have in controlling how their forms look and behave. If you have a challenging form to build and want to save the expense, time and risk of building it from scratch yourself, then get in touch and see how UX Forms can help you deliver better forms, faster.

Want to know more?

Come have a look around, follow UX Forms on twitter, LinkedIn, or email us at and see how we can make your forms better, together.

An enterprise-ready cloud platform for webform development. See our website for more:

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store