Angular Material Textarea
September 05, 2018
This page will walk through Angular Material textarea example. Angular Material provides MatInput
Directive to create <input>
and <textarea>
element with a MatFormField
. To use MatInput
we need to import MatInputModule
in application module. MatInput
provides errorStateMatcher
property to assign ErrorStateMatcher
object to control when to show validation error.
Angular Component Dev Kit (CDK) provides
CdkTextareaAutosize
Directive to automatically resize a textarea to fit its content. It provides cdkTextareaAutosize
property to enable autosizing, cdkAutosizeMinRows
property to define minimum amount of rows and cdkAutosizeMaxRows
property to define maximum amount of rows in the textarea for autosizing. CdkTextareaAutosize
also provides resizeToFitContent()
method to resize the text area to fit its content and reset()
method to reset the textarea to original size.
On this page we will create Angular Material textarea and validate it. We will use
CdkTextareaAutosize
Directive for autosizing and will create reactive and template-driven forms with Angular Material textarea.
Contents
Technologies Used
Find the technologies being used in our example.1. Angular 6.1.0
2. Angular CLI 6.1.3
3. Angular Material 6.4.7
4. TypeScript 2.7.2
5. Node.js 10.3.0
6. NPM 6.1.0
Import MatInputModule
To work with Angular Material<input>
and <textarea>
, we need to import MatInputModule
in application module.
import { MatInputModule } from '@angular/material/input'; @NgModule({ imports: [ ------ MatInputModule ], ------ }) export class AppModule { }
Use MatInput to create Textarea
Angular Material usesMatInput
Directive to create <input>
and <textarea>
inside a <mat-form-field>
. MatInput
Directive selector is matInput
. Find the code snippet to create a <textarea>
using matInput
selector.
<mat-form-field> <textarea matInput placeholder="Comment" [formControl]="commentFC" (change)="onCommentChange()"> </textarea> </mat-form-field>
commentFC = new FormControl(); onCommentChange() { console.log(this.commentFC.value); }
MatInput
has following properties.
errorStateMatcher: This is
ErrorStateMatcher
object to control when error messages are shown.
readonly: This is Boolean value to know if element is readonly.
type: It gives input type of the element.
errorState: This is Boolean value to know if control is in error state or not.
Validation
To apply validation on<textarea>
input, we can use Angular Validators
as usual. Find the code snippet of TS file.
commentFC = new FormControl('', [ Validators.required, Validators.maxLength(30) ]);
<textarea>
in HTML template.
<mat-form-field> <textarea matInput placeholder="Comment" [formControl]="commentFC" (change)="onCommentChange()"> </textarea> <mat-error *ngIf="commentFC.hasError('required')"> Comment is required. </mat-error> <mat-error *ngIf="commentFC.hasError('maxlength')"> Max length is 30. </mat-error> </mat-form-field>
mat-error
and mat-form-field
associates error messages with matInput
. By default errors are shown in the state of invalid control, touched or form submitted. We can use custom ErrorStateMatcher
to change default behavior when to show error.
Using Custom ErrorStateMatcher
Angular Material providesErrorStateMatcher
to control when to show error. It has isErrorState()
method that accepts FormControl
and FormGroupDirective
or NgForm
as arguments and returns Boolean. To create custom ErrorStateMatcher
class, we need to implement ErrorStateMatcher
and override isErrorState()
. If isErrorState()
returns true
, error will be shown and if false
then error will not be shown. To use it with <input>
and <textarea>
input, MatInput
Directive provides errorStateMatcher
property. We need to assign the object of custom ErrorStateMatcher
to errorStateMatcher
property. Find our custom ErrorStateMatcher
.
custom-error-state-matcher.ts
import { ErrorStateMatcher } from '@angular/material/core'; import { FormControl, FormGroupDirective, NgForm } from '@angular/forms'; export class CustomErrorStateMatcher implements ErrorStateMatcher { isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean { const isSubmitted = form && form.submitted; return (control.invalid && (control.dirty || control.touched || isSubmitted)); } }
ErrorStateMatcher
can be used for a <input>
and <textarea>
using errorStateMatcher
property or globally for every <input>
and <textarea>
in the application.
a. To use
errorStateMatcher
property, we will create an instance of CustomErrorStateMatcher
in TS file.
esMatcher = new CustomErrorStateMatcher();
esMatcher
object with errorStateMatcher
property.
<mat-form-field> <textarea matInput placeholder="Comment" [formControl]="commentFC" [errorStateMatcher]="esMatcher" (change)="onCommentChange()"> </textarea> <mat-error *ngIf="commentFC.hasError('required')"> Comment is required. </mat-error> <mat-error *ngIf="commentFC.hasError('maxlength')"> Max length is 30. </mat-error> </mat-form-field>
ErrorStateMatcher
globally, configure provider in application module as following.
providers: [ {provide: ErrorStateMatcher, useClass: CustomErrorStateMatcher} ]
CustomErrorStateMatcher
will be applied to all <input>
and <textarea>
element in the application. Angular material also provides ShowOnDirtyErrorStateMatcher
that matches when a control is invalid and dirty.
Using CdkTextareaAutosize
CdkTextareaAutosize
Directive is used to automatically resize a textarea to fit its content. Component Dev Kit (CDK) provides high quality predefined behavior for the components. CDK allows us to add common interaction patterns with minimal effort.
Find the
CdkTextareaAutosize
properties to use with textarea.
1. cdkTextareaAutosize
It defines whether autosizing is enabled or not.
cdkTextareaAutosize
is used with <textarea>
element. It is declared in CdkTextareaAutosize
Directive as following.
@Input('cdkTextareaAutosize') get enabled(): boolean { return this._enabled; }
enabled
property in TS file to know if autosize is enabled or not.
2. cdkAutosizeMinRows
It defines minimum amount of rows in the textarea for autosizing.
cdkAutosizeMinRows
is used with <textarea>
element. It is declared in CdkTextareaAutosize
Directive as following.
@Input('cdkAutosizeMinRows') get minRows(): number { return this._minRows; }
minRows
property in TS file to get configured autosize minimum rows.
3. cdkAutosizeMaxRows
It defines maximum amount of rows in the textarea for autosizing.
cdkAutosizeMaxRows
is used with <textarea>
element. It is declared in CdkTextareaAutosize
Directive as following.
@Input('cdkAutosizeMaxRows') get maxRows(): number { return this._maxRows; }
maxRows
property in TS file to get configured autosize maximum rows.
Now find the sample example of textarea with autosize configurations.
<mat-form-field> <textarea matInput placeholder="Description" [formControl]="descFC" cdkTextareaAutosize cdkAutosizeMinRows="2" cdkAutosizeMaxRows="5" #autosize="cdkTextareaAutosize" (change)="onDescChange()"> </textarea> <mat-error *ngIf="descFC.hasError('required')"> Description is required. </mat-error> </mat-form-field>
descFC = new FormControl('', [ Validators.required ]); @ViewChild('autosize') txtAreaAutosize: CdkTextareaAutosize; onDescChange() { console.log("enabled: "+ this.txtAreaAutosize.enabled); console.log("minRows: "+ this.txtAreaAutosize.minRows); console.log("maxRows: "+ this.txtAreaAutosize.maxRows); console.log("Description: "+ this.descFC.value); }
resizeToFitContent()
method of CdkTextareaAutosize
is used to resize the text area to fit its content. It accepts Boolean value. By passing true
we can force a height calculation. By default, height calculation is performed only when value changed since the last call.
5. reset()
reset()
method of CdkTextareaAutosize
resets the textarea to original size. When we configure cdkAutosizeMinRows
and cdkAutosizeMaxRows
in textarea, it is auto resized. On calling reset()
, textarea resizes to its original size.
Find the HTML code snippet to test
resizeToFitContent()
and reset()
.
<div> <mat-form-field [style.fontSize]="fontSize.value"> <textarea matInput placeholder="Content" [formControl]="contentFC" cdkTextareaAutosize cdkAutosizeMinRows="2" cdkAutosizeMaxRows="5" #cfcAutosize="cdkTextareaAutosize"> </textarea> </mat-form-field> </div> <div> <button mat-button (click)="resetTextAreaSize()">Reset Textarea Size</button> </div> <br/> <div> <mat-form-field> <mat-label>Select Font size</mat-label> <mat-select #fontSize value="15px" (selectionChange)="resizeTextArea()"> <mat-option value="10px">10px</mat-option> <mat-option value="15px">15px</mat-option> <mat-option value="20px">20px</mat-option> </mat-select> </mat-form-field> </div>
constructor(private ngZone: NgZone) {} contentFC = new FormControl(); @ViewChild('cfcAutosize') contentFCAutosize: CdkTextareaAutosize; resizeTextArea() { this.ngZone.onStable.pipe(take(1)) .subscribe(() => this.contentFCAutosize.resizeToFitContent(true)); } resetTextAreaSize() { this.contentFCAutosize.reset(); }
NgZone
is an injectable service for executing work inside or outside of the Angular zone.
Create readonly Textarea
To create a readonly textarea, usereadonly
property with <textarea>
element.
<mat-form-field> <textarea matInput readonly cdkTextareaAutosize cdkAutosizeMinRows="2" cdkAutosizeMaxRows="5"> Text Line 1 Text Line 2 Text Line 3 </textarea> </mat-form-field>
Reactive Form Example using Textarea
Find the complete code to create textarea using reactive form.reactive-form.component.html
<h4>1. Textarea validation</h4> <div> <mat-form-field> <textarea matInput placeholder="Comment" [formControl]="commentFC" [errorStateMatcher]="esMatcher" (change)="onCommentChange()"> </textarea> <mat-error *ngIf="commentFC.hasError('required')"> Comment is required. </mat-error> <mat-error *ngIf="commentFC.hasError('maxlength')"> Max length is 30. </mat-error> </mat-form-field> </div> <h4>2. Textarea autosize</h4> <div> <mat-form-field> <textarea matInput placeholder="Description" [formControl]="descFC" cdkTextareaAutosize cdkAutosizeMinRows="2" cdkAutosizeMaxRows="5" #autosize="cdkTextareaAutosize" (change)="onDescChange()"> </textarea> <mat-error *ngIf="descFC.hasError('required')"> Description is required. </mat-error> </mat-form-field> </div> <h4>3. resizeToFitContent() and Reset() test</h4> <div> <mat-form-field [style.fontSize]="fontSize.value"> <textarea matInput placeholder="Content" [formControl]="contentFC" cdkTextareaAutosize cdkAutosizeMinRows="2" cdkAutosizeMaxRows="5" #cfcAutosize="cdkTextareaAutosize"> </textarea> </mat-form-field> </div> <div> <button mat-raised-button (click)="resetTextAreaSize()">Reset Textarea Size</button> </div> <br/> <div> <mat-form-field> <mat-label>Select Font size</mat-label> <mat-select #fontSize value="15px" (selectionChange)="resizeTextArea()"> <mat-option value="10px">10px</mat-option> <mat-option value="15px">15px</mat-option> <mat-option value="20px">20px</mat-option> </mat-select> </mat-form-field> </div> <h4>4. Person Reactive Form</h4> <form [formGroup]="personForm" (ngSubmit)="onFormSubmit()"> <div> <mat-form-field> <input matInput placeholder="Name" formControlName="name" [errorStateMatcher]="esMatcher"> <mat-error *ngIf="name.hasError('required')"> Name is required. </mat-error> </mat-form-field> </div> <div> <mat-form-field> <textarea matInput placeholder="Address" formControlName="address" cdkTextareaAutosize cdkAutosizeMinRows="2" cdkAutosizeMaxRows="4" [errorStateMatcher]="esMatcher"> </textarea> <mat-error *ngIf="address.hasError('required')"> Comment is required. </mat-error> <mat-error *ngIf="address.hasError('maxlength')"> Max length is 100. </mat-error> </mat-form-field> </div> <div> <button mat-raised-button>Submit</button> </div> </form>
import { Component, OnInit, ViewChild, NgZone } from '@angular/core'; import { FormControl, Validators, FormBuilder } from '@angular/forms'; import { CdkTextareaAutosize } from '@angular/cdk/text-field'; import { take } from 'rxjs/operators'; import { CustomErrorStateMatcher } from './custom-error-state-matcher'; import { PersonService } from './person.service'; @Component({ selector: 'app-reactive', templateUrl: './reactive-form.component.html' }) export class ReactiveFormComponent implements OnInit { constructor(private ngZone: NgZone, private formBuilder: FormBuilder, private personService: PersonService) {} ngOnInit() { } //Textarea validation esMatcher = new CustomErrorStateMatcher(); commentFC = new FormControl('', [ Validators.required, Validators.maxLength(30) ]); onCommentChange() { console.log(this.commentFC.value); } //Textarea autosize descFC = new FormControl('', [ Validators.required ]); @ViewChild('autosize') txtAreaAutosize: CdkTextareaAutosize; onDescChange() { console.log("enabled: "+ this.txtAreaAutosize.enabled); console.log("minRows: "+ this.txtAreaAutosize.minRows); console.log("maxRows: "+ this.txtAreaAutosize.maxRows); console.log("Description: "+ this.descFC.value); } //resizeToFitContent() and Reset() test contentFC = new FormControl(); @ViewChild('cfcAutosize') contentFCAutosize: CdkTextareaAutosize; resizeTextArea() { this.ngZone.onStable.pipe(take(1)) .subscribe(() => this.contentFCAutosize.resizeToFitContent(true)); } resetTextAreaSize() { this.contentFCAutosize.reset(); } //Create a form personForm = this.formBuilder.group({ name: ['', Validators.required], address: ['', [Validators.required, Validators.maxLength(100)]] }); onFormSubmit() { this.personService.savePerson(this.personForm.value); } get name() { return this.personForm.get('name'); } get address() { return this.personForm.get('address'); } }
export interface Person { name: string; address: string; }
import { Injectable } from '@angular/core'; import { Person } from './person'; @Injectable({ providedIn: 'root' }) export class PersonService { savePerson(person: Person) { console.log(person); } }
Template-Driven Form Example using Textarea
Find the complete code to create textarea using template-driven form.template-driven-form.component.html
<h4>5. Person Template-Driven Form</h4> <form #personForm="ngForm" (ngSubmit)="onFormSubmit(personForm)"> <div> <mat-form-field> <input matInput placeholder="Name" name="name" required ngModel #name="ngModel" [errorStateMatcher]="esMatcher"> <mat-error *ngIf="name.hasError('required')"> Name is required. </mat-error> </mat-form-field> </div> <div> <mat-form-field> <textarea matInput placeholder="Address" name="address" required maxlength="100" ngModel #address="ngModel" cdkTextareaAutosize cdkAutosizeMinRows="2" cdkAutosizeMaxRows="4" [errorStateMatcher]="esMatcher"> </textarea> <mat-error *ngIf="address.hasError('required')"> Comment is required. </mat-error> </mat-form-field> </div> <div> <button mat-raised-button>Submit</button> </div> </form>
import { Component, OnInit } from '@angular/core'; import { CustomErrorStateMatcher } from './custom-error-state-matcher'; import { PersonService } from './person.service'; @Component({ selector: 'app-template-driven', templateUrl: './template-driven-form.component.html' }) export class TemplateDrivenFormComponent implements OnInit { constructor(private personService: PersonService) {} ngOnInit() { } esMatcher = new CustomErrorStateMatcher(); onFormSubmit(form) { this.personService.savePerson(form.value); } }
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` <app-reactive></app-reactive> <app-template-driven></app-template-driven> ` }) export class AppComponent { }
import { BrowserModule } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; import { MatSelectModule } from '@angular/material/select'; import { MatButtonModule } from '@angular/material/button'; import { ErrorStateMatcher } from '@angular/material/core'; import { CustomErrorStateMatcher } from './custom-error-state-matcher'; import { AppComponent } from './app.component'; import { ReactiveFormComponent } from './reactive-form.component'; import { TemplateDrivenFormComponent } from './template-driven-form.component'; @NgModule({ declarations: [ AppComponent, ReactiveFormComponent, TemplateDrivenFormComponent ], imports: [ BrowserModule, BrowserAnimationsModule, FormsModule, ReactiveFormsModule, MatFormFieldModule, MatInputModule, MatSelectModule, MatButtonModule ], providers: [ // {provide: ErrorStateMatcher, useClass: CustomErrorStateMatcher} ], bootstrap: [AppComponent] }) export class AppModule { }
@import "~@angular/material/prebuilt-themes/indigo-pink.css";
Run Application
To run the application, find the steps.1. Install Angular CLI using link.
2. Install Angular Material using link.
3. Download source code using download link given below on this page.
4. Use downloaded src in your Angular CLI application.
5. Run ng serve using command prompt.
6. Access the URL http://localhost:4200
Find the print screen of the output.

References
Angular Material InputCdkTextareaAutosize Directive
A Component Dev Kit (CDK) for Angular