Developer Programs

Learn

Docs

Editing Forms

Components > Editing Data > Forms > Editing Forms
Use this feature to...
Prompt the user for input

Overview

Views that allow the user to edit data include an HTML form element.

Each field in the form displays a label and an editor appropriate for editing the field’s data.

You can think of record detail as a kind of read-only form.

Like a form, record detail displays a label for each field, but it displays the value as read-only text rather that providing an editor for the field.

Field labels and values

Display the field label to the left and the field value editor to the b at desktop or tablet screen sizes.

Display the field label above and the field value editor below on mobile.

Each field should prompt for data using the type of editor most appropriate for the type of data being requested.

For example, a date field should use a date picker as the field editor.

Required fields

Required fields must include the themed required field indicator at the far right of the field label.

Display the required field indicator next to every required field, even if every field in the form is required.

This field is required, so it displays the required field indicator

Action buttons

If you need to support additional functionality with a field to help the user enter the proper value in the field, include an action button with the field. Your application can perform whatever action is appropriate when the user presses the field’s action button, e.g. displaying contextual info or allowing the user to search for or calculate the appropriate value for the field. Action buttons always display using secondary button styling.

This field includes an action button to the right of the editor

Help

Display a hint below the editor if the field’s format is atypical or may not be apparent to the user. Try to avoid overusing hints as they can clutter the edit form. If you need to display more than a small amount of text here, use the field-level tooltip icon discussed below.

This field displays a hint that lets the user know about specific atypical input requirements

You can also display a field-level tooltip icon next to fields where you need to provide in-depth information about the field. The information displays in a tooltip when the user hovers the mouse over or clicks the tooltip icon. See Tooltip for more information.

This field displays a field-level tooltip when you hover over or click the icon
Field-level tooltip icon

Validating the form

Form fields must be validated if there are any constraints on what the user can enter. See Validating Forms for more information.

Posting and canceling the form

Your form should include a button labeled Save to submit the user’s changes and a button labeled Cancel to cancel the user’s changes. Your app should return to the same location after the user presses either button.

The Save and Cancel buttons should appear as the leftmost options in the toolbar for the display block that contains the form elements. You should also include a copy of these two buttons in the floating toolbar for the page. This ensures that these buttons are always easily accessible by the user, even after scrolling down the page.

Display a busy indicator at the display block or function level while posting the form.

Do not include a button that clears or resets the form. These do far more harm than good.
Portion of an edit form showing required fields, with varying data types. The Name field displays a field-level tooltip icon that allows the user to see more info about the field. The Interest Rate field displays a hint below the editor. The Gross Income field includes an action button.
Form editing example

Guidance for large forms

Larger forms present specific challenges that we don’t see in smaller forms. See Forms - Large Forms for guidance on building larger forms.

Guidance for editing certain data types

This section provides guidance for editing certain specific data types.

Editing Boolean values

We use the word “Boolean” to describe a value that has two states: true/false, on/off, selected/unselected, etc.

User interfaces typically use 3 different types of components to manage Boolean values: checkboxes, toggles, and toggle buttons. All three of these components essentially do the same two things:

  • Display the current Boolean value with a distinct appearance for both states.
  • Allow the user to change the Boolean value by clicking the component.

Since these components perform the same actions, it’s important to distinguish when to use each component:

  • Use a checkbox to manage state for any Boolean value that requires a separate action in order to take effect.
    • This includes Boolean fields in forms that are posted by pressing a Save button.
    • If changes to a form are processed after the user presses a Save button, then use a checkbox for managing Boolean fields in that form.
  • Use a toggle to manage state for any Boolean value that takes effect immediately (does not require a separate action to take effect) and is not in a toolbar.
    • The toggle acts like a physical switch that allows users to turn things on or off, like a light switch.
    • If changes to a form are processed immediately without the user pressing a Save button, then use a toggle for managing Boolean fields in that form.
  • Use a toggle button to manage state for any Boolean value that takes effect immediately (does not require a separate action to take effect) and is in a toolbar.
    • The compact nature of the toggle button — with its label internal to the button — makes it a better fit for a toolbar, where space is at a premium.
    • Since this case is beyond the scope of editing data in a form, we don’t discuss toggle buttons further here.

You can use a toggle in a form that uses Save/Cancel buttons, but only for showing and hiding other form fields when toggled. For example, your form may hide some of the lesser used fields by default until the user clicks a toggle to display these fields.

When you use a toggle in this way, place the label to the right of the toggle. This is obviously different from the layout for form fields, where the field label is to the left and the field input is to the right. This is by design; this toggle is not used for a form field and this layout helps visually distinguish that.

Selecting one item from a list

