Form Field
Display a form field to handle errors and hints.
import { Component } from '@angular/core';
import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms';
import { HlmFormFieldModule } from '@spartan-ng/helm/form-field';
import { HlmInput } from '@spartan-ng/helm/input';
@Component({
selector: 'spartan-form-field-preview',
imports: [HlmInput, HlmFormFieldModule, ReactiveFormsModule],
template: `
<hlm-form-field>
<input class="w-80" hlmInput [formControl]="control" type="email" placeholder="Email" />
<hlm-hint>This is your email address.</hlm-hint>
<hlm-error>The email is required.</hlm-error>
</hlm-form-field>
`,
})
export class FormFieldPreview {
public control = new FormControl('', Validators.required);
}
Installation
npx nx g @spartan-ng/cli:ui formfield
ng g @spartan-ng/cli:ui formfield
Usage
import { HlmFormFieldModule } from '@spartan-ng/helm/form-field';
import { HlmInputDirective } from '@spartan-ng/helm/input';
<hlm-form-field>
<input class="w-80" hlmInput type="email" placeholder="Email" />
<hlm-hint>This is your email address.</hlm-hint>
</hlm-form-field>
Helm API
SingleFormFieldMock
Selector: single-form-field-example
SingleFormFieldDirtyMock
Selector: single-form-field-dirty-example
HlmError
Selector: hlm-error
Inputs
Prop | Type | Default | Description |
---|---|---|---|
class | ClassValue | - | - |
HlmFormField
Selector: hlm-form-field
Inputs
Prop | Type | Default | Description |
---|---|---|---|
class | ClassValue | - | - |
HlmHint
Selector: hlm-hint
Inputs
Prop | Type | Default | Description |
---|---|---|---|
class | ClassValue | - | - |
Examples
Error
import { Component, type OnInit } from '@angular/core';
import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms';
import { HlmFormFieldModule } from '@spartan-ng/helm/form-field';
import { HlmInput } from '@spartan-ng/helm/input';
@Component({
selector: 'spartan-form-field-error',
imports: [ReactiveFormsModule, HlmFormFieldModule, HlmInput],
template: `
<hlm-form-field>
<input aria-label="Your Name" class="w-80" [formControl]="name" hlmInput type="text" placeholder="Your Name" />
<hlm-error>Your name is required</hlm-error>
</hlm-form-field>
`,
})
export class FormFieldErrorPreview implements OnInit {
public name = new FormControl('', Validators.required);
ngOnInit(): void {
this.name.markAsTouched();
}
}
With Form
import { Component, inject } from '@angular/core';
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
import { BrnSelectImports } from '@spartan-ng/brain/select';
import { HlmButtonModule } from '@spartan-ng/helm/button';
import { HlmFormFieldModule } from '@spartan-ng/helm/form-field';
import { HlmInput } from '@spartan-ng/helm/input';
import { HlmSelectImports, HlmSelectModule } from '@spartan-ng/helm/select';
@Component({
selector: 'spartan-form-field-form',
imports: [
ReactiveFormsModule,
HlmFormFieldModule,
HlmSelectModule,
HlmInput,
HlmSelectImports,
BrnSelectImports,
HlmButtonModule,
],
template: `
<form [formGroup]="form" class="space-y-6">
<hlm-form-field>
<input
aria-label="Your Name"
formControlName="name"
class="w-80"
hlmInput
type="text"
placeholder="Your Name"
/>
<hlm-error>Your name is required</hlm-error>
</hlm-form-field>
<hlm-form-field>
<brn-select class="inline-block" placeholder="Select some fruit" formControlName="fruit">
<hlm-select-trigger class="w-80">
<hlm-select-value />
</hlm-select-trigger>
<hlm-select-content>
<hlm-select-label>Fruits</hlm-select-label>
@for (option of options; track option.value) {
<hlm-option [value]="option.value">{{ option.label }}</hlm-option>
}
</hlm-select-content>
</brn-select>
<hlm-error>The fruit is required</hlm-error>
</hlm-form-field>
<button type="submit" hlmBtn>Submit</button>
</form>
`,
})
export class FormFieldFormPreview {
private readonly _formBuilder = inject(FormBuilder);
public form = this._formBuilder.group({
name: ['', Validators.required],
fruit: ['', Validators.required],
});
public options = [
{ value: 'apple', label: 'Apple' },
{ value: 'banana', label: 'Banana' },
{ value: 'blueberry', label: 'Blueberry' },
{ value: 'grapes', label: 'Grapes' },
{ value: 'pineapple', label: 'Pineapple' },
];
}
Changing when error messages are shown
By default, these error messages are shown when the control is invalid and the user has interacted with (touched) the element or the parent form has been submitted. If you wish to override this behavior (e.g. to show the error as soon as the invalid control is dirty or when a parent form group is invalid), you can use the ErrorStateMatcher
provider.
For convenience, ShowOnDirtyErrorStateMatcher
is available in order to globally cause input errors to show when the input is dirty and invalid
providers: [
{ provide: ErrorStateMatcher, useClass: ShowOnDirtyErrorStateMatcher }
]
import { Component, inject } from '@angular/core';
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
import { ErrorStateMatcher, ShowOnDirtyErrorStateMatcher } from '@spartan-ng/brain/forms';
import { BrnSelectImports } from '@spartan-ng/brain/select';
import { HlmButtonModule } from '@spartan-ng/helm/button';
import { HlmFormFieldModule } from '@spartan-ng/helm/form-field';
import { HlmInput } from '@spartan-ng/helm/input';
import { HlmSelectImports, HlmSelectModule } from '@spartan-ng/helm/select';
@Component({
selector: 'spartan-form-field-form-dirty',
imports: [
ReactiveFormsModule,
HlmFormFieldModule,
HlmSelectModule,
HlmInput,
HlmSelectImports,
BrnSelectImports,
HlmButtonModule,
],
template: `
<form [formGroup]="form" class="space-y-6">
<hlm-form-field>
<input
aria-label="Your Name"
formControlName="name"
class="w-80"
hlmInput
type="text"
placeholder="Your Name"
/>
<hlm-error>Your name is required</hlm-error>
</hlm-form-field>
<hlm-form-field>
<brn-select class="inline-block" placeholder="Select some fruit" formControlName="fruit">
<hlm-select-trigger class="w-80">
<hlm-select-value />
</hlm-select-trigger>
<hlm-select-content>
<hlm-select-label>Fruits</hlm-select-label>
@for (option of options; track option.value) {
<hlm-option [value]="option.value">{{ option.label }}</hlm-option>
}
</hlm-select-content>
</brn-select>
<hlm-error>The fruit is required</hlm-error>
</hlm-form-field>
<button type="submit" hlmBtn>Submit</button>
</form>
`,
providers: [{ provide: ErrorStateMatcher, useClass: ShowOnDirtyErrorStateMatcher }],
})
export class FormFieldFormWithDirtyPreview {
private readonly _formBuilder = inject(FormBuilder);
public form = this._formBuilder.group({
name: ['', Validators.required],
fruit: ['', Validators.required],
});
public options = [
{ value: 'apple', label: 'Apple' },
{ value: 'banana', label: 'Banana' },
{ value: 'blueberry', label: 'Blueberry' },
{ value: 'grapes', label: 'Grapes' },
{ value: 'pineapple', label: 'Pineapple' },
];
}
export const providerShowOnDirtyErrorStateMatcher = `
providers: [
{ provide: ErrorStateMatcher, useClass: ShowOnDirtyErrorStateMatcher }
]
`;