Forms in notifications

You can create forms in notifications to request information from users. To do this, you include a set of input widgets in the notification card. The data filled in by users are passed back to your calling application when the user submits the form.

656

Notification card with a form field

User story

Suppose you have a process that checks for errors in a booking system. You would like to send users notifications to fix these errors. Some errors are complicated, and require users to find the booking in the original app. Others are very simple, though, and users can correct them quickly if you provide an easy way to enter new data. You need to implement the following user story:

As a user I want to be able to correct simple errors without opening a heavyweight app.

Recipe

To make a form, you need to include two items in the notification:

  • A form element

  • At least one button, which submits the form. That button must be marked specially.

Optionally, you can validate the information that the user submits.

Code example

const formNote: NotificationOptions = 
{
  title: 'Booking error',
  body: '*Trade 276128763* containing an *equity swap* was booked in *Book 1234545*, which doesn\'t permit that kind of trade. ' +
      'Analysis indicates that 90% of users who made this mistake intended to type *Book 1234554*. Correct?',
  icon: 'oflogo.png',
  form: 
  [
    {
      key: 'book',
      label: 'Book Name',
      type: 'string',
      widget: 
      {
        type: 'Text',
        placeholder: 'Book name'
      },
      validation: 
      {
        min: 
        {
          arg: 7,
          invalidMessage: 'Must be at least 7 characters'
        },
        max: 
        {
          arg: 9,
          invalidMessage: 'Cannot be more than 9 characters'
        },
        required: 
        {
          arg: true
        }
      },
      value: '1234554'
    }
  ],
  buttons: 
  [
    {
      title: 'Correct',
      submit: true,
      cta: true
    },
    {
      title: 'Open App'
    },
    {
      title: 'Ignore'
    }
  ]
};
create(formNote)

Basic fields

You start with a form element. A form element is an array of input widgets; these widgets are rendered in a vertical stack in the notification.

Example form element:

{
    label: 'Your name',
    type: 'string',
    key: 'name',
    widget: {
        type: 'Text',
        placeholder: 'Illustrative text'
    },
}

Rendered example:

608

Example form element, rendered

This example shows the use of these fields:

  • type gives the type of data you are getting from the user.

  • label is used to label the form element and for building error messages.

  • widget describes what widget is displayed and holds configuration specific to that widget. (Refer to Widget for available types and their members.)

  • key is used to refer to this element in the data returned to you.

  • placeholder is text that is displayed in the widget before the user enters a value. It disappears as soon as the user starts to type in the widget, so for best usability and accessibility, be sure to include a label.

You can also include a value field, for the default value of that form element if the user does not provide one.

When a form is filled in and submitted, it generates a notification-form-submitted event in your application.

Validation

The elements of a form can have validation. In order to do that, you can include an optional validation object:

{
    validation: {
        min: {
            arg: 7,
            invalidMessage: 'Must be at least 7 characters'
        },
        max: {
            arg: 9,
            invalidMessage: 'Cannot be more than 9 characters'
        },
        required: {
            arg: true
        }
    },
}

The validation data contains a set of rules that you can choose from. Each rule has a set of arguments. So for example, the min rule for the string datatype indicates the minimum length the string must be. The validation generates an error string if this validation rule is violated, but you can provide one yourself with the invalidMessage value.

As the user enters data into the form, if any of the validation rules fail, the user is prevented from submitting the form. The rules are evaluated on every key press, and the submit button is clickable once they all pass. Error messages are displayed under each widget. They are displayed only if the user's focus leaves the field while its value is invalid, to avoid having distracting errors while the user is initially typing.

Submission buttons

In order to submit a form, it must contain at least one button. That button must have the call-to-action (cta) and submit fields set to true on it.

buttons: [
  {
      title: 'OK',
      submit: true,
      cta: true
  },
  {
      title: 'Open App'
  },
  {
      title: 'Ignore'
  }
]

The submit field means that the button can be clicked only if the validations have passed. This does not affect other buttons. On a form with invalid inputs, the submit button is disabled.

Once the user clicks the submit button, your app receives a notification-form-submitted callback from the button. To subscribe to that event type, do this:

addEventListener('notification-form-submitted', (event) => 
{
    console.log(`Form submitted: ${JSON.stringify(event.form)}`);
});

Here event.form is a Record, where the keys are the key fields you gave in the form definition, and the values are the values submitted by the user.

The notification is dismissed when it is submitted, so the user can’t accidentally resubmit the form.

Best practices

  • Large forms take up a lot of space when displayed as toasts, so keep them fairly small. If you need a large form, you probably need to send the user to the app.
  • You can’t require that user must submit a form, because the user can always dismiss the notification. Therefore, it’s polite to have an ‘ignore’ or ‘cancel’ button, so the user doesn’t have to hunt for the close button.
  • Make sure the validation messages (invalidMessage) are clear, so the user knows exactly what is expected of them.