flex_phone_input 1.0.1 copy "flex_phone_input: ^1.0.1" to clipboard
flex_phone_input: ^1.0.1 copied to clipboard

A searchable phone number input field with a country code picker. Supports multiple field styles, selector surfaces, validation states, and full light/dark theming.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:flex_phone_input/flex_phone_input.dart';

void main() => runApp(const DemoApp());

class DemoApp extends StatefulWidget {
  const DemoApp({super.key});

  @override
  State<DemoApp> createState() => _DemoAppState();
}

class _DemoAppState extends State<DemoApp> {
  ThemeMode _mode = ThemeMode.light;

  void _toggle() => setState(
        () => _mode = _mode == ThemeMode.dark ? ThemeMode.light : ThemeMode.dark,
      );

  @override
  Widget build(BuildContext context) {
    const Color seed = Color(0xFF1A56DB);
    return MaterialApp(
      title: 'flex_phone_input demo',
      debugShowCheckedModeBanner: false,
      themeMode: _mode,
      // Theming, way #1: register PhoneInputTheme globally for light + dark.
      theme: ThemeData(
        useMaterial3: true,
        brightness: Brightness.light,
        colorSchemeSeed: seed,
        extensions: <ThemeExtension<dynamic>>[PhoneInputTheme.light()],
      ),
      darkTheme: ThemeData(
        useMaterial3: true,
        brightness: Brightness.dark,
        colorSchemeSeed: seed,
        extensions: <ThemeExtension<dynamic>>[PhoneInputTheme.dark()],
      ),
      home: DemoPage(isDark: _mode == ThemeMode.dark, onToggleTheme: _toggle),
    );
  }
}

class DemoPage extends StatefulWidget {
  const DemoPage({super.key, required this.isDark, required this.onToggleTheme});

  final bool isDark;
  final VoidCallback onToggleTheme;

  @override
  State<DemoPage> createState() => _DemoPageState();
}

class _DemoPageState extends State<DemoPage> {
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
  PhoneNumber? _latest;

  Widget _section(String title) => Padding(
        padding: const EdgeInsets.only(top: 28, bottom: 8),
        child: Text(
          title,
          style: const TextStyle(fontSize: 13, fontWeight: FontWeight.w700, letterSpacing: 0.4),
        ),
      );

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('flex_phone_input'),
        actions: <Widget>[
          IconButton(
            tooltip: 'Toggle theme',
            icon: Icon(widget.isDark ? Icons.light_mode : Icons.dark_mode),
            onPressed: widget.onToggleTheme,
          ),
        ],
      ),
      body: SafeArea(
        child: ListView(
          padding: const EdgeInsets.fromLTRB(16, 8, 16, 40),
          children: <Widget>[
            Text(
              _latest == null ? 'Type a number below…' : 'Value: ${_latest!.completeNumber}',
              style: const TextStyle(fontWeight: FontWeight.w600),
            ),

            _section('Field styles'),
            PhoneNumberInput(
              initialCountryCode: 'IN',
              variant: PhoneFieldVariant.outlined,
              labelText: 'Outlined',
              onChanged: (PhoneNumber v) => setState(() => _latest = v),
            ),
            const SizedBox(height: 14),
            const PhoneNumberInput(
              initialCountryCode: 'US',
              variant: PhoneFieldVariant.filled,
              hintText: 'Filled',
            ),
            const SizedBox(height: 14),
            const PhoneNumberInput(
              initialCountryCode: 'GB',
              variant: PhoneFieldVariant.pill,
              hintText: 'Pill',
            ),
            const SizedBox(height: 14),
            const PhoneNumberInput(
              initialCountryCode: 'AE',
              variant: PhoneFieldVariant.underline,
              hintText: 'Underline',
            ),

            _section('Selector surfaces'),
            const PhoneNumberInput(
              initialCountryCode: 'SG',
              selectorMode: CountrySelectorMode.bottomSheet,
              hintText: 'Bottom sheet (tap the flag)',
            ),
            const SizedBox(height: 14),
            const PhoneNumberInput(
              initialCountryCode: 'AU',
              selectorMode: CountrySelectorMode.dialog,
              hintText: 'Dialog',
            ),
            const SizedBox(height: 14),
            const PhoneNumberInput(
              initialCountryCode: 'JP',
              selectorMode: CountrySelectorMode.fullScreen,
              hintText: 'Full screen',
            ),
            const SizedBox(height: 14),
            const PhoneNumberInput(
              initialCountryCode: 'DE',
              selectorMode: CountrySelectorMode.dropdown,
              hintText: 'Inline dropdown',
            ),

            _section('Country control'),
            const PhoneNumberInput(
              countries: <String>['IN', 'US', 'GB', 'AE', 'SG'],
              initialCountryCode: 'IN',
              hintText: 'Allow-list: only 5 countries',
            ),
            const SizedBox(height: 14),
            const PhoneNumberInput(
              excludeCountries: <String>['KP', 'IR', 'SY'],
              favoriteCountries: <String>['IN', 'US', 'GB'],
              hintText: 'Exclude a few + custom favourites',
            ),

            _section('Per-widget theme override'),
            PhoneNumberInput(
              initialCountryCode: 'FR',
              hintText: 'Custom purple theme',
              theme: (widget.isDark ? PhoneInputTheme.dark() : PhoneInputTheme.light())
                  .copyWith(
                focusedBorderColor: const Color(0xFF7C3AED),
                selectedTileColor: const Color(0x337C3AED),
                borderRadius: 16,
              ),
            ),

            _section('Validation (Form)'),
            Form(
              key: _formKey,
              child: PhoneNumberInput(
                initialCountryCode: 'IN',
                labelText: 'Required, min 6 digits',
                autovalidateMode: AutovalidateMode.onUserInteraction,
                validator: (PhoneNumber? value) {
                  if (value == null || value.number.length < 6) {
                    return 'Enter a valid phone number';
                  }
                  return null;
                },
              ),
            ),
            const SizedBox(height: 16),
            FilledButton(
              onPressed: () {
                final bool ok = _formKey.currentState?.validate() ?? false;
                ScaffoldMessenger.of(context).showSnackBar(
                  SnackBar(content: Text(ok ? 'Valid!' : 'Please fix the field')),
                );
              },
              child: const Text('Validate'),
            ),
          ],
        ),
      ),
    );
  }
}
0
likes
160
points
25
downloads
screenshot

Documentation

API reference

Publisher

verified publisherhindcorporation.com

Weekly Downloads

A searchable phone number input field with a country code picker. Supports multiple field styles, selector surfaces, validation states, and full light/dark theming.

Repository (GitHub)
View/report issues

Topics

#phone #country #input #picker #form

License

MIT (license)

Dependencies

flutter

More

Packages that depend on flex_phone_input