TextField requires a MaterialLocalizations widget

Summary

Instances of TextField must have a MaterialLocalizations present in the widget tree. Trying to instantiate a TextField without the proper localizations results in an assertion such as the following:

No MaterialLocalizations found.
TextField widgets require MaterialLocalizations to be provided by a Localizations widget ancestor.
The material library uses Localizations to generate messages, labels, and abbreviations.
To introduce a MaterialLocalizations, either use a MaterialApp at the root of your application to
include them automatically, or add a Localization widget with a MaterialLocalizations delegate.
The specific widget that could not find a MaterialLocalizations ancestor was:
  TextField

Context

If the TextField descends from a MaterialApp, the DefaultMaterialLocalizations is already instantiated and will not require any changes to your existing code.

If the TextField doesn’t descend from MaterialApp, you can use a Localizations widget to provide your own localizations.

Migration guide

If you see an assertion error, make sure that locale information is available to the TextField, either through an ancestor MaterialApp (that automatically provides Localizations), or by creating your own Localizations widget.

Code before migration:

import 'package:flutter/material.dart';

void main() => runApp(Foo());

class Foo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MediaQuery(
      data: const MediaQueryData(),
      child: Directionality(
        textDirection: TextDirection.ltr,
        child: TextField(),
      ),
    );
  }
}

Code after migration (Providing localizations using the MaterialApp):

import 'package:flutter/material.dart';

void main() => runApp(Foo());

class Foo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: TextField(),
    );
  }
}

Code after migration (Providing localizations via the Localizations widget):

import 'package:flutter/material.dart';

void main() => runApp(Foo());

class Foo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Localizations(
      locale: const Locale('en', 'US'),
      delegates: <LocalizationsDelegate<dynamic>>[
        DefaultWidgetsLocalizations.delegate,
        DefaultMaterialLocalizations.delegate,
      ],
      child: MediaQuery(
        data: const MediaQueryData(),
        child: Directionality(
          textDirection: TextDirection.ltr,
          child: TextField(),
        ),
      ),
    );
  }
}

Timeline

This change was introduced in June 2020, in 1.20.0-1.0.pre.

References

API documentation:

Relevant PR: