phone_flag_input 0.0.1 copy "phone_flag_input: ^0.0.1" to clipboard
phone_flag_input: ^0.0.1 copied to clipboard

A beautiful and customizable phone number input widget with country flag selector and international phone number formatting for Flutter.

example/lib/main.dart

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

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Phone Flag Input Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.deepPurple,
          brightness: Brightness.light,
        ),
        useMaterial3: true,
      ),
      darkTheme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.deepPurple,
          brightness: Brightness.dark,
        ),
        useMaterial3: true,
      ),
      home: const PhoneInputDemo(),
    );
  }
}

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

  @override
  State<PhoneInputDemo> createState() => _PhoneInputDemoState();
}

class _PhoneInputDemoState extends State<PhoneInputDemo> {
  PhoneNumber? _phoneNumber;
  PhoneNumber? _customPhone;

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);

    return Scaffold(
      appBar: AppBar(
        title: const Text('Phone Flag Input'),
        backgroundColor: theme.colorScheme.inversePrimary,
        centerTitle: true,
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(24),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // Basic Example
            _buildSection(
              title: 'Basic Usage',
              description: 'Simple phone input with default settings',
              child: PhoneInput(
                initialCountry: Country.unitedStates,
                onChanged: (phone) {
                  setState(() {
                    _phoneNumber = phone;
                  });
                },
              ),
            ),
            if (_phoneNumber != null) ...[
              const SizedBox(height: 16),
              _buildInfoCard('Entered Phone Number', [
                'Country: ${_phoneNumber!.country.name}',
                'Dial Code: ${_phoneNumber!.country.dialCode}',
                'Number: ${_phoneNumber!.number}',
                'Full Number: ${_phoneNumber!.fullNumber}',
              ]),
            ],
            const SizedBox(height: 32),

            // With Initial Value
            _buildSection(
              title: 'With Initial Value',
              description: 'Pre-filled phone number',
              child: PhoneInput(
                initialValue: PhoneNumber(Country.india, '9876543210'),
                onChanged: (phone) => debugPrint('Phone: ${phone.fullNumber}'),
              ),
            ),
            const SizedBox(height: 32),

            // Custom Theme
            _buildSection(
              title: 'Custom Theme',
              description: 'Customized appearance with larger flags',
              child: PhoneInput(
                initialCountry: Country.unitedKingdom,
                theme: const PhoneInputTheme(
                  flagHeight: 24,
                  flagWidth: 36,
                  maxWidth: 250,
                  borderRadius: BorderRadius.all(Radius.circular(16)),
                ),
                phoneHint: 'Enter phone number',
                onChanged: (phone) {
                  setState(() {
                    _customPhone = phone;
                  });
                },
              ),
            ),
            if (_customPhone != null && _customPhone!.number.isNotEmpty) ...[
              const SizedBox(height: 16),
              Container(
                padding: const EdgeInsets.all(16),
                decoration: BoxDecoration(
                  color: theme.colorScheme.primaryContainer,
                  borderRadius: BorderRadius.circular(12),
                ),
                child: Row(
                  children: [
                    Icon(Icons.check_circle, color: theme.colorScheme.primary),
                    const SizedBox(width: 12),
                    Expanded(
                      child: Text(
                        'Valid phone: ${_customPhone!.fullNumber}',
                        style: TextStyle(
                          color: theme.colorScheme.onPrimaryContainer,
                          fontWeight: FontWeight.w500,
                        ),
                      ),
                    ),
                  ],
                ),
              ),
            ],
            const SizedBox(height: 32),

            // Limited Countries
            _buildSection(
              title: 'Limited Countries',
              description: 'Only show specific countries in the picker',
              child: PhoneInput(
                countries: const [
                  Country.unitedStates,
                  Country.canada,
                  Country.unitedKingdom,
                  Country.australia,
                  Country.india,
                  Country.germany,
                  Country.france,
                  Country.japan,
                ],
                searchHint: 'Search from available countries...',
                onChanged: (phone) => debugPrint('Phone: ${phone.fullNumber}'),
              ),
            ),
            const SizedBox(height: 32),

            // Disabled State
            _buildSection(
              title: 'Disabled State',
              description: 'Read-only phone input',
              child: PhoneInput(
                initialValue: PhoneNumber(Country.germany, '1234567890'),
                enabled: false,
                onChanged: (phone) {},
              ),
            ),
            const SizedBox(height: 48),

            // All Countries Reference
            Text(
              'Available Countries',
              style: theme.textTheme.titleLarge?.copyWith(
                fontWeight: FontWeight.bold,
              ),
            ),
            const SizedBox(height: 8),
            Text(
              'The package includes ${Country.values.length} countries. Here are a few examples:',
              style: theme.textTheme.bodyMedium?.copyWith(
                color: theme.colorScheme.onSurface.withValues(alpha: 0.7),
              ),
            ),
            const SizedBox(height: 16),
            Wrap(
              spacing: 8,
              runSpacing: 8,
              children:
                  Country.values.take(20).map((country) {
                    return Chip(
                      avatar: ClipRRect(
                        borderRadius: BorderRadius.circular(4),
                        child: Image.network(
                          'https://flagcdn.com/w40/${country.code.toLowerCase()}.png',
                          width: 24,
                          height: 16,
                          fit: BoxFit.cover,
                          errorBuilder:
                              (_, __, ___) => const SizedBox(width: 24),
                        ),
                      ),
                      label: Text(
                        '${country.name} (${country.dialCode})',
                        style: const TextStyle(fontSize: 12),
                      ),
                    );
                  }).toList(),
            ),
            const SizedBox(height: 24),
          ],
        ),
      ),
    );
  }

  Widget _buildSection({
    required String title,
    required String description,
    required Widget child,
  }) {
    final theme = Theme.of(context);

    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(
          title,
          style: theme.textTheme.titleMedium?.copyWith(
            fontWeight: FontWeight.bold,
          ),
        ),
        const SizedBox(height: 4),
        Text(
          description,
          style: theme.textTheme.bodySmall?.copyWith(
            color: theme.colorScheme.onSurface.withValues(alpha: 0.6),
          ),
        ),
        const SizedBox(height: 16),
        child,
      ],
    );
  }

  Widget _buildInfoCard(String title, List<String> items) {
    final theme = Theme.of(context);

    return Container(
      padding: const EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: theme.colorScheme.surfaceContainerHighest,
        borderRadius: BorderRadius.circular(12),
        border: Border.all(
          color: theme.colorScheme.outline.withValues(alpha: 0.2),
        ),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            title,
            style: theme.textTheme.labelLarge?.copyWith(
              fontWeight: FontWeight.bold,
              color: theme.colorScheme.primary,
            ),
          ),
          const SizedBox(height: 12),
          ...items.map(
            (item) => Padding(
              padding: const EdgeInsets.only(bottom: 4),
              child: Text(item, style: theme.textTheme.bodyMedium),
            ),
          ),
        ],
      ),
    );
  }
}
1
likes
150
points
66
downloads

Publisher

verified publisherdivyanshdev.tech

Weekly Downloads

A beautiful and customizable phone number input widget with country flag selector and international phone number formatting for Flutter.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

country_flags, flutter

More

Packages that depend on phone_flag_input