Dart Tutorial

Flutter Lesson 31 of 83 3 min read

Dropdowns, Date Pickers and Time Pickers in Flutter

Let users choose from a list or pick a date and time in Flutter with DropdownMenu, showDatePicker, showTimePicker and date ranges.

On this page

When there are too many options to show at once, or the value is a date, use a menu or a picker.

import 'package:flutter/material.dart';

void main() => runApp(const MaterialApp(home: CityPage()));

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

  @override
  State<CityPage> createState() => _CityPageState();
}

class _CityPageState extends State<CityPage> {
  static const _cities = ['Kathmandu', 'Pokhara', 'Lalitpur', 'Biratnagar', 'Butwal'];
  String? _city;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            DropdownMenu<String>(
              label: const Text('City'),
              width: 260,
              enableFilter: true, // type to narrow the list
              dropdownMenuEntries: [
                for (final c in _cities) DropdownMenuEntry(value: c, label: c),
              ],
              onSelected: (value) => setState(() => _city = value),
            ),
            const SizedBox(height: 16),
            Text(_city == null ? 'No city chosen' : 'You chose $_city'),
          ],
        ),
      ),
    );
  }
}

DropdownMenu is the Material 3 control. It supports typing to filter, which matters for long lists. Set initialSelection to preselect a value.

The older DropdownButton and DropdownButtonFormField are still common, and the form version takes part in Form validation.

Date picker #

showDatePicker opens a dialog and returns the chosen date, or null if the user cancels.

DateTime? _birthday;

Future<void> _pickDate() async {
  final now = DateTime.now();
  final picked = await showDatePicker(
    context: context,
    initialDate: _birthday ?? DateTime(now.year - 20),
    firstDate: DateTime(1920),
    lastDate: now,
  );
  if (picked == null) return; // cancelled
  setState(() => _birthday = picked);
}

firstDate and lastDate are required and set the range that can be chosen. Use them to enforce your rules, such as no birthdays in the future, or no bookings in the past.

Time picker #

TimeOfDay? _time;

Future<void> _pickTime() async {
  final picked = await showTimePicker(
    context: context,
    initialTime: _time ?? TimeOfDay.now(),
  );
  if (picked == null) return;
  setState(() => _time = picked);
}

// Display it in the user's 12- or 24-hour format:
Text(_time?.format(context) ?? 'Choose a time')

Date and time together #

Future<DateTime?> pickDateTime(BuildContext context) async {
  final date = await showDatePicker(
    context: context,
    firstDate: DateTime.now(),
    lastDate: DateTime.now().add(const Duration(days: 365)),
  );
  if (date == null || !context.mounted) return null;

  final time = await showTimePicker(context: context, initialTime: TimeOfDay.now());
  if (time == null) return null;

  return DateTime(date.year, date.month, date.day, time.hour, time.minute);
}

Date range #

final range = await showDateRangePicker(
  context: context,
  firstDate: DateTime.now(),
  lastDate: DateTime.now().add(const Duration(days: 365)),
);
if (range != null) {
  debugPrint('${range.start} to ${range.end}, ${range.duration.inDays} nights');
}

A field that opens a picker #

Users expect a date to look like a form field. Use a read-only text field that opens the picker when tapped.

final _dateController = TextEditingController();

TextFormField(
  controller: _dateController,
  readOnly: true,
  decoration: const InputDecoration(
    labelText: 'Date of birth',
    suffixIcon: Icon(Icons.calendar_today),
    border: OutlineInputBorder(),
  ),
  validator: (v) => (v == null || v.isEmpty) ? 'Choose a date' : null,
  onTap: () async {
    final picked = await showDatePicker(
      context: context,
      firstDate: DateTime(1920),
      lastDate: DateTime.now(),
    );
    if (picked != null) {
      _dateController.text = '${picked.day}/${picked.month}/${picked.year}';
    }
  },
)

Formatting dates for display #

DateTime.toString() is not user friendly. Use the intl package.

import 'package:intl/intl.dart';

DateFormat.yMMMd().format(date)          // Oct 10, 2026
DateFormat('EEEE, d MMMM').format(date)  // Saturday, 10 October
DateFormat.jm().format(date)             // 6:45 PM

Other ways to choose #

NeedWidget
A few options in a menu from a buttonPopupMenuButton, MenuAnchor
Search with suggestionsSearchAnchor, Autocomplete
iOS-style wheelCupertinoPicker, CupertinoDatePicker
Pick from a long list with searchA full-screen page with a ListView and a search field

Try it yourself #

Build an appointment booking form: a dropdown for the service, a date field limited to the next 30 days, a time field, and a summary line such as “Haircut on Saturday, 10 October at 3:30 PM”.

Practise in the playground Updated by Santosh Adhikari