Smart Chip Field

A production-ready Flutter package that provides a Gmail-style chip input field. Perfect for email recipients, tags, and multi-select inputs with proper backspace handling.

Pub Version License

โœจ Features

  • Gmail-Style Backspace Behavior: First press highlights, second press deletes
  • Smart Chip Creation: Auto-converts text to chips on Space, Enter, Comma, or Semicolon
  • Custom Validation: Built-in email validator with extensible validation system
  • Full Customization: Custom chip builders, separators, and styling
  • Keyboard Support: Proper handling of physical keyboard events
  • No WidgetSpan Issues: Uses a dual-layer architecture that avoids Flutter's text selection limitations

๐ŸŽฏ The Problem This Solves

Existing chip input packages (like chip_inputs_textfield) struggle with backspace behavior because they use WidgetSpan, which Flutter's text selection system treats as a single character. This causes chips to convert back to text instead of being deleted.

Smart Chip Field solves this by using a dual-layer architecture where chips are real widgets alongside the text field, not embedded within it.

๐Ÿ“ฆ Installation

Add this to your pubspec.yaml:

dependencies:
  smart_chip_field: ^1.0.0

Then run:

flutter pub get

๐Ÿš€ Quick Start

import 'package:smart_chip_field/smart_chip_field.dart';

SmartChipField(
  hintText: 'Add recipients',
  validator: ChipValidators.email,
  separators: const [',', ' ', ';'],
  onChanged: (chips) {
    print('Current chips: $chips');
  },
)

๐Ÿ“– Usage Examples

Basic Email Input

SmartChipField(
  hintText: 'To: Add recipients',
  validator: ChipValidators.email,
  onChanged: (emails) {
    setState(() {
      _recipients = emails;
    });
  },
)

Custom Validator

SmartChipField(
  hintText: 'Add tags',
  validator: (value) {
    if (value.length < 3) return 'Tag must be at least 3 characters';
    if (value.contains(' ')) return 'Tags cannot contain spaces';
    return null; // Valid
  },
)

Custom Chip Design

SmartChipField(
  chipBuilder: (text, onDelete) {
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
      decoration: BoxDecoration(
        color: Colors.purple.shade100,
        borderRadius: BorderRadius.circular(20),
      ),
      child: Row(
        mainAxisSize: MainAxisSize.min,
        children: [
          Icon(Icons.tag, size: 16),
          const SizedBox(width: 4),
          Text(text),
          const SizedBox(width: 4),
          GestureDetector(
            onTap: onDelete,
            child: Icon(Icons.close, size: 16),
          ),
        ],
      ),
    );
  },
)

Pre-filled Chips

SmartChipField(
  initialChips: const [
    'john@example.com',
    'jane@example.com',
  ],
  validator: ChipValidators.email,
)

๐ŸŽจ Customization Options

Parameter Type Description
initialChips List<String> Pre-populated chips
validator String? Function(String)? Validation function (return null if valid)
onChanged void Function(List<String>)? Called when chips list changes
separators List<String> Characters that trigger chip creation (default: [',', ' '])
hintText String Placeholder text when empty
chipBuilder Widget Function(String, VoidCallback)? Custom chip widget builder

๐Ÿงช Built-in Validators

Email Validator

SmartChipField(
  validator: ChipValidators.email,
)

No Spaces Validator

SmartChipField(
  validator: ChipValidators.noSpaces,
)

Combine Multiple Validators

String? multiValidator(String value) {
  final emailError = ChipValidators.email(value);
  if (emailError != null) return emailError;

  if (value.contains('test')) {
    return 'Test emails not allowed';
  }

  return null;
}

โŒจ๏ธ Keyboard Behavior

  • Space / Enter / Comma: Creates a chip from current text
  • Backspace (first press): Highlights the last chip
  • Backspace (second press): Deletes the highlighted chip
  • Click chip: Deletes the chip immediately
  • Type while chip highlighted: Unhighlights and continues typing

๐Ÿ—๏ธ Architecture

Unlike traditional approaches that embed chips in text using WidgetSpan, Smart Chip Field uses:

  1. Chip Layer: Real widgets in a Wrap layout
  2. Input Layer: Standard TextField for text entry
  3. Event Interceptor: Focus.onKeyEvent to handle backspace before TextField processes it

This architecture completely avoids Flutter's text selection limitations with WidgetSpan.

๐Ÿ› Common Issues

Issue: Chips not creating on space

Solution: Make sure separators includes ' ' (space character)

Issue: Validation not working

Solution: Your validator must return null for valid input, and a String error message for invalid input

Issue: Custom chip builder not showing

Solution: Ensure your chipBuilder returns a complete widget and calls the onDelete callback

๐Ÿ“„ License

MIT License - see LICENSE file for details

๐Ÿค Contributing

Contributions are welcome! Please open an issue or submit a pull request.

๐Ÿ“ง Support

If you find this package helpful, please give it a โญ on GitHub and a ๐Ÿ‘ on pub.dev!

For bugs or feature requests, please open an issue.

Libraries

smart_chip_field