Input

In ProgressDark modeRTL

A text input field with labels, icons, and validation.


7:21
Email
you@example.com
Email
you@example.com
Password
••••••••
Search
Search...
Password
Too short
Password must be at least 8 characters
Disabled field
Cannot edit this field

Installation

Copy the component into your project using the CLI:

$ronakcn add input

Usage

Import and use the component in your Flutter widget tree:

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

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

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

Variants

Input ships with the following variants:

default

A plain text input field.

7:21
Email
you@example.com

with-label

Input with a floating label above.

7:21
Email
you@example.com
Password
••••••••

with-icon

Input with a prefix or suffix icon.

7:21
Search
Search...

with-error

Input showing an error state with message.

7:21
Password
Too short
Password must be at least 8 characters

disabled

A non-interactive disabled input.

7:21
Disabled field
Cannot edit this field

Props

PropTypeDefaultDescription
valueString''Current value of the input.
onChanged*ValueChanged<String>Called when the value changes.
placeholderString?nullPlaceholder text shown when empty.
labelString?nullLabel displayed above the input.
prefixIconWidget?nullIcon shown at the start of the input.
suffixIconWidget?nullIcon shown at the end of the input.
errorTextString?nullError message shown below the input.
enabledbooltrueWhether the input is interactive.
obscureTextboolfalseHides text for password fields.
keyboardTypeTextInputTypeTextInputType.textKeyboard type for the input.

Source files

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

class RcnInput extends StatelessWidget {
  const RcnInput({
    super.key,
    this.value = '',
    required this.onChanged,
    this.placeholder,
    this.label,
    this.prefixIcon,
    this.suffixIcon,
    this.errorText,
    this.enabled = true,
    this.obscureText = false,
    this.keyboardType = TextInputType.text,
    this.controller,
  });

  final String value;
  final ValueChanged<String> onChanged;
  final String? placeholder;
  final String? label;
  final Widget? prefixIcon;
  final Widget? suffixIcon;
  final String? errorText;
  final bool enabled;
  final bool obscureText;
  final TextInputType keyboardType;
  final TextEditingController? controller;

  @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(
          controller: controller,
          onChanged: onChanged,
          enabled: enabled,
          obscureText: obscureText,
          keyboardType: keyboardType,
          style: TextStyle(fontSize: 14, color: colors.onSurface),
          decoration: InputDecoration(
            hintText: placeholder,
            hintStyle: TextStyle(color: colors.onSurface.withOpacity(0.4)),
            prefixIcon: prefixIcon,
            suffixIcon: suffixIcon,
            errorText: errorText,
            contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
            enabledBorder: OutlineInputBorder(
              borderRadius: BorderRadius.circular(8),
              borderSide: BorderSide(color: colors.outline),
            ),
            focusedBorder: OutlineInputBorder(
              borderRadius: BorderRadius.circular(8),
              borderSide: BorderSide(color: colors.primary, width: 2),
            ),
            disabledBorder: OutlineInputBorder(
              borderRadius: BorderRadius.circular(8),
              borderSide: BorderSide(color: colors.outline.withOpacity(0.4)),
            ),
            errorBorder: OutlineInputBorder(
              borderRadius: BorderRadius.circular(8),
              borderSide: const BorderSide(color: Color(0xFFE11D48)),
            ),
          ),
        ),
      ],
    );
  }
}
Version 0.1.0 · input category