Skip to content

Forms

A form asks a person for what WerkOS cannot work out itself. Ask for less, in the order people think about it, and say exactly what to fix.

Before you ask

Take what WerkOS already knows from the record, the account or the step before, and ask only for the rest.

Fill in a sensible default. Offer a choice when the answers are known. Leave typing for what only the person can say.

Layout

Use one column with labels above the fields. Put two fields on one row only when people read them as a pair, such as passport number and expiry, or start and end date. On a narrow screen they stack.

Group related questions under a short heading, and order the groups the way people think about the task.

Candidate

Passport

Column width
At most 768 px
Between fields
16 px
--space-4
Between groups
32 px
--space-8
Pairs stack below
640 px
Buttons below 640 px
Full width, stacked, the main action on top

Checking answers

Check a format when the person leaves a field they filled in. Check required answers when the form is sent, and show all the errors at once.

In a form that fits the window, focus then moves to the first field with an error. In a longer form, a message above the first field says how many answers need a change, links to each, and takes the focus.

Two answers need a change.

Candidate

Enter the full name.

Passport

Enter the date as day, month and year.

Sending

Name the button after what it does: Add candidate, Save changes, Send offer. While the form is sending, the button stops taking presses and shows a spinner once sending takes longer than a second. The answers stay as they are.

If sending fails, keep the answers, put a message above the first field that says what happened, and move focus to it. When it succeeds, show the new record where the person expects to find it.

Enter in a field sends the form, and so does Cmd+Enter or Ctrl+Enter in a text area. In a dialog, Escape closes the form, and asks first when answers are unsent.

Sending

The candidate was not saved. Check your connection and try again.

Failed

Saving as you go

A form with a send button saves nothing until it is sent. A settings panel saves each change on its own and says Saved beside it. Keep the two apart on one screen.

When someone closes a form with answers they have not sent, ask first: Discard changes? with the buttons Discard and Keep editing.

On a phone with the keyboard open

On a phone, a form that opens in a dialog becomes a sheet as tall as the part of the window the keyboard leaves free. The questions scroll, and the buttons stay at the bottom of the sheet, above the keyboard.

The field you are typing in scrolls into view above the buttons. Text in fields stays at 16 px so the browser does not zoom, and the page can still be zoomed by hand.

Add candidate

Permitted and not permitted

Permitted

  • An enabled send button that checks the form and shows what is missing

    Focus lands on the first answer to fix.

Not permitted

  • A send button disabled until the form is complete

    Nothing says which answer is missing, so the reader has to hunt for it.

NextSearch and filtering

Forms

Collects information from a person with the least typing and the clearest correction.

  • Kind: pattern
  • Page: https://design.werklist.com/patterns/forms
  • Version: 2.1.2

When to use it

  • Creating a record
  • Editing a record with a send button
  • Public intake forms

When not to use it

  • Asking for what the record, the account or the previous step already holds
  • Two columns of unrelated fields
  • Saving on send and saving each change on the same screen

Rules

  • Ask only for what WerkOS cannot find out.
  • Check a format when the person leaves a field they filled in. Check required answers when the form is sent.
  • The send button stays enabled.
  • A failed submit moves focus to the first field with an error in a form that fits the window, and to a summary with links in a longer one.
  • A settings panel saves each change and says Saved. A form saves when it is sent.

Anatomy

  • Column: One column, at most 768 px, labels above the fields
  • Between fields: 16 px (--space-4)
  • Between groups: 32 px, each group under a short heading (--space-8)
  • Pairs: Two fields on a row only when people read them as a pair. They stack below 640 px.
  • Buttons: At the end of the form, secondary then primary, 8 px apart. Below 640 px they take the full width, stacked, the primary on top. (--space-2)
  • Sheet on a phone: Below 640 px a form in a dialog is a sheet as tall as the space the keyboard leaves. The questions scroll, the buttons stay at the bottom, and the field being typed in stays 16 px above them.

States

  • Empty: A default is filled in where one answer suits most people
  • Sent with answers to change: All errors show at once. In a form that fits the window, focus moves to the first field with an error. In a longer form, a message above the form says how many answers need a change, links to each and takes the focus.
  • Sending: The primary button takes no presses and shows a spinner after one second. The answers stay as they are.
  • Failed: The answers stay. An error message above the first field says what happened and takes the focus.
  • Sent: The new record shows, selected, where the person expects it
  • Closing with unsent answers: Ask first: Discard changes? with Discard and Keep editing

Keyboard

  • Enter in a field: Sends the form
  • Cmd+Enter or Ctrl+Enter in a text area: Sends the form
  • Escape: Closes a form in a dialog, and asks first when answers are unsent

Accessibility

  • Each field shows its own message, under the field.
  • Text in fields stays at 16 px on a phone, and the page can still be zoomed by hand.

Content

  • The primary button names the action and the object: Add candidate, Save changes, Send offer.
  • A failure says what happened, then what to do: 'The candidate was not saved. Check your connection and try again.'
  • When every question is required, one sentence above the form says so, instead of a mark on each.

Tokens

  • --space-2
  • --space-4
  • --space-8

JSON

{
  "title": "Forms",
  "path": "/patterns/forms",
  "url": "https://design.werklist.com/patterns/forms",
  "text": "https://design.werklist.com/agent/patterns/forms",
  "summary": "How to ask for information: what to ask, layout, checking answers, sending, and phones with the keyboard open.",
  "version": "2.1.2",
  "kind": "pattern",
  "name": "Forms",
  "purpose": "Collects information from a person with the least typing and the clearest correction.",
  "use": [
    "Creating a record",
    "Editing a record with a send button",
    "Public intake forms"
  ],
  "avoid": [
    "Asking for what the record, the account or the previous step already holds",
    "Two columns of unrelated fields",
    "Saving on send and saving each change on the same screen"
  ],
  "anatomy": [
    {
      "part": "Column",
      "measure": "One column, at most 768 px, labels above the fields"
    },
    {
      "part": "Between fields",
      "measure": "16 px",
      "token": "--space-4"
    },
    {
      "part": "Between groups",
      "measure": "32 px, each group under a short heading",
      "token": "--space-8"
    },
    {
      "part": "Pairs",
      "measure": "Two fields on a row only when people read them as a pair. They stack below 640 px."
    },
    {
      "part": "Buttons",
      "measure": "At the end of the form, secondary then primary, 8 px apart. Below 640 px they take the full width, stacked, the primary on top.",
      "token": "--space-2"
    },
    {
      "part": "Sheet on a phone",
      "measure": "Below 640 px a form in a dialog is a sheet as tall as the space the keyboard leaves. The questions scroll, the buttons stay at the bottom, and the field being typed in stays 16 px above them."
    }
  ],
  "states": [
    {
      "name": "Empty",
      "change": "A default is filled in where one answer suits most people"
    },
    {
      "name": "Sent with answers to change",
      "change": "All errors show at once. In a form that fits the window, focus moves to the first field with an error. In a longer form, a message above the form says how many answers need a change, links to each and takes the focus."
    },
    {
      "name": "Sending",
      "change": "The primary button takes no presses and shows a spinner after one second. The answers stay as they are."
    },
    {
      "name": "Failed",
      "change": "The answers stay. An error message above the first field says what happened and takes the focus."
    },
    {
      "name": "Sent",
      "change": "The new record shows, selected, where the person expects it"
    },
    {
      "name": "Closing with unsent answers",
      "change": "Ask first: Discard changes? with Discard and Keep editing"
    }
  ],
  "keys": [
    {
      "key": "Enter in a field",
      "action": "Sends the form"
    },
    {
      "key": "Cmd+Enter or Ctrl+Enter in a text area",
      "action": "Sends the form"
    },
    {
      "key": "Escape",
      "action": "Closes a form in a dialog, and asks first when answers are unsent"
    }
  ],
  "accessibility": [
    "Each field shows its own message, under the field.",
    "Text in fields stays at 16 px on a phone, and the page can still be zoomed by hand."
  ],
  "content": [
    "The primary button names the action and the object: Add candidate, Save changes, Send offer.",
    "A failure says what happened, then what to do: 'The candidate was not saved. Check your connection and try again.'",
    "When every question is required, one sentence above the form says so, instead of a mark on each."
  ],
  "rules": [
    "Ask only for what WerkOS cannot find out.",
    "Check a format when the person leaves a field they filled in. Check required answers when the form is sent.",
    "The send button stays enabled.",
    "A failed submit moves focus to the first field with an error in a form that fits the window, and to a summary with links in a longer one.",
    "A settings panel saves each change and says Saved. A form saves when it is sent."
  ],
  "tokens": [
    "--space-2",
    "--space-4",
    "--space-8"
  ]
}

Raw file: https://design.werklist.com/agent/patterns/forms