VisorVisor
FlutterWidgets

VisorChipSearchInput

A search input that holds selected items as inline chip pills, with a generic type parameter for arbitrary item shapes.

VisorChipSearchInput<T> combines a text query field with inline chip pills representing the user's current selection. It is the Flutter counterpart of the React search-input + tag-input combined pattern. The generic T parameter lets consumers supply any item shape; labelBuilder extracts the display string for each chip.

Preview

When to Use

  • Multi-select search surfaces (filter pickers, recipient pickers, tag entry)
  • Any UI where the user builds a query by adding and removing labelled tokens
  • Search bars that need to show active filter chips inline with the input

When Not to Use

  • Simple single-value search (use a plain TextField or VisorTextInput)
  • Static chip groups where no typing is involved (use VisorChip)
  • Forms that need full validation support (use VisorTextInput)

Installation

npx visor add chip-search-input --target flutter

Or copy components/flutter/visor_chip_search_input/visor_chip_search_input.dart into your project.

Basic Usage

import 'package:ui/ui.dart';

class TagItem {
  TagItem(this.id, this.label);
  final String id;
  final String label;
}

VisorChipSearchInput<TagItem>(
  selectedItems: _selected,
  labelBuilder: (item) => item.label,
  hintText: 'Add tags…',
  onQueryChanged: _runSearch,
  onItemRemoved: (item) => setState(() => _selected.remove(item)),
)

API Reference

PropertyTypeDefaultDescription
selectedItemsList<T>requiredItems currently selected, rendered as inline chips
labelBuilderString Function(T)requiredReturns the display label for a given item
hintTextStringrequiredPlaceholder shown when the field is empty
onQueryChangedValueChanged<String>requiredFires on every query keystroke
onItemRemovedValueChanged<T>requiredFires when the user removes a chip
controllerTextEditingController?nullOptional external text controller
focusNodeFocusNode?nullOptional external focus node
onFocusChangedValueChanged<bool>?nullFires when focus enters or leaves the field
onSubmittedValueChanged<String>?nullFires on keyboard submit
autofocusboolfalseRequest focus on first build
enabledbooltrueWhen false, renders at reduced opacity and ignores input

Accessibility

  • Backspace on an empty field removes the last chip (Gmail / Slack UX).
  • Each chip's remove button is labelled 'Remove <label>' and meets the 48 dp tap target.
  • Animations honour MediaQuery.disableAnimations β€” chip add/remove collapses to instant snaps when reduce-motion is requested.
  • Field uses EdgeInsetsDirectional for RTL layout.

Source

  • components/flutter/visor_chip_search_input/visor_chip_search_input.dart
  • Quality contract audit row: docs/flutter-widget-quality-contract.md (Rec8)