Textarea

In ProgressDark modeRTL

A multi-line text input for longer content.


7:21
๐Ÿ“ฑ
TextareaPreview coming soon

Installation

Copy the component into your project using the CLI:

$ronakcn add textarea

Usage

Import and use the component in your Flutter widget tree:

lib/pages/example.dart
import 'package:flutter/material.dart';
import '../components/textarea/textarea.dart';

class ExamplePage extends StatelessWidget {
  const ExamplePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('RcnTextarea Example')),
      body: Center(
        child: RcnTextarea(
          // Configure props here
        ),
      ),
    );
  }
}

Variants

Textarea ships with the following variants:

default

A plain multi-line input.

7:21
๐Ÿ“ฑ
default variantPreview coming soon

with-label

Textarea with a label above.

7:21
๐Ÿ“ฑ
with-label variantPreview coming soon

with-character-count

Shows remaining character count.

7:21
๐Ÿ“ฑ
with-character-count variantPreview coming soon

disabled

A non-interactive disabled textarea.

7:21
๐Ÿ“ฑ
disabled variantPreview coming soon

Props

PropTypeDefaultDescription
valueString''Current text content.
onChanged*ValueChanged<String>โ€”Called when text changes.
placeholderString?nullPlaceholder text.
labelString?nullLabel above the textarea.
maxLinesint4Maximum number of visible lines.
maxLengthint?nullMaximum character count.
showCounterboolfalseShows remaining character count.

Source files

lib/components/ui/textarea.dart
import 'package:flutter/material.dart';

class RcnTextarea extends StatelessWidget {
  const RcnTextarea({
    super.key,
    this.value = '',
    required this.onChanged,
    this.placeholder,
    this.label,
    this.maxLines = 4,
    this.maxLength,
    this.showCounter = false,
    this.enabled = true,
  });

  final String value;
  final ValueChanged<String> onChanged;
  final String? placeholder;
  final String? label;
  final int maxLines;
  final int? maxLength;
  final bool showCounter;
  final bool enabled;

  @override
  Widget build(BuildContext context) {
    final colors = Theme.of(context).colorScheme;
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        if (label != null) ...[
          Text(label!, style: TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: colors.onSurface)),
          const SizedBox(height: 6),
        ],
        TextField(
          onChanged: onChanged,
          enabled: enabled,
          maxLines: maxLines,
          maxLength: showCounter ? maxLength : null,
          style: TextStyle(fontSize: 14, color: colors.onSurface),
          decoration: InputDecoration(
            hintText: placeholder,
            hintStyle: TextStyle(color: colors.onSurface.withOpacity(0.4)),
            contentPadding: const EdgeInsets.all(12),
            enabledBorder: OutlineInputBorder(
              borderRadius: BorderRadius.circular(8),
              borderSide: BorderSide(color: colors.outline),
            ),
            focusedBorder: OutlineInputBorder(
              borderRadius: BorderRadius.circular(8),
              borderSide: BorderSide(color: colors.primary, width: 2),
            ),
          ),
        ),
      ],
    );
  }
}
Version 0.1.0 ยท input category