If a field’s value must be one out of a finite set of possible values:

  • If the number of possible values is small (say 3 items or less) and the values can all be displayed horizontally in a row, then display the possible values as a button group.
  • If the number of possible values is relatively small and all options need to remain visible on the screen at once, then display the possible values as a vertical list of radio buttons.
  • If the number of possible values is medium (say larger than 3 but smaller than around 50 items), then display the list in a dropdown input that contains all possible values.
  • If the number of possible values is large (say larger than 50 items but smaller than around 1000 items), then use a autocomplete input, where all possible values that are a subset of the current input display in a dropdown. Since the user’s input is freeform, you’ll still need to validate it.
  • If the number of possible values is very large (say larger than 1000 items), then just prompt for freeform text and validate that.

Development

Web component development

Component reference

rui-form-field
rui-form-field
Module: rui-input - Package: @jkhy/responsive-ui-wc

Provides layout for the elements of an individual form field.

NameTypeDefaultDescription
orientationstring'horizontal'

One of:

  • “horizontal”: the field label and field value display side-by-side
  • “vertical”: the field label displays above the field value
isRequiredbooleanfalseSpecifies whether the user must fill out the field in order for the form to pass validation. Required fields display an asterisk after the field label to indicate that the field is required.
labelTextstring''

Text displayed for the field label.

A colon displays at the end of the field label unless it already ends with a colon or question mark.

labelForstring''Specifies the id of the field’s input element. Used as the HTML “for” attribute for the field label.
labelClassesstring''

Specify one or more responsive layout CSS classes for laying out the label portion of the field.

If you leave this blank, a value of ‘col-md-4’ is used, giving the field label 4 of the 12 layout columns used by the field.

valueClassesstring''

Specify one or more responsive layout CSS classes for laying out the value portion of the field.

If you leave this blank for a horizontal field, a value of ‘col-md-8’ is used, giving the field value 8 of the 12 layout columns used by the field.

If you leave this blank for a vertical field, a value of ‘col-sm-12’ is used, giving the field value all 12 layout columns used by the field. This is appropriate since the label and value are stacked vertically, with each taking all 12 of the layout columns.

inputPrefixstring''Specifies a short, static text value displayed to the left of the field value’s input. We typically only use this to display a dollar sign to the left of currency field inputs.
inputSuffixstring''Specifies a short, static text value displayed to the right of the field value’s input. One use for this to display a percent sign to the field of a rate field’s input. Another use would be to specify units for a numeric value, such as “days” or “months”.
helpTextstring''

Specifies optional text to display below the field.

The helpText value is always visible, below the field. If you have help text that is on the large side or if it isn’t critical for the user to see the help text, consider using a field tooltip instead.

slotstring''Set to form-field-extra-info to add additional markup below the help text.
slotstring''Set to custom-form-label to create custom label for form input.
actionButtonIconTypestring''

If you want to display an action button to the right of the field’s input, you can specify the name of an enterprise icon to display in the button. The use of custom icons is also supported.

Action buttons can be useful for field’s that offer additional functionality. One example would be an action button that displays a stacked view that allows the user to look up information for the field.

rui-form-field-action-button-clickeventEvent fired when the user presses the action button.
hasErrorbooleanfalse

Specifies whether the current form field contains a validation error.

In Angular Reactive forms, you’ll typically bind this property to the invalid, dirty, and touched properties for the form field.

In the example below, we’re binding the name field’s hasError property to the appropriate Reactive form metadata for the field:

‘[hasError]=“name.invalid && (name.dirty || name.touched)”’

rui-info-tooltip
rui-info-tooltip
Module: rui-tooltip - Package: @jkhy/responsive-ui-wc

Information icon that displays a themed tooltip popup when the user hovers or presses the icon. Place the tooltip content within the rui-info-tooltip start and closing tags. Typically used within a rui-form-field element.

NameTypeDefaultDescription
locationstring'right'

Specifies the location of the tooltip popup relative to the tooltip icon.

One of:

  • ’top'
  • ‘bottom’
  • ’left'
  • ‘right’
tooltipWidthnumber-1If you need to override the default tooltip popup width, specify the width in pixels here. The default value results in a width of 200 pixels.

Implementation

This section talks about the basics of setting up forms and fields with web components.

See Validating Forms for specifics on defining form validations.

Angular Form Basics

If your application is built with Angular, start by reading this forms overview from the Angular site first: https://angular.io/guide/forms-overview.

We strongly recommend using reactive forms in Angular apps, but you can also use template-driven forms if needed. Both are supported, although be aware that all of our examples and samples use reactive forms.

The Editing and Validating Form Data view in the Angular sample app demonstrates setting up a form with validations. We start by talking you through the process of setting up the form here, then get into more detail about different types of inputs after that.

Imports

Import FormsModule and ReactiveFormsModule in app.module.ts.

Import FormsModule and ReactiveFormsModule
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

...

imports: [
    ...
    FormsModule,
    ReactiveFormsModule,
    ...

Import rui-input and rui-tooltip in app.module.ts.

Import rui-input and rui-tooltip
// import into app.module
import '@jkhy/responsive-ui-wc/components/rui-input/rui-input-imports';
import '@jkhy/responsive-ui-wc/components/rui-tooltip/rui-tooltip-imports';

In the TypeScript that backs the form, import FormGroup, FormControl, and Validators.

Import FormGroup, FormControl, and Validators
import { FormGroup, FormControl, Validators } from '@angular/forms';
Defining the Form

Define the form, its fields, and the validators for each field (if any) in the TypeScript. Create a FormGroup for the form and a FormControl for each field, passing in the initial value for the field as well as zero or more validators.

See Validating Forms for specifics on defining form validations.

Creating the form
public editForm: FormGroup = new FormGroup({
    'name': new FormControl(this.customerInfo.name, Validators.required),
    'ssn': new FormControl(this.customerInfo.ssn, Validators.required),
    'birthdate': new FormControl(this.customerInfo.birthdate, Validators.required),
    'grossIncome': new FormControl(this.customerInfo.grossIncome),
    'interestRate': new FormControl(this.customerInfo.interestRate, [Validators.min(3), Validators.max(100)]),
    'activeCustomer': new FormControl(this.customerInfo.activeCustomer),
    'idChecked': new FormControl(this.customerInfo.idChecked),
    'street': new FormControl(this.customerInfo.street, Validators.required),
    'city': new FormControl(this.customerInfo.city, Validators.required),
    'state': new FormControl(this.customerInfo.state, Validators.required),
    'zip': new FormControl(this.customerInfo.zip, [Validators.required, Validators.pattern('^[0-9]{5}(?:[0-9]{4})?$')]),
    'country': new FormControl(this.customerInfo.country, Validators.required),
    'addressType': new FormControl(this.customerInfo.addressType),
    'homePhone': new FormControl(this.customerInfo.homePhone),
    'businessPhone': new FormControl(this.customerInfo.businessPhone),
    'mobilePhone': new FormControl(this.customerInfo.mobilePhone),
    'email': new FormControl(this.customerInfo.email, Validators.email)
    }, { validators: CountryAddressTypeValidator });

Next, create a property for each of the form fields to make it easier to interact with each of them in the HTML.

Creating properties for form fields
get name() { return this.editForm.get('name'); }
get ssn() { return this.editForm.get('ssn'); }
get birthdate() { return this.editForm.get('birthdate'); }
get grossIncome() { return this.editForm.get('grossIncome'); }
get interestRate() { return this.editForm.get('interestRate'); }
get activeCustomer() { return this.editForm.get('activeCustomer'); }
get idChecked() { return this.editForm.get('idChecked'); }
get street() { return this.editForm.get('street'); }
get city() { return this.editForm.get('city'); }
get state() { return this.editForm.get('state'); }
get zip() { return this.editForm.get('zip'); }
get country() { return this.editForm.get('country'); }
get addressType() { return this.editForm.get('addressType'); }
get homePhone() { return this.editForm.get('homePhone'); }
get businessPhone() { return this.editForm.get('businessPhone'); }
get mobilePhone() { return this.editForm.get('mobilePhone'); }
get email() { return this.editForm.get('email'); }

Define the form element in the HTML, binding the formGroup attribute to the FormGroup variable you defined in the TypeScript (editForm in this case). Wire up a submit event handler.

Form HTML
<form [formGroup]="editForm" (ngSubmit)="saveChanges()">

    ...

</form>
Save/Cancel Buttons

Add Save and Cancel buttons for the form. The Save button is a submit button that is disabled any time the editForm is invalid (i.e. when [disabled]="!editForm.valid"). The Cancel button is a regular button that calls a method to abandon the form changes when pressed.

At a minimum you’ll add the Save and Cancel buttons to the display block toolbar, but you should also add them to a floating toolbar if the form is long. The floating toolbar displays after the user scrolls down the page a bit, so having the Save/Cancel buttons in the floating toolbar makes them available to the user no matter how far down they scroll.

Save/Cancel Buttons
<form [formGroup]="editForm" (ngSubmit)="saveChanges()">

    <rui-floating-toolbar>
        <rui-button text="Save" buttonStyle="primary" buttonType="submit" [isDisabled]="!editForm.valid"></rui-button>
        <rui-button text="Cancel" buttonStyle="secondary" (rui-click)="cancelChanges()"></rui-button>
    </rui-floating-toolbar>

    <rui-display-block>
        <rui-toolbar slot="display-block-toolbar-below">
            <rui-button text="Save" buttonStyle="primary" buttonType="submit" [isDisabled]="!editForm.valid"></rui-button>
            <rui-button text="Cancel" buttonStyle="secondary" (rui-click)="cancelChanges()"></rui-button>
        </rui-toolbar>

        ...

    </rui-display-block>

</form>
Form Fields

Add an instance of rui-form-field for each field in the form:

  • Use the orientation property to specify whether the field uses a horizontal layout or a vertical layout:
    • Horizontal fields display the field label and field value side-by-side.
    • Vertical fields display the field label above the field value.
  • Set the isRequired property to true if this field must have a non-blank value in order to pass validation.
    • Required fields display an asterisk after the field label to indicate that the field is required.
  • For the field label:
    • Specify the field label text with the labelText property.
    • A colon displays at the end of the field label unless the text already ends with a colon or question mark.
    • For a custom field label, leave off the labelText property and add your own label tag with slot="custom-form-label" inside of the rui-form-field. This will allow you to provide custom markup and styling.
  • For the field value:
    • Nest the input editor appropriate to the field’s data type as the rui-form-field component’s content.
    • Turn off auto-complete, auto-correct, auto-capitalize, and spell check behavior in editors. This is important for security reasons. Add the following attributes and values to the input element to do this:
      • autocomplete=“off”
      • autocorrect=“off”
      • autocapitalize=“off”
      • spellcheck=“false”
    • Add the required attribute to the field’s input component if the field uses a simple input and is required.
    • See the Form Fields section below for details on setting up the right type of input component for the type of data you’re prompting for.
  • Specify the field input editor’s ID as the value for labelFor. This lets the browser know that the label and editor are connected, which is important for accessibility.
  • You can specify a responsive layout for a horizontal field’s label and value sections, letting the browser know how much of the field’s width to assign to the label and how much width to assign to the value.
    • You do this by assigning one or more responsive layout CSS classes to the labelClasses and valueClasses properties.
    • Vertical fields always use the full available width for both the label and the value (displaying the value below the label), so you should not assign a responsive layout for them.
  • For help text:
    • To display a short block of help text below the field, assign that text to the helpText property.
      • This help text is always visible to the user. This is helpful if the user always needs to see this text, but it can also clutter the screen.
    • If the amount of help text is large or doesn’t always need to be seen by the user, you can use a field info tooltip instead of helpText:
      • The field info tooltip presents a small icon next to the field label which displays a block of help text in a popup when the user hovers or presses it.
      • Add an instance of rui-info-tooltip inside the rui-form-field.
      • Add slot="info-tooltip" to the rui-info-tooltip so the rui-form-field can position the tooltip appropriately.
      • Nest the tooltip content within the rui-info-tooltip opening and closing tags. This is typically simple text, but you can also display formatted data.
      • By default, the field info tooltip displays to the right of the tooltip icon so the tooltip isn’t clipped on the left. You can override the tooltip’s location by setting its location property to ’top’, ‘bottom’, ’left’, or ‘right’.
    • If you have more complex help text that requires additional markup, add it to the form-field-extra-info slot.
  • If you’d like to add a button to the field that provides extended functionality for the field — say you want to add a button that allows the user to look up an appropriate value for the field — specify the name of an enterprise icon for the actionButtonIconType property and the field will display that icon in a button to the right of the field’s value.
    • One example of this would be an action button that displays a stacked view that allows the user to search for and select the appropriate information for the field.
    • The field fires the rui-form-field-action-button-click event when the user presses the action button.
    • If necessary, you can provide custom icons for the action button using the custom-icon slot. You can find more information on implementing custom icons on the icon component doc.
  • If the field contains a validation error, bind its hasError property to a value of true.
    • In Angular Reactive forms, you’ll typically bind this property to the invalid, dirty, and touched properties for the form field.
    • In the example below, we’re binding the name field’s hasError property to the appropriate Reactive form metadata for the field:
      [hasError]="name.invalid && (name.dirty || name.touched)"
Field-Level Validation Errors

Display field-level validation errors in a separate ul element after the rui-form-field element. Add the rui-form-validation-errors CSS class to the ul. Display each validation error as its own li element in the ul.

Setting Focus Automatically

It can be helpful to automatically set focus to the first editable field in the form. This allows the user to start editing fields immediately without having to manually set focus to a form field.

In many web technologies you simply add the autofocus attribute to the input element that should receive auto-focus. However, this technique often doesn’t work in Angular due to timing around components being added to the DOM.

Angular applications can add the jhaAutoFocus directive (part of the JhaResponsiveCoreModule module in the responsive-ui-angular package) to focusable elements instead, the same as you would typically add the autofocus directive. The jhaAutoFocus directive sets focus to the element after a brief delay to account for timing issues as the DOM is constructed.

Examples

In the example below:

  • The field label (“Name”) is assigned with the labelText property.
  • We assign the input’s id value (“field-name”) to the form field with the labelFor property.
  • We specify that the input is required by binding the isRequired property to a value of true.
  • We indicate when the input contains errors by binding the hasError property to various values in the Reactive form. This logic will flag an error if the Name field is invalid (name.invalid) and the user has had a chance to modify the field value: name.dirty is true if the user has modified the input value and name.touched is true if the user has tabbed through the field without changing its value.
  • We nest a simple text input within the rui-form-field:
    • The input’s id (“field-name”) matches the value in the labelFor property in the rui-form-field element.
    • The formControlName property contains the field’s name as defined in the form.
    • We add the rui-form-control CSS class to get the proper themed styling for the field.
    • We add the jhaAutoFocus directive to automatically set focus to this field after the view is constructed and added to the DOM.
  • We display field-level validation errors in a separate ul element after the rui-form-field element.
    • We use *ngIf to conditionally display the set of validation errors. Note that we use the same conditional logic here as we used for the hasError property in the rui-form-field element.
    • We add the rui-form-validation-errors CSS class to get the proper themed styling for the validation errors.
    • We display each individual validation error for the field (there can be more than one validation error per field) as its own element.
Field with field-level validation errors
<rui-form-field labelText="Name" labelFor="field-name" [isRequired]="true" [hasError]="name.invalid && (name.dirty || name.touched)">

    <input id="field-name" formControlName="name" type="text" class="rui-form-control" jhaAutoFocus
        required autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" />

</rui-form-field>

<!-- Name validation errors -->
<ul *ngIf="name.invalid && (name.dirty || name.touched)" class="rui-form-validation-errors">
    <li *ngIf="name.errors['required']">
        Name is required
    </li>
</ul>

In the example below:

  • The field is not required and has no validation errors.
  • We’re using a rui-button-group as the field editor.
    • It’s important to use the proper editor component for the type of data being edited.
    • See the “Editing Form Fields by Datatype” section below for guidance on which editor to use for each different field data type.
  • We embed a rui-info-tooltip component with helper text. The tooltip displays when the user hovers or presses the tooltip icon in the form.
Field without field-level validation errors
<rui-form-field labelText="Account Tier" labelFor="field-accountTier">

    <rui-button-group id="field-accountTier" [value]="accountTier.value"
        (rui-button-group-value-change)="accountTier.setValue($event.detail)" tabindex="0">
        <rui-button-group-option value="Gold">Gold</rui-button-group-option>
        <rui-button-group-option value="Silver">Silver</rui-button-group-option>
        <rui-button-group-option value="Platinum">Platinum</rui-button-group-option>
    </rui-button-group>

    <rui-info-tooltip>
        This is a field-level tooltip
    </rui-info-tooltip>

</rui-form-field>

Angular wrapper development

Implementation

This section talks about the basics of setting up forms and fields with Angular. Start by reading this information from the Angular site first: https://angular.io/guide/forms-overview.

We strongly recommend using reactive forms in Angular apps, but you can also use template-driven forms if needed. Both are supported, although be aware that all of our examples and samples use reactive forms.

See Validating Forms for specifics on defining form validations.

The Editing and Validating Form Data view in the Angular sample app demonstrates setting up a form with validations. We start by talking you through the process of setting up the form here, then get into more detail about different types of inputs after that.

Imports

Import FormsModule and ReactiveFormsModule in app.module.ts.

Import FormsModule and ReactiveFormsModule
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

...

imports: [
    ...
    FormsModule,
    ReactiveFormsModule,
    ...

In the TypeScript that backs the form, import FormGroup, FormControl, and Validators.

Import FormGroup, FormControl, and Validators
import { FormGroup, FormControl, Validators } from '@angular/forms';
Defining the Form

Define the form, its fields, and the validators for each field (if any) in the TypeScript. Create a FormGroup for the form and a FormControl for each field, passing in the initial value for the field as well as zero or more validators.

See Validating Forms for specifics on defining form validations.

Creating the form
public editForm: FormGroup = new FormGroup({
    'name': new FormControl(this.customerInfo.name, Validators.required),
    'ssn': new FormControl(this.customerInfo.ssn, Validators.required),
    'birthdate': new FormControl(this.customerInfo.birthdate, Validators.required),
    'grossIncome': new FormControl(this.customerInfo.grossIncome),
    'interestRate': new FormControl(this.customerInfo.interestRate, [Validators.min(3), Validators.max(100)]),
    'activeCustomer': new FormControl(this.customerInfo.activeCustomer),
    'idChecked': new FormControl(this.customerInfo.idChecked),
    'street': new FormControl(this.customerInfo.street, Validators.required),
    'city': new FormControl(this.customerInfo.city, Validators.required),
    'state': new FormControl(this.customerInfo.state, Validators.required),
    'zip': new FormControl(this.customerInfo.zip, [Validators.required, Validators.pattern('^[0-9]{5}(?:[0-9]{4})?$')]),
    'country': new FormControl(this.customerInfo.country, Validators.required),
    'addressType': new FormControl(this.customerInfo.addressType),
    'homePhone': new FormControl(this.customerInfo.homePhone),
    'businessPhone': new FormControl(this.customerInfo.businessPhone),
    'mobilePhone': new FormControl(this.customerInfo.mobilePhone),
    'email': new FormControl(this.customerInfo.email, Validators.email)
    }, { validators: CountryAddressTypeValidator });

Next, create a property for each of the form fields to make it easier to interact with each of them in the HTML.

Creating properties for form fields
get name() { return this.editForm.get('name'); }
get ssn() { return this.editForm.get('ssn'); }
get birthdate() { return this.editForm.get('birthdate'); }
get grossIncome() { return this.editForm.get('grossIncome'); }
get interestRate() { return this.editForm.get('interestRate'); }
get activeCustomer() { return this.editForm.get('activeCustomer'); }
get idChecked() { return this.editForm.get('idChecked'); }
get street() { return this.editForm.get('street'); }
get city() { return this.editForm.get('city'); }
get state() { return this.editForm.get('state'); }
get zip() { return this.editForm.get('zip'); }
get country() { return this.editForm.get('country'); }
get addressType() { return this.editForm.get('addressType'); }
get homePhone() { return this.editForm.get('homePhone'); }
get businessPhone() { return this.editForm.get('businessPhone'); }
get mobilePhone() { return this.editForm.get('mobilePhone'); }
get email() { return this.editForm.get('email'); }

Define the form element in the HTML, binding the formGroup attribute to the FormGroup variable you defined in the TypeScript (editForm in this case). Wire up a submit event handler.

Form HTML
<form [formGroup]="editForm" (ngSubmit)="saveChanges()">

    ...

</form>
Save/Cancel Buttons

Add Save and Cancel buttons for the form. The Save button is a submit button that is disabled any time the editForm is invalid (i.e. when [disabled]="!editForm.valid"). The Cancel button is a regular button that calls a method to abandon the form changes when pressed.

At a minimum you’ll add the Save and Cancel buttons to the display block toolbar, but you should also add them to a floating toolbar if the form is long. The floating toolbar displays after the user scrolls down the page a bit, so having the Save/Cancel buttons in the floating toolbar makes them available to the user no matter how far down they scroll.

Save/Cancel Buttons
<form [formGroup]="editForm" (ngSubmit)="saveCustomerChanges()">

    <jha-floating-toolbar>
        <jha-button jhaText="Save" jhaButtonStyle="Primary" jhaButtonType="submit" [jhaIsDisabled]="!editForm.valid"></jha-button>
        <jha-button jhaText="Cancel" jhaButtonStyle="Secondary" (jhaClick)="cancelChanges()"></jha-button>
    </jha-floating-toolbar>

    <jha-display-block>
        <jha-display-block-toolbar>
            <jha-button jhaText="Save" jhaButtonStyle="Primary" jhaButtonType="submit" [jhaIsDisabled]="!editForm.valid"></jha-button>
            <jha-button jhaText="Cancel" jhaButtonStyle="Secondary" (jhaClick)="cancelChanges()"></jha-button>
        </jha-display-block-toolbar>

        ...

    </jha-display-block>

</form>

Display form-level validations at the top of the form, between the Save/Cancel buttons and the form elements. See Validating Forms for specifics on defining form validations.

Form-level validation errors
<jha-display-block>

    <jha-display-block-toolbar>
        <jha-button jhaText="Save" jhaButtonStyle="Primary" jhaButtonType="submit" [jhaIsDisabled]="!editForm.valid"></jha-button>
        <jha-button jhaText="Cancel" jhaButtonStyle="Secondary" (jhaClick)="cancelChanges()"></jha-button>
    </jha-display-block-toolbar>

    <!-- Form-level validation errors -->
    <jha-inline-notification jhaType="Error" jhaIconType="Error" *ngIf="editForm.errors && (editForm.touched || editForm.dirty)">
        <div *ngIf="editForm.errors?.countryAddressTypeMismatch">
            {{country.value}} is an invalid country for {{addressType.value}} address type
        </div>
    </jha-inline-notification>

    <!-- Form elements go here -->

</jha-display-block>
Form Fields
Each field has one div for the label, a second div for the input + validation errors + help, and a third div to wrap the previous two
Field layout

Set up each field in the HTML with three div elements:

  • An inner div contains the field label.
    • Add a col-xx-xx CSS class to this div for Bootstrap grid layout (col-md-2 in this example).
    • Add the control-label CSS class to the label.
    • Add the jha-required-indicator CSS class to the label if the field is required. This displays a themed asterisk next to the field label, visually indicating to the user that the field is required.
    • Include a colon at the end of the field label text.
  • An inner div contains the input element, any field-level validation errors, and any field-level help.
    • Add a col-xx-xx CSS class to this div for Bootstrap grid layout (col-md-4 in this example).
    • For the Bootstrap grid layout:
      • Add the form-control CSS class to the input.
      • Add the required attribute to the input if the field is required, as well as attributes for any other HTML 5 constraints.
      • Turn off auto-complete, auto-correct, auto-capitalize, and spell check behavior in editors. This is important for security reasons. Add the following attributes and values to the input element to do this:
        • autocomplete=“off”
        • autocorrect=“off”
        • autocapitalize=“off”
        • spellcheck=“false”
      • The jha-input-highlighted CSS class can be added to the input to highlight the field as important. This feature works independently from the required field indicator and validation errors and should be used sparingly.
      • See the Form Fields section below for details on setting up the right type of input component for the type of data you’re prompting for.
    • Add a nested div within this div for displaying field-level validation errors (if any).
      • Use *ngIf to include this div if the field has any validation errors. Note the use of “ssn” in this example; this is the property we defined for this field in the TypeScript. We display validation errors only if the user has changed or visited the field, which we test with the Angular attributes ssn.dirty and ssn.touched.
      • Add the help-block CSS class to this div. This is critical for getting the proper error styling.
      • Add yet another nested div for each individual validation error that can be flagged for this field, with the text for that particular validation error message. This example checks for a missing required field (ssn.errors.required) and an out-of-range value (ssn.errors.min || ssn.errors.max).
      • While Angular has several built-in validators, you can also easily create your own custom validators for validations specific to your use case (not shown here). Note that custom validators at the field level have a slightly different internal interface than custom validators at the form level, since field-level validators only look at one field while form-level validators look at the entire form.
    • If you’re displaying field-level help for this field, include a nested div after the input element and the validation errors. Add the help-block CSS class to this div. Field-level help should be used sparingly in order to reduce the size of the form. Only use this on fields that need extra explanation.
  • An outer div wraps the two internal divs for the field.
    • Add the row and form-group CSS classes to this div.
    • If the field has any validation errors, use ngClass to add the has-error CSS class to the div. This is critical for getting the proper error styling; it displays the field label, input border, field-level validation errors, and field-level help in red to indicate the error state. We display validation errors only if the user has changed or visited the field, which we test with the Angular attributes ssn.dirty and ssn.touched.
Field example
<!-- Outer div for SSN field -->
<div class="row form-group" [ngClass]="{'has-error': ssn.invalid && (ssn.dirty || ssn.touched)}">

    <!-- Inner div for label -->
    <div class="col-md-2">

        <!-- Label, with required field indicator -->
        <label class="control-label jha-required-indicator" for="SSN">SSN:</label>

    </div>

    <!-- Inner div for input, field-level validation errors, and field-level help -->
    <div class="col-md-4">

        <!-- Input -->
        <input id="SSN" formControlName="ssn" type="number" jhaZeroPaddedNumber jhaLength="9" min="0" max="999999999"
            class="form-control" required autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" />

        <!-- Field-level validation errors -->
        <div *ngIf="ssn.invalid && (ssn.dirty || ssn.touched)" class="help-block">

            <!-- Required field error -->
            <div *ngIf="ssn.errors.required">
                SSN is required
            </div>

            <!-- Out of range error -->
            <div *ngIf="ssn.errors.min || ssn.errors.max">
                Must be between 0 and 999999999
            </div>

        </div>

        <!-- Field-level help -->
        <div class="help-block">Enter value without dashes</div>

    </div>

</div>
Action Buttons

To add an action button to a field, wrap the element with a , then add a new span for the button as shown in the example below.

For example, if you have an input like this:

Input example
<div class="col-md-4">
    <input id="Name" formControlName="name" type="text" class="form-control" required
        autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" />
</div>

Add the sections below to include an action button. The button’s click event will typically reference a method in your controller.

Same input with an action button
<div class="col-md-4">
    <div class="input-group">
        <input id="Name" formControlName="name" type="text" class="form-control" required
            autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" />
        <span class="input-group-btn">
            <jha-button jhaIconType="Ellipsis" (click)="someMethod()"></jha-button>
        </span>
    </div>
</div>
This currency field includes an action button
Action button example

Action buttons always display using secondary button styling.

Don’t set the jhaButtonStyle property on the jha-button for an action button, since it will be ignored.


Design

Figma design

Figma design info
You can find this component in the Components - Forms page in the Figma UI Kit.
Dev ComponentDesign Component Name
Save buttonRUI / Buttons / Button; set Style to “Primary”
Cancel buttonRUI / Buttons / Button; set Style to “Secondary”
Field labelAdd text and apply the “rui/regular” text style and “rui-pacific/text-regular” color style. Suffix the field label with a colon.
Required field indicatorRUI / Forms / Required Field Indicator
SubheaderRUI / Layout / Subheader; set Size to Small and switch on Separator
Text inputJHA / Forms / Text Input; set State to “Watermark” if you want to show watermark text instead of user input, otherwise leave State as “Normal”
Date inputRUI / Forms / Date Input
Inline date inputRUI / Forms / Inline Date Input
Inline time inputRUI / Forms / Inline Time Input
Inline date/time inputRUI / Forms / Inline Date Time Input
Currency inputRUI / Forms / Currency Input
Rate inputRUI / Forms / Rate Input
Dropdown inputRUI / Forms / Dropdown Input
CheckboxRUI / Forms / Checkbox
Radio buttonRUI / Forms / Radio Button
Button groupRUI / Buttons / Button Group
Slider ThumbRUI / Forms / Slider Thumb
Slider TrackRUI / Forms / Slider Track
Field-level tooltipRUI / Forms / Field Tooltip
Field-level tooltip popupRUI / Forms / Field Tooltip Popup
Action ButtonRUI / Forms / Action Button
Rich text editorRUI / Forms / Rich Text Editor
Help textAdd text and apply the “rui/help-text” text style and “rui-pacific/text-help” color style.

Show Save and Cancel buttons below the display block title, with the Save button as a primary button and the Cancel button as a secondary button.

For each field:

  • Display a field label to the left of the input component. Suffix the field label text with a colon.
  • Display a required field indicator to the right of the label for every required field.
  • Display the appropriate input component to the right of the field label.
  • Display help text below the input component if appropriate. Try to limit the usage of help text to just those cases where it’s absolutely needed.
  • You can optionally display a field-level tooltip to the right of any field label if that field should display additional help input in a special tooltip when the user hovers or clicks the icon.
    • You can also optionally display the field-level tooltip popup above the field-level tooltip icon if you need to show the tooltip text, although this should be done sparingly to cut down on the number of artboards in your design. Field tooltip popup text will typically be conveyed through a separate design artifact.
  • You can layer an action button above and at the right edge of the input component if the user should be able to press a button to perform a secondary activity associated with the input component.
    • Pressing the action button will typically display a dialog box that helps the user come up with the appropriate value for the field.
    • Note that the date input component already has a built-in action button for displaying a calendar popup, so you should not add an action button to date input components.

Adobe XD design

Adobe XD design info
You can find this component in these artboards in the Adobe XD design samples:
  • Sample App - Editing Form Data
Dev ComponentDesign Component Name
Save buttonJHA / Buttons / Button / Primary
Cancel buttonJHA / Buttons / Button / Secondary
Field labelAdd text and apply the “JHA / Text / Regular” character style. Suffix the field label with a colon.
Required field indicatorJHA / Forms / Required Field Indicator
SubheaderJHA / Subheader with “Small with Separator” state applied
Text input

JHA / Forms / Text Input

  • Select the “Watermark Text” state in the component if you want to show watermark text instead of user input.
Date inputJHA / Forms / Date Input
Inline date inputJHA / Forms / Inline Date Input
Inline time inputJHA / Forms / Inline Time Input
Inline date/time inputJHA / Forms / Inline Date/Time Input
Currency inputJHA / Forms / Currency Input
Rate inputJHA / Forms / Rate Input
Dropdown inputJHA / Forms / Dropdown Input
Checkbox - checkedJHA / Forms / Checkbox / Checked
Checkbox - uncheckedJHA / Forms / Checkbox / Unchecked
Radio button - checkedJHA / Forms / Radio Button / Checked
Radio button - uncheckedJHA / Forms / Radio Button / Unchecked
Button group - unselectedJHA / Buttons / Button Group ; choose the “Default State” state
Button group - selectedJHA / Buttons / Button Group ; choose the “Selected” state
Button group - disabledJHA / Buttons / Button Group / choose the “Disabled” state
Slider ThumbJHA / Forms / Slider Thumb
Slider TrackJHA / Forms / Slider Track
Field-level tooltipJHA / Forms / Field Tooltip
Field-level tooltip popupJHA / Forms / Field Tooltip Popup
Action ButtonJHA / Forms / Action Button
Rich text editorJHA / Forms / Rich Text Editor
Help textJHA / Forms / Help Text

Show Save and Cancel buttons below the display block title, with the Save button as a primary button and the Cancel button as a secondary button.

For each field:

  • Display a field label to the left of the input component. Suffix the field label text with a colon.
  • Display a required field indicator to the right of the label for every required field.
  • Display the appropriate input component to the right of the field label.
  • Display help text below the input component if appropriate. Try to limit the usage of help text to just those cases where it’s absolutely needed.
  • You can optionally display a field-level tooltip to the right of any field label if that field should display additional help input in a special tooltip when the user hovers or clicks the icon.
    • You can also optionally display the field-level tooltip popup above the field-level tooltip icon if you need to show the tooltip text, although this should be done sparingly to cut down on the number of artboards in your design. Field tooltip popup text will typically be conveyed through a separate design artifact.
  • You can layer an action button above and at the right edge of the input component if the user should be able to press a button to perform a secondary activity associated with the input component.
    • Pressing the action button will typically display a dialog box that helps the user come up with the appropriate value for the field.
    • Note that the date input component already has a built-in action button for displaying a calendar popup, so you should not add an action button to date input components.
    • If you add an action button, layer the “Ellipses” icon above this button and set its state to “Secondary Button”.

Support options
Have questions on this topic?
Join the Responsive UI team in Microsoft Teams to connect with the community.
See something in this page that needs to change?
Send us feedback on this page.
Last updated Tue Sep 17 2024