Show clipboard suggestion where users mostly copy-paste
Some text fields are mostly copy-pasted: a promo code, a referral code, a card number, a tracking number. When such a text field gets focus, read the clipboard and show copied value so one tap fills it in:
Some bank apps show it above the keyboard instead. Also fine, but most Android keyboards already show a paste suggestion there, iOS doesn't. Pick the spot that fits the case.
Put the suggestion widget right under the text field and give both the same FocusNode. That's how the suggestion knows the text field was tapped, only then it reads the clipboard:
TextField( controller: controller, focusNode: focusNode,),// Shows the clipboard as a chip under the text fieldClipboardSuggestion( focusNode: focusNode, onTap: (String value) { controller.text = value; applyPromoCode(value); },),
The widget, design the chip to your taste:
import 'package:flutter/material.dart';import 'package:flutter/services.dart';class ClipboardSuggestion extends StatefulWidget { final FocusNode focusNode; final ValueChanged<String> onTap; const ClipboardSuggestion({ super.key, required this.focusNode, required this.onTap, }); @override State<ClipboardSuggestion> createState() => _ClipboardSuggestionState();}class _ClipboardSuggestionState extends State<ClipboardSuggestion> { String? _suggestion; @override void initState() { super.initState(); widget.focusNode.addListener(_onFocusChanged); } @override void dispose() { widget.focusNode.removeListener(_onFocusChanged); super.dispose(); } Future<void> _onFocusChanged() async { if (!widget.focusNode.hasFocus) { _set(null); return; } final ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain); final String value = data?.text?.trim() ?? ''; // Only short, single-word text, so a copied sentence doesn't show up. final bool isCodeLike = value.isNotEmpty && value.length <= 32 && !value.contains(RegExp(r'\s')); _set(isCodeLike ? value : null); } void _set(String? value) { if (!mounted || _suggestion == value) return; setState(() => _suggestion = value); } @override Widget build(BuildContext context) { final String? suggestion = _suggestion; if (suggestion == null) return const SizedBox.shrink(); return GestureDetector( onTap: () { widget.onTap(suggestion); _set(null); }, behavior: .opaque, child: Chip( avatar: const Icon( Icons.content_paste_rounded, size: 14, ), label: Text( suggestion, ), ), ); }}