The Programmable Form-Builder

Formulate is a form-builder for hackers. Rather than using a fiddly drag-and-drop UI to define form layout, connections, and conditional logic, Formulate lets you use code instead. Here's a simple signup form for a newsletter:

export default async function() {
  let name = await form.short("First off, what's your name?", {banner: true})
  await form.statement(`It's lovely to meet you, ${name} 👋!`)
  await form.short("Please enter your email address", {
    description: "We won't spam you or share your email with anyone",
    email: true,
  await form.statement("We'll send you an email to confirm. Thanks!");

Which generates this form:

No-code? Low-code? Just code!

There are typically two ways to build forms/surveys/etc. Use a no-code tool like Tally or Google Forms, or build the entire thing yourself, from scratch. These are both reasonable choices, but we believe there's a middle ground that's grossly underserved by the tools available today:

  • You write code just to define the form's content and conditional logic
  • We build a user interface around this code
  • We provide the infrastructure to publish forms and collect responses

There aren't many tools that work this way, and there isn't an established nomenclature for this kind of tool. We've seen it described as Just Code, which really resonates with us. You get to use the power of a real programming language to build out the logic for your form, without having to worry about UI, persistence, or availability.

How Does it Work?

You write Javascript code describing your form's content and conditional logic. We take this code and execute it in a secure browser sandbox, and use it to generate the form UI that the respondent sees.

The code you write has full access to Javascript-the-language, but isn't allowed access to Web APIs or the DOM. All external access happens through the form global object that we provide (also aliased to formulate and f), which lets you:

  • Present a question to the respondent
  • Log messages to the browser console
  • Make a HTTP request
  • Retrieve values from the URL query string

While these building blocks are sufficient to let you build any form that you'd be able to build in a traditional form-builder, you can go much, much further with them…

The Possibilities are Endless

Loops, conditionals, and variables can be powerful in this context. Coupled with the ability to fetch data over the wire at runtime, you're able to build forms and experiences that are difficult-to-impossible to create in traditional form builders. Here are a few examples:

  • Run an A/B test using Math.random() to group respondents into segments.
  • Load inventory or pricing data dynamically using fetch to load the data, and generate a payment page in response.
  • Fetch a user's membership information from your database and pick an appropriate support channel based on their tier.
  • The user picks a few options from a list, you then collect more details for each of their selections.
  • Personalization based on the user's location, timezone, time of day, or even the weather forecast.

Head over to the gallery for more inspiration, or create your first form.