Skip to content

Pending Review

Pending Review from User Experience (UX)

Textarea Component

Overview

The PWC Textarea component provides a multi-line text input interface with comprehensive validation, accessibility features, and responsive design capabilities. Built on standard HTML textarea elements with enhanced functionality including character limits, clear actions, and seamless form integration for collecting extended text content and user feedback.

Core Capabilities

  • Multi-line Text Input - Native textarea element with customizable rows, character limits, and automatic text wrapping for extended content
  • Built-in Clear Action - Optional clear button with close icon for quick content removal and user convenience
  • Length Validation - Support for minimum and maximum character limits with real-time validation feedback and user guidance
  • Accessibility Support - ARIA attributes, keyboard navigation, screen reader compatibility, and focus management for inclusive design
  • Form Integration - Seamless PWC form context integration with validation states, error handling, and data synchronization
  • Loading State Management - Skeleton rendering during form initialization and data loading operations with appropriate visual feedback

When to use Textarea:

  • Extended text input scenarios requiring multiple lines such as comments, descriptions, feedback, and detailed responses
  • Form fields where users need to provide lengthy explanations, detailed information, or multi-paragraph content
  • Content creation interfaces where users compose messages, notes, documentation, or other substantial text content
  • Data collection forms requiring open-ended responses with flexible input length and formatting requirements

When not to use Textarea:

  • Single-line text input where regular input components provide better user experience and visual consistency
  • Structured data entry where specific input types (email, number, date) offer better validation and user guidance
  • Short responses or simple values where textarea height creates unnecessary vertical space and visual complexity

Basic Implementation

import { PwcButton, PwcForm, PwcTextarea, PwcSubmitEvent } from "@progress-i360/pwc-react";
import { useState } from 'react';

function ProductFeedbackForm() {
  const [isSubmitting, setIsSubmitting] = useState(false);

  const handleSubmit = (event: Event) => {
    const detail = (event as PwcSubmitEvent).detail;
    setIsSubmitting(true);

    setTimeout(() => {
      setIsSubmitting(false);
      detail.success();
    }, 2000);
  };

  return (
    <PwcForm onPwcSubmit={handleSubmit}>
      <PwcTextarea
        name="generalFeedback"
        label="General Feedback"
        placeholder="Share your overall experience with our product..."
        maxLength={500}
        required
        hint="Help us understand what's working well and what could be improved"
        clear
      />

      <PwcTextarea
        name="suggestions"
        label="Improvement Suggestions"
        placeholder="What improvements or new features would you like to see?"
        maxLength={750}
        hint="Optional: Help us prioritize future development"
        clear
      />

      <PwcButton
        type="submit"
        variant="primary"
        label={isSubmitting ? 'Submitting...' : 'Submit Feedback'}
        disabled={isSubmitting}
      />
    </PwcForm>
  );
}
import { useEffect, useRef, useState } from 'react';
import '@progress-i360/progress-web-components/button';
import '@progress-i360/progress-web-components/form';
import '@progress-i360/progress-web-components/textarea';

type TextareaElement = HTMLElement & {
  value?: string;
  required?: boolean;
  maxLength?: number;
  minLength?: number;
  clear?: boolean;
  disabled?: boolean;
};

type ButtonElement = HTMLElement & {
  label?: string;
  disabled?: boolean;
  variant?: string;
};

type PwcSubmitDetail = {
  payload: Record<string, unknown>;
  success: () => void;
};

const DRAFT_STORAGE_KEY = 'ticketDraft';

function SupportTicketForm() {
  const formRef = useRef<HTMLElement | null>(null);
  const descriptionRef = useRef<TextareaElement | null>(null);
  const contextRef = useRef<TextareaElement | null>(null);
  const submitButtonRef = useRef<ButtonElement | null>(null);

  const [formData, setFormData] = useState({
    description: '',
    additionalContext: ''
  });
  const [isSubmitting, setIsSubmitting] = useState(false);

  useEffect(() => {
    const timer = setTimeout(() => {
      if (formData.description || formData.additionalContext) {
        localStorage.setItem(DRAFT_STORAGE_KEY, JSON.stringify(formData));
      }
    }, 1000);

    return () => clearTimeout(timer);
  }, [formData]);

  useEffect(() => {
    const textarea = descriptionRef.current;
    if (!textarea) {
      return;
    }

    textarea.value = formData.description;
    textarea.required = true;
    textarea.maxLength = 1000;
    textarea.minLength = 25;
    textarea.clear = true;
    textarea.disabled = isSubmitting;

    const handleChange = (event: Event) => {
      const detail = (event as CustomEvent<string>).detail ?? '';
      setFormData((previous) => ({ ...previous, description: detail }));
    };

    textarea.addEventListener('pwc-change', handleChange);
    return () => {
      textarea.removeEventListener('pwc-change', handleChange);
    };
  }, [formData.description, isSubmitting]);

  useEffect(() => {
    const textarea = contextRef.current;
    if (!textarea) {
      return;
    }

    textarea.value = formData.additionalContext;
    textarea.maxLength = 800;
    textarea.clear = true;
    textarea.disabled = isSubmitting;

    const handleChange = (event: Event) => {
      const detail = (event as CustomEvent<string>).detail ?? '';
      setFormData((previous) => ({ ...previous, additionalContext: detail }));
    };

    textarea.addEventListener('pwc-change', handleChange);
    return () => {
      textarea.removeEventListener('pwc-change', handleChange);
    };
  }, [formData.additionalContext, isSubmitting]);

  useEffect(() => {
    const button = submitButtonRef.current;
    if (!button) {
      return;
    }

    button.label = isSubmitting ? 'Submitting...' : 'Submit Ticket';
    button.disabled = isSubmitting;
    button.variant = 'primary';
  }, [isSubmitting]);

  useEffect(() => {
    const formElement = formRef.current;
    if (!formElement) {
      return;
    }

    const handleSubmit = (event: Event) => {
      const submitDetail = (event as CustomEvent<PwcSubmitDetail>).detail;
      if (!submitDetail || isSubmitting) {
        return;
      }

      setIsSubmitting(true);
      setTimeout(() => {
        submitDetail.success();
        setIsSubmitting(false);
        localStorage.removeItem(DRAFT_STORAGE_KEY);
      }, 2000);
    };

    formElement.addEventListener('pwc-submit', handleSubmit as EventListener);
    return () => {
      formElement.removeEventListener('pwc-submit', handleSubmit as EventListener);
    };
  }, [isSubmitting]);

  return (
    <pwc-form ref={formRef}>
      <pwc-textarea
        ref={descriptionRef}
        name="description"
        label="Issue Description"
        placeholder="Describe the problem you're experiencing..."
        hint="Provide a detailed description (minimum 25 characters)"
      ></pwc-textarea>

      <pwc-textarea
        ref={contextRef}
        name="additionalContext"
        label="Additional Context"
        placeholder="Browser version, OS, error messages, screenshots, etc."
        hint="Any additional information that might be helpful"
      ></pwc-textarea>

      <pwc-button ref={submitButtonRef} type="submit"></pwc-button>
    </pwc-form>
  );
}
import { Component, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
import "@progress-i360/progress-web-components/button";
import "@progress-i360/progress-web-components/textarea";

@Component({
  selector: 'textarea-demo',
  template: `
    <pwc-textarea 
      label="Project Description" 
      placeholder="Describe your project in detail..."
      [maxLength]="500"
      [minLength]="10"
      required
      hint="Provide a clear overview of your project goals and requirements"
      (pwc-change)="updateDescription($event)"
      (pwc-input)="trackProgress($event)">
    </pwc-textarea>

    <pwc-textarea 
      label="Additional Comments" 
      placeholder="Any additional thoughts or questions?"
      [maxLength]="1000"
      hint="Optional: Share any other relevant information"
      [disabled]="!isDescriptionValid"
      (pwc-change)="updateComments($event)">
    </pwc-textarea>

    <pwc-textarea 
      label="Technical Requirements" 
      placeholder="List technical specifications, constraints, or dependencies..."
      [maxLength]="2000"
      [readOnly]="isReadOnly"
      [border]="true"
      hint="Detailed technical information for development team"
      (pwc-change)="updateRequirements($event)">
    </pwc-textarea>

    <div class="character-counter" *ngIf="showProgress">
      <p>Description: {{ descriptionLength }}/{{ maxDescriptionLength }} characters</p>
      <p>Progress: {{ getCompletionPercentage() }}% complete</p>
    </div>

    <div class="form-actions" *ngIf="hasContent">
      <pwc-button 
        label="Clear All" 
        variant="outline"
        (pwc-click)="clearAllFields()">
      </pwc-button>

      <pwc-button 
        label="Save Draft" 
        variant="primary"
        [disabled]="!canSave"
        (pwc-click)="saveDraft()">
      </pwc-button>
    </div>
  `,
  schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class TextareaDemo {
  projectDescription = '';
  additionalComments = '';
  technicalRequirements = '';
  descriptionLength = 0;
  maxDescriptionLength = 500;
  isReadOnly = false;

  get isDescriptionValid() {
    return this.projectDescription.length >= 10;
  }

  get showProgress() {
    return this.descriptionLength > 0;
  }

  get hasContent() {
    return this.projectDescription || this.additionalComments || this.technicalRequirements;
  }

  get canSave() {
    return this.isDescriptionValid && this.projectDescription.length <= this.maxDescriptionLength;
  }

  updateDescription(event: CustomEvent<string>) {
    this.projectDescription = event.detail || '';
    this.descriptionLength = this.projectDescription.length;

    // Auto-enable technical requirements when description is substantial
    if (this.descriptionLength > 100) {
      this.isReadOnly = false;
    }
  }

  trackProgress(event: CustomEvent<string>) {
    this.descriptionLength = (event.detail || '').length;
  }

  updateComments(event: CustomEvent<string>) {
    this.additionalComments = event.detail || '';
  }

  updateRequirements(event: CustomEvent<string>) {
    this.technicalRequirements = event.detail || '';
  }

  getCompletionPercentage(): number {
    let completed = 0;
    let total = 3;

    if (this.isDescriptionValid) completed++;
    if (this.additionalComments.length > 0) completed++;
    if (this.technicalRequirements.length > 0) completed++;

    return Math.round((completed / total) * 100);
  }

  clearAllFields() {
    this.projectDescription = '';
    this.additionalComments = '';
    this.technicalRequirements = '';
    this.descriptionLength = 0;
    this.isReadOnly = false;
  }

  saveDraft() {
    const draft = {
      description: this.projectDescription,
      comments: this.additionalComments,
      requirements: this.technicalRequirements,
      timestamp: new Date()
    };

    console.log('Saving draft:', draft);
    // Simulate API call
    setTimeout(() => {
      alert('Draft saved successfully!');
    }, 500);
  }
}
import '@progress-i360/progress-web-components/textarea';

// Create textarea for feedback with character limit
const feedbackTextarea = document.createElement('pwc-textarea');
feedbackTextarea.label = 'Your Feedback';
feedbackTextarea.placeholder = 'Please share your thoughts...';
feedbackTextarea.name = 'feedback';
feedbackTextarea.maxLength = 250;
feedbackTextarea.required = true;

feedbackTextarea.addEventListener('pwc-change', (event) => {
  console.log('Feedback updated:', event.detail);
});

document.body.appendChild(feedbackTextarea);

Usage Patterns

  • Form Content Input - Extended text fields for comments, descriptions, feedback, and other multi-line content requiring user input
  • Message Composition - Email drafts, chat messages, notes, and other communication content with flexible formatting needs
  • Data Collection Interfaces - Survey responses, application forms, and user-generated content requiring detailed text input
  • Content Management Systems - Article drafts, documentation editing, and content creation tools with validation and character limits

Best Practices

Content Strategy Guidelines

  • Clear Labeling - Use descriptive labels that clearly indicate the expected content type, format, and purpose of the text input
  • Helpful Placeholder Text - Provide example content or guidance that demonstrates the expected input format and style
  • Character Limit Guidance - Set appropriate minimum and maximum character limits with clear messaging about requirements and constraints
  • Contextual Hints - Use hint text to provide additional guidance, formatting requirements, or examples of good input

Performance Optimization

  • Debounced Validation - Implement input debouncing to prevent excessive validation calls during rapid typing and user input
  • Efficient Change Handling - Use optimized event handling patterns to manage text updates and form synchronization effectively
  • Memory Management - Properly handle large text content and component cleanup to prevent memory leaks in long-running applications
  • Loading State Integration - Implement skeleton states and loading indicators during form initialization and data operations

Integration Architecture

  • Form Context Coordination - Integrate seamlessly with PWC form systems for validation, error handling, and data management workflows
  • Validation Strategy Design - Implement comprehensive validation patterns that handle text length, format requirements, and content rules
  • Accessibility Standards - Ensure proper ARIA labeling, keyboard navigation, and screen reader compatibility for inclusive user experiences
  • Error Handling Patterns - Provide clear validation feedback with actionable error messages and recovery guidance for users

Common Use Cases

Data Table Headers

  • Contact forms with message fields requiring detailed user input and inquiry information for customer service workflows
  • Feedback collection systems with structured comment fields and rating explanations for product improvement analysis
  • Support ticket creation with problem descriptions and detailed context for technical assistance and resolution tracking

Search Result Sections

  • Content creation interfaces with draft management and auto-save functionality for blog posts and article composition
  • Review and comment systems with moderation capabilities and content validation for community-driven platforms
  • Survey response collection with open-ended questions and detailed feedback gathering for research and analysis purposes

Dashboard Widget Headers

  • Settings panels with configuration descriptions and detailed parameter explanations for system customization workflows
  • Report generation interfaces with custom description fields and analysis notes for business intelligence dashboards
  • User profile management with bio sections and detailed information fields for professional networking and social platforms

Troubleshooting

Common Issues

Actions Not Triggering

Symptoms: Clear button doesn't work, input events don't fire, or form submission doesn't include textarea values

Solutions:

  • Verify that event handlers are properly bound using .bind(this) pattern and component instance references are maintained

  • Check that form context integration is working correctly and textarea changes trigger form updates and validation

  • Ensure that disabled state management allows or prevents user interactions appropriately based on component configuration

Actions Not Visible

Symptoms: Clear button doesn't appear, textarea doesn't render, or component appears blank in form contexts

Solutions:

  • Confirm that textarea has content and clear action visibility logic is functioning properly for user interaction states

  • Check that loading states and skeleton rendering work correctly during form initialization and data loading operations

  • Verify that responsive styles and layout constraints accommodate textarea content properly across different screen sizes

Layout Issues

Symptoms: Textarea appears with incorrect height, text wrapping doesn't work, or component doesn't fit form layouts properly

Solutions:

  • Use appropriate container styling and max-width constraints to ensure textarea fits within form layouts and responsive designs

  • Check that text wrapping and overflow handling work correctly for various content lengths and formatting requirements

  • Ensure that focus states and border styling provide clear visual feedback without disrupting overall layout consistency

Icon Problems

Symptoms: Clear icon doesn't display, button states don't show proper icons, or icon interactions don't work correctly

Solutions:

  • Verify that close icon is available in your icon system and renders correctly with appropriate sizing and color theming

  • Check that icon click handlers are properly configured and trigger clear functionality without interfering with textarea focus

  • Ensure that icon visibility logic works correctly based on content state and disabled status for optimal user experience

Implementation Support

  • Text Content Management - Best practices for handling large text inputs, character counting, and content validation patterns
  • Form Integration Strategies - Comprehensive guidance for textarea integration with PWC form systems and validation workflows
  • Accessibility Compliance - WCAG guidelines implementation, keyboard navigation patterns, and screen reader optimization for text input interfaces

Resources

Storybook Documentation

For comprehensive API documentation, interactive examples, and testing tools: 📖 View Complete API Documentation in Storybook →


This guide provides high-level implementation guidance. For detailed API specifications and interactive examples, visit our Storybook documentation.