Skip to main content
Open Innovations is winding down and will no longer be commencing new work from May 2026.

Making better feedback forms

Over the years we've occasionally needed feedback forms for events. Sometimes we've received survey data that has been collected by another organisation. In all these cases the forms were hosted by 3rd-party websites.

Issues with 3rd-party forms

  • Some corporate firewalls block Google Forms which limits responses.
  • The websites for third-party forms aren't usually optimised. That results in excessive bandwidth requirements and high CO2 emissions e.g. one Google form I filled in recently was over 7MB in size and a recent forms.app form that we created was over 4MB for only six questions!
  • There are usually limits to how much we can customise the look and feel of forms
  • Using a third party for a form generally has GDPR implications around data/tracking.
  • Sometimes we've wanted to be able to have repeating groups of questions and that hasn't seemed to be something that can be done easily. For instance to monitor the impact of a festival, hosts were asked to submit details about their events. Hosts with multiple events ended up trying to add attendance numbers for multiple events into one form field. In some cases a host might add up all the figures into one (not helpful when we need per-event breakdowns) or they might enter them as, say, "35 + 24 + 29" (not easy to automatically deal with everyone's inconsistent formatting). We'd prefer to have a group of questions for an event that can be duplicated as many times as needed by the respondent.

These thoughts have been at the back of my mind for a number of years but it was the recent need to make a feedback form that finally made me do something about it. So I've built our own lightweight feedback form system. This blog post is to document what I did in the open (👋 hello future me trying to remember what I did).

Defining a form

I'm defining each of our new forms with a simple JSON file (example below) that contains the metadata and the questions. I've defined 12 question types so far:

  1. text - some text
  2. textarea - text that spans multiple lines
  3. number - an HTML number input
  4. numeric - like number but follows GDS's accessibility observations on number input
  5. radio - only one option can be selected at the same time
  6. rating - based on radio but it highlights all the values up to the selected one so would be useful for star ratings
  7. checkbox - multiple options can be selected
  8. select - one option can be selected from a drop-down list
  9. date - a date using an HTML date input
  10. datetime-local - a date and time using an HTML datetime-local input
  11. url - a web address using an HTML url input
  12. colour/color - a colour picker using an HTML color input

There are also plans to add a repeat-group type - which will create a group of further questions that can be duplicated as necessary - but I haven't got around to implementing this yet.

Here's the JSON structure we are using to define the form:

{
"author": "slowe",
"title": "Example form",
"logo": "Some SVG logo here",
"style": "Some form-specific CSS here",
"class": {
"body": "b5-bg",
"send": "c8-bg"
},
"dates": {
"open": "2024-01-17T00:00Z",
"close": "2030-01-31T00:00Z"
},
"text": {
"intro": "Some introductory text",
"outro": "Some outro text that goes before the submit button.",
"footer": "Some footer text.",
"unopened": "This feedback survey is not yet open. Please try again on 2024-01-25T15:02+0000.",
"closed": "This survey closed on 2024-01-25T15:02+0000",
"send": "Send my answers",
"saved": "Thank you for sending us your feedback."
},
"questions": [{
"type": "text",
"column": "Name of column in CSV",
"question": "What is a question?",
"pre": "Some text before the input field",
"maxlength": 200,
"pattern": "[A-Za-z0-9\\s]*",
"placeholder": "e.g. blah",
"post": "Some text after the input field",
"required": true
},{
...
}]
}

The JSON structure lets us customise the form with different text, logos, text and styles as necessary. But, by default, forms will be in our house style. Here's an example of a rendered form based on a recent event feedback form we made:

A feedback form example
A simple feedback form created in our own feedback system.
Credit: Open Innovations

It mostly uses default HTML elements with some styling. It means that the generated web page ended up being around 20-30kB in size which is nearly 200 times smaller than forms.app's version. By hosting them ourselves we've also taken away issues around user-tracking and cookies.

I've made an example form for us to test form validation and the user experience for the different question types. Getting feedback has meant I've already fixed a couple of issues that affected narrow screens or iPhones.

When someone submits the form it does some form validation/sanitisation and then appends the information to a plain CSV file. But there is nothing stopping us writing responses to a database if we wanted/needed to.

At the moment the responses are stored unencrypted albeit not in a publicly accessible location. If a form needs an extra layer of security, we are considering an option to use asymmetric encryption on specific fields or the entire response. At the moment we don't need this extra step but it is something we can add when we do.