Skip to main content

Overview

The Textarea component extends the standard Input component to provide multi-line text entry. It’s perfect for comments, descriptions, addresses, and any content that requires more than one line.

When to Use

Use the Textarea component when you need to:
  • Capture comments, feedback, or descriptions
  • Enter multi-line addresses
  • Write longer text content (bio, notes, etc.)
  • Provide space for detailed explanations
For single-line text, use Input instead. Textarea inherits all Input properties and methods.

Basic Usage

import { TextArea } from 'mat-dynamic-form';

const commentArea = new TextArea(
  'comments',
  'Comments'
);

Common Patterns

Textarea with Character Limit

import { Validators } from '@angular/forms';

const bioArea = new TextArea(
  'bio',
  'Biography',
  '',
  500 // maxCharCount
).apply({
  icon: 'description',
  validator: Validators.required,
  hint: 'Tell us about yourself (max 500 characters)'
});
The character counter appears automatically when maxCharCount is set.

Textarea with Validation

const feedbackArea = new TextArea(
  'feedback',
  'Your Feedback',
  '',
  1000
).apply({
  icon: 'feedback',
  validator: [Validators.required, Validators.minLength(10)],
  errorMessage: 'Please provide at least 10 characters of feedback',
  hint: 'We value your input'
});

Full-Width Textarea

const descriptionArea = new TextArea(
  'description',
  'Product Description',
  '',
  2000
).apply({
  singleLine: true, // Takes full row width
  icon: 'notes',
  validator: Validators.required,
  hint: 'Provide a detailed product description'
});

Read-Only Textarea

const termsArea = new TextArea(
  'terms',
  'Terms and Conditions',
  'These are the terms...'
).apply({
  readOnly: true,
  singleLine: true,
  hint: 'Please read carefully'
});

Textarea with Value Change Handler

const messageArea = new TextArea(
  'message',
  'Message',
  '',
  500
).apply({
  icon: 'message',
  action: {
    type: 'valueChange',
    onEvent: (param) => {
      const text = param.event;
      const wordCount = text.trim().split(/\s+/).length;
      console.log('Word count:', wordCount);
      
      // Show warning if too long
      if (text.length > 450) {
        console.warn('Approaching character limit');
      }
    }
  }
});

Properties

id
string
required
Unique identifier for the textarea.
placeholder
string
Placeholder text shown when the textarea is empty.
value
any
Initial value of the textarea.
maxCharCount
number
Maximum number of characters allowed. Shows a character counter.
minCharCount
number
Minimum number of characters required.
readOnly
boolean
default:"false"
Whether the textarea is read-only.
icon
string
Material icon name to display (e.g., 'notes', 'description', 'message').
validator
ValidatorFn | ValidatorFn[]
Angular validators to apply.
errorMessage
string
Custom error message shown when validation fails.
hint
string
Helper text displayed below the textarea.
disabled
boolean
default:"false"
Whether the textarea is disabled.
singleLine
boolean
default:"false"
Whether the textarea takes up a full row in the form grid.
autoFocus
boolean
default:"false"
Whether the textarea receives focus when the form loads.

Methods

editable()

Makes the textarea editable by setting readOnly to false.
const textarea = new TextArea('field', 'Field').apply({ readOnly: true });

// Later, make it editable
textarea.editable();

readonly()

Makes the textarea read-only by setting readOnly to true.
const textarea = new TextArea('field', 'Field');

// Make it read-only
textarea.readonly();

apply()

Applies multiple properties at once.
textarea.apply({
  icon: 'notes',
  validator: Validators.required,
  maxCharCount: 500,
  hint: 'Enter your text here'
});

getNativeElement()

Returns the native DOM element.
const element = textarea.getNativeElement();
if (element) {
  element.focus();
}

Validation Examples

Required Textarea

import { Validators } from '@angular/forms';

const textarea = new TextArea('comments', 'Comments', '', 500).apply({
  validator: Validators.required,
  errorMessage: 'Comments are required'
});

Min/Max Length Validation

const textarea = new TextArea('description', 'Description', '', 1000).apply({
  validator: [
    Validators.required,
    Validators.minLength(50),
    Validators.maxLength(1000)
  ],
  errorMessage: 'Description must be between 50 and 1000 characters'
});

Pattern Validation (No Special Characters)

const textarea = new TextArea('notes', 'Notes', '', 500).apply({
  validator: [
    Validators.required,
    Validators.pattern(/^[a-zA-Z0-9\s.,!?-]*$/)
  ],
  errorMessage: 'Only letters, numbers, and basic punctuation allowed'
});

Word Count Validator

import { AbstractControl, ValidationErrors } from '@angular/forms';

function wordCountValidator(min: number, max: number) {
  return (control: AbstractControl): ValidationErrors | null => {
    if (!control.value) return null;
    
    const wordCount = control.value.trim().split(/\s+/).filter((w: string) => w.length > 0).length;
    
    if (wordCount < min) {
      return { minWords: { required: min, actual: wordCount } };
    }
    
    if (wordCount > max) {
      return { maxWords: { required: max, actual: wordCount } };
    }
    
    return null;
  };
}

const textarea = new TextArea('essay', 'Essay', '', 5000).apply({
  validator: [Validators.required, wordCountValidator(100, 500)],
  errorMessage: 'Essay must be between 100 and 500 words',
  hint: 'Write 100-500 words'
});

Complete Example

import { Component } from '@angular/core';
import { Validators } from '@angular/forms';
import { FormStructure, Input, TextArea, Dropdown, OptionChild, Button } from 'mat-dynamic-form';

@Component({
  selector: 'app-feedback-form',
  template: '<mat-dynamic-form [structure]="formStructure"></mat-dynamic-form>'
})
export class FeedbackFormComponent {
  formStructure: FormStructure;
  
  constructor() {
    this.formStructure = new FormStructure('Submit Feedback');
    this.formStructure.appearance = 'outline';
    this.formStructure.nodeGrid = 2;
    
    this.formStructure.nodes = [
      new Input('name', 'Your Name').apply({
        icon: 'person',
        validator: Validators.required,
        singleLine: true
      }),
      
      new Input('email', 'Email Address').apply({
        icon: 'email',
        validator: [Validators.required, Validators.email],
        singleLine: true
      }),
      
      new Dropdown(
        'category',
        'Feedback Category',
        [
          new OptionChild('Bug Report', 'bug'),
          new OptionChild('Feature Request', 'feature'),
          new OptionChild('General Feedback', 'general'),
          new OptionChild('Complaint', 'complaint')
        ]
      ).apply({
        icon: 'category',
        validator: Validators.required,
        singleLine: true
      }),
      
      new Input('subject', 'Subject').apply({
        icon: 'subject',
        validator: Validators.required,
        maxCharCount: 100,
        singleLine: true
      }),
      
      new TextArea(
        'message',
        'Your Message',
        '',
        1000
      ).apply({
        icon: 'message',
        validator: [Validators.required, Validators.minLength(20)],
        errorMessage: 'Please provide at least 20 characters',
        hint: 'Describe your feedback in detail (max 1000 characters)',
        singleLine: true
      }),
      
      new TextArea(
        'steps',
        'Steps to Reproduce (for bugs)',
        '',
        500
      ).apply({
        icon: 'list',
        hint: 'Optional: Help us understand the issue',
        singleLine: true
      })
    ];
    
    this.formStructure.validateActions = [
      new Button('reset', 'Clear Form', {
        style: 'warn',
        onEvent: (param) => {
          param.structure.reset();
          param.structure.remapValues();
        }
      }).apply({
        icon: 'clear'
      }),
      
      new Button('submit', 'Submit Feedback', {
        style: 'primary',
        onEvent: (param) => this.onSubmit(param.structure)
      }).apply({
        validateForm: true,
        icon: 'send'
      })
    ];
  }
  
  onSubmit(structure: FormStructure) {
    const data = structure.getValue();
    console.log('Feedback:', data);
    
    // Submit to API
    // this.feedbackService.submit(data).subscribe(...);
    
    alert('Thank you for your feedback!');
    structure.reset();
    structure.remapValues();
  }
}

Best Practices

Set appropriate character limits - Balance between giving users enough space and preventing excessive input:
maxCharCount: 500 // For short descriptions
maxCharCount: 2000 // For longer content
Use full width for longer content - Textareas benefit from more horizontal space:
singleLine: true // Takes full row width
Provide helpful hints - Guide users on what to write:
hint: 'Describe the issue in detail'
hint: 'Include any relevant background information'
Don’t set maxCharCount too low - Users get frustrated when they can’t express themselves. 500+ is a good starting point.
Consider minimum length validation - For critical fields, ensure users provide enough detail:
validator: [Validators.required, Validators.minLength(20)]
Use appropriate icons:
  • 'notes' - General notes/text
  • 'description' - Descriptions
  • 'message' - Messages/comments
  • 'feedback' - Feedback
  • 'comment' - Comments

Common Use Cases

Address Entry

const addressArea = new TextArea(
  'address',
  'Address',
  '',
  200
).apply({
  icon: 'location_on',
  validator: Validators.required,
  hint: 'Enter your complete address',
  singleLine: true
});

Product Description

const descriptionArea = new TextArea(
  'description',
  'Product Description',
  '',
  2000
).apply({
  icon: 'inventory',
  validator: [Validators.required, Validators.minLength(50)],
  hint: 'Provide a detailed description (at least 50 characters)',
  singleLine: true
});

User Bio

const bioArea = new TextArea(
  'bio',
  'About Me',
  '',
  500
).apply({
  icon: 'person',
  hint: 'Tell us about yourself (max 500 characters)'
});

Comment Section

const commentArea = new TextArea(
  'comment',
  'Leave a Comment',
  '',
  1000
).apply({
  icon: 'comment',
  validator: [Validators.required, Validators.minLength(5)],
  hint: 'Share your thoughts',
  singleLine: true
});

Textarea vs Input

Choose between Textarea and Input based on content length:
Use CaseComponentReason
Name, email, phoneInputSingle line is sufficient
Comments, feedbackTextareaMulti-line needed
AddressTextareaMultiple lines typical
URLInputSingle line
DescriptionTextareaUsually longer content
UsernameInputAlways single line
BioTextareaMultiple sentences

Input

For single-line text entry

Input File

For file uploads with descriptions

See Also

Build docs developers (and LLMs) love