Last active
November 10, 2025 16:09
-
-
Save followthemoney1/1189ddc208206598f9fb5f6ae9d06b80 to your computer and use it in GitHub Desktop.
Good Flutter User Name Validation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import 'package:flutter/material.dart'; | |
| import 'package:flutter/services.dart'; | |
| import 'package:form_builder_validators/form_builder_validators.dart'; | |
| import 'package:recase/recase.dart'; | |
| /// Custom TextInputFormatter that converts input to title case | |
| class TitleCaseTextInputFormatter extends TextInputFormatter { | |
| @override | |
| TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) { | |
| if (newValue.text.isEmpty || newValue.text.endsWith(' ')) { | |
| return newValue; | |
| } | |
| final titleCase = newValue.text.titleCase; | |
| return TextEditingValue(text: titleCase, selection: newValue.selection); | |
| } | |
| } | |
| /// A shared stateless widget for full name text field input. | |
| /// | |
| /// This widget enforces consistent validation and formatting across the app | |
| /// for full name inputs. It automatically converts input to title case and | |
| /// filters out potentially dangerous characters. | |
| class FullNameTextField extends StatelessWidget { | |
| const FullNameTextField({required this.controller, required this.onChanged, this.hintText = 'John Doe', super.key}); | |
| final TextEditingController controller; | |
| final ValueChanged<String> onChanged; | |
| final String? hintText; | |
| @override | |
| Widget build(BuildContext context) { | |
| return TextField( | |
| controller: controller, | |
| hintText: hintText ?? context.loc.fullNamePlaceholder, | |
| backgroundColor: const Color(0xFF000000), | |
| borderRadius: BorderRadius.circular(BorderRadiusConstants.normal), | |
| textStyle: context.textTheme.bodyMedium?.copyWith(color: Colors.white), | |
| validator: FormBuilderValidators.compose([ | |
| FormBuilderValidators.required(), | |
| FormBuilderValidators.minLength(4, errorText: context.loc.fullNameMinLength), | |
| ]), | |
| inputFormatters: [ | |
| // Remove any characters that are NOT valid in names | |
| // Allows: Unicode letters (\p{L}), combining marks/diacritics (\p{M}), numbers (\p{N}), | |
| // dots (.), apostrophes ('), hyphens (-), middle dot (·), glottal stop (ʔ), and spaces | |
| FilteringTextInputFormatter.deny(RegExp(r"[^\p{L}\p{M}\p{N}.'ʼʔ·\- ]+", unicode: true)), | |
| TitleCaseTextInputFormatter(), | |
| ], | |
| maxLength: 35, | |
| onChanged: onChanged, | |
| ); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment