
A Flutter widget for entering IPv4 addresses with 4 segmented fields, auto-advance, paste support, form validation, and full visual customization.
Features
- 4 segmented fields separated by
. dots
- Auto-advance — focus moves to the next field automatically when 3 digits are entered
- Backspace navigation — pressing Backspace in an empty field moves focus to the previous field
- Auto paste — paste a full IP (e.g.
192.168.0.1) into the first field and it distributes across all fields automatically
onCompleted callback — fires only when all 4 octets are filled
IpAddressInputController — programmatic control with setValue, clear, and value getter
IpAddressFormField — drop-in replacement compatible with Flutter's Form widget and validator
- Full visual customization via
IpAddressInputDecoration (border radius, colors, widths)
- Custom separator — replace the dot with any widget via
separatorWidget
- Accessibility —
semanticsLabel support for screen readers
Getting started
flutter pub add ip_address_input
Usage
Basic
import 'package:ip_address_input/ip_address_input.dart';
IpAddressInput(
label: 'IP Address',
onChanged: (value) => print(value), // e.g. '192.168.'
onCompleted: (value) => print(value), // e.g. '192.168.0.1'
)
final controller = IpAddressInputController();
// In your widget tree:
IpAddressInput(controller: controller)
// Control it from anywhere:
controller.setValue('10.0.0.1');
controller.clear();
print(controller.value); // '10.0.0.1'
// Always dispose:
controller.dispose();
Pre-filling with an initial value
IpAddressInput(
initialValue: '192.168.1.1',
)
IpAddressInput(
separatorWidget: const Icon(Icons.fiber_manual_record, size: 6),
)
final _formKey = GlobalKey<FormState>();
Form(
key: _formKey,
child: Column(
children: [
IpAddressFormField(
label: 'Router IP',
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: (value) {
if (value == null || value.replaceAll('.', '').isEmpty) {
return 'IP address is required.';
}
final parts = value.split('.');
if (parts.length != 4 || parts.any((p) => p.isEmpty)) {
return 'Incomplete IP address.';
}
for (final p in parts) {
final n = int.tryParse(p);
if (n == null || n < 0 || n > 255) {
return 'Invalid octet: $p (must be 0–255).';
}
}
return null;
},
),
ElevatedButton(
onPressed: () => _formKey.currentState?.validate(),
child: const Text('Validate'),
),
],
),
)
Disabled state
IpAddressInput(
initialValue: '8.8.8.8',
enabled: false,
)
API Reference
| Parameter |
Type |
Default |
Description |
controller |
IpAddressInputController? |
null |
Programmatic controller |
initialValue |
String? |
null |
Pre-fills all fields. Format: 'x.x.x.x' |
onChanged |
ValueChanged<String>? |
null |
Called on every keystroke |
onCompleted |
ValueChanged<String>? |
null |
Called only when all 4 fields are filled |
label |
String? |
null |
Optional label above the widget |
enabled |
bool |
true |
Enables/disables all fields |
decoration |
IpAddressInputDecoration |
IpAddressInputDecoration() |
Visual customization |
textStyle |
TextStyle? |
null |
Text style for the input fields |
separatorStyle |
TextStyle? |
null |
Style for the . separator. Ignored if separatorWidget is set |
separatorWidget |
Widget? |
null |
Custom widget to replace the dot separator |
semanticsLabel |
String? |
null |
Accessibility label |
autofillHints |
Iterable<String>? |
null |
Autofill hints |
hasError |
bool |
false |
Forces error border |
Accepts all the same parameters as IpAddressInput, plus the standard FormField parameters:
| Parameter |
Type |
Description |
validator |
FormFieldValidator<String>? |
Validation function |
autovalidateMode |
AutovalidateMode? |
When to auto-validate |
onSaved |
FormFieldSetter<String>? |
Called when the form is saved |
| Parameter |
Type |
Default |
Description |
borderRadius |
BorderRadius |
BorderRadius.all(Radius.circular(8)) |
Border radius |
focusedBorderColor |
Color? |
Theme primary color |
Border color when focused |
unfocusedBorderColor |
Color? |
Theme outline color |
Border color when unfocused |
errorBorderColor |
Color? |
Theme error color |
Border color on error |
focusedBorderWidth |
double |
2.0 |
Border width when focused |
unfocusedBorderWidth |
double |
1.0 |
Border width when unfocused |
| Member |
Description |
value |
Returns the current IP string (e.g. '192.168.0.1') |
setValue(String) |
Sets the full IP value |
clear() |
Clears all 4 fields |
dispose() |
Releases resources. Call in your widget's dispose() |