S
Text Field

Textarea

Multi-line text input for longer content like messages, descriptions, or comments.

stable
textarea multiline text message

Interactive demo of textarea field

Share your thoughts with us

Maximum 200 characters

/**
 * Textarea Field Demo - Interactive examples of textarea fields
 */

import { Form, FormBuilder } from '@saastro/forms';

import { FormProvider } from '@/components/FormProvider';
import { TooltipProvider } from '@/components/ui/tooltip';

const config = FormBuilder.create('textarea-demo')
  .layout('manual')
  .columns(12)
  .addField('message', (f) =>
    f
      .type('textarea')
      .label('Message')
      .placeholder('Write your message here...')
      .helperText('Share your thoughts with us')
      .rows(4)
      .required('Message is required')
      .minLength(10, 'Message must be at least 10 characters')
      .columns({ default: 12 }),
  )
  .addField('bio', (f) =>
    f
      .type('textarea')
      .label('Bio')
      .placeholder('Tell us about yourself...')
      .helperText('Maximum 200 characters')
      .rows(3)
      .maxLength(200)
      .optional()
      .columns({ default: 12 }),
  )
  .addStep('main', ['message', 'bio'])
  .build();

export default function TextareaDemo() {
  const handleSubmit = (data: Record<string, unknown>) => {
    console.log('Form submitted:', data);
    alert('Form submitted! Check console for data.');
  };

  return (
    <TooltipProvider>
      <FormProvider>
        <Form config={config} onSubmit={handleSubmit} className="space-y-4" />
      </FormProvider>
    </TooltipProvider>
  );
}

Overview

The textarea field provides a multi-line text input for longer content. It supports character counting, auto-resize, and configurable rows.

Usage

Basic Textarea

import { FormBuilder } from '@saastro/forms';

const config = FormBuilder.create('feedback')
  .addField('message', (f) =>
    f
      .type('textarea')
      .label('Your Message')
      .placeholder('Write your message here...')
      .required('Message is required')
      .minLength(10, 'Message must be at least 10 characters'),
  )
  .addStep('main', ['message'])
  .build();

With Character Limit

.addField('bio', (f) =>
  f.type('textarea')
    .label('Bio')
    .placeholder('Tell us about yourself...')
    .maxLength(500)
    .helperText('Maximum 500 characters')
    .rows(4)
)

With Rows Configuration

.addField('description', (f) =>
  f.type('textarea')
    .label('Description')
    .rows(6)
    .placeholder('Detailed description...')
)

JSON Configuration

{
  "type": "textarea",
  "label": "Message",
  "placeholder": "Write your message...",
  "rows": 4,
  "maxLength": 500,
  "schema": {
    "required": true,
    "minLength": 10,
    "minLengthMessage": "Message must be at least 10 characters"
  }
}

Props

PropTypeDefaultDescription
type'textarea'-Field type (required)
labelstring-Label text
placeholderstring-Placeholder text
helperTextstring-Help text below field
rowsnumber3Number of visible rows
maxLengthnumber-Maximum character count (HTML attribute)
size'sm' | 'md' | 'lg''md'Input size variant
columnsPartial<Record<Breakpoint, number>>-Grid columns by breakpoint
disabledboolean | function | ConditionGroupfalseDisable the field
hiddenboolean | function | ConditionGroup | ResponsivefalseHide the field

Validation

Required with Minimum Length

.addField('feedback', (f) =>
  f.type('textarea')
    .label('Feedback')
    .required('Feedback is required')
    .minLength(20, 'Please provide at least 20 characters')
)

Maximum Length Validation

.addField('tweet', (f) =>
  f.type('textarea')
    .label('Tweet')
    .maxLength(280)
    .maxLengthValidation(280, 'Tweet cannot exceed 280 characters')
)

With Zod Schema

import { z } from 'zod';

.addField('essay', (f) =>
  f.type('textarea')
    .label('Essay')
    .schema(z.string()
      .min(100, 'Essay must be at least 100 characters')
      .max(5000, 'Essay cannot exceed 5000 characters')
    )
)

Styling

Custom Classes

.addField('message', (f) =>
  f.type('textarea')
    .label('Message')
    .rows(4)
    .required()
    .classNames({
      wrapper: 'bg-muted/30 p-4 rounded-lg',
      input: 'min-h-[120px] resize-none',
      label: 'text-lg font-medium',
      error: 'text-destructive text-sm',
      helper: 'text-muted-foreground text-xs',
    })
)

Responsive Layout

.addField('description', (f) =>
  f.type('textarea')
    .label('Description')
    .rows(5)
    .columns({ default: 12, md: 8 })
    .size('lg')
)

JSON Styling

{
  "type": "textarea",
  "label": "Message",
  "rows": 4,
  "wrapper_className": "bg-muted/30 p-4 rounded-lg",
  "input_className": "min-h-[120px] resize-none",
  "label_className": "text-lg font-medium",
  "columns": { "default": 12 },
  "size": "lg"
}
  • Text - Single-line text input
  • Input Group - Text input with prefix/suffix

Accessibility

  • Native <textarea> element for full accessibility
  • Proper labeling via label prop
  • Supports keyboard navigation
  • Character count announced to screen readers