Migrating a Flutter app to Material 3
Tags: flutter, dart, mobile, devops
Published: 2022-12-16 08:33:53

> This article is written by **Taha Tesser** and originally posted to [Codemagic blog](https://blog.codemagic.io/migrating-a-flutter-app-to-material-3/?utm_source=devto&utm_medium=referral&utm_campaign=flutter_distribution&utm_content=material3). 

At Google I/O 2021, Google announced the next evolution of Material Design, Material You, along with Android 12. The Material Design system's biggest overhaul yet brought redesigned components, new colors, a wide range of shapes, simplified typography, new elevation, better accessibility, and many other tweaks. With this update, Flutter apps can have a consistent design across multiple platforms. Material Design 3 (the technical name for Material You) is sometimes referred to as Material 3 or simply M3 for the sake of brevity, similarly to how Material 2 is referred to as M2.

In this article, we will discuss everything that you, as a Flutter developer, should know about migrating your Flutter app to Material 3.

How to enable Material 3 in Flutter
-----------------------------------

Since the announcement of Material 3, Flutter has received a bunch of updates to support it, including support for new typography, shapes, elevation, updated widgets, and new M3 widgets. Most of the M3 components are available in Flutter. You can track the few remaining widgets that are yet to receive Material 3 support and the progress of the Material 3 implementations in Flutter for them in the [Bring Material 3 to Flutter](https://github.com/flutter/flutter/issues/91605) issue.

Currently, Material 3 changes are only available when opting in, so you'll need to use the `useMaterial3` flag on `ThemeData` to enable Material 3 support. (This might change in the future, so be sure to check out the Flutter website for updated documentation. We'll also update this article soon after the change takes place.)

To use Material 3 in Flutter instead of Material 2, specify the following:

```
theme: ThemeData(
  useMaterial3: true,
),

```

What's new in Material Design 3 for Flutter?
--------------------------------------------

Material 3 updates brought revamped typography, an improved `ColorScheme` (including the ability to generate a full `ColorScheme` from a given seed color), updated elevation, a beautiful Android 12 overscroll stretch effect, and a new ink ripple. A bunch of Material widgets, such as `AppBar`, `FloatingActionButton` (FAB), `ElevatedButton`, `OutlinedButton`, `IconButton`, and `Card`, have been updated to support Material 3 design. There are also new Material 3 widgets, such as `NavigationBar`, `NavigationDrawer`, and`SegmentedButton`, some new M3-style buttons, such as `FilledButton` and `FilledButton.tonal`, and a whole lot more.

If you simply migrate the Flutter starter app to Material 3, you'll already notice some changes: The `AppBar` has no elevation or background color, and the `FAB` has a rounded rectangular shape instead of the more familiar circular shape.

For a complete overview of M3 in Flutter, check out the official [Material 3 Demo](https://github.com/flutter/samples/tree/main/material_3_demo).

In the following sections, I'll explain some of the key changes and tweaks you might want to make in your app to support Material 3.

The key changes in Material 3 are:

-   Dynamic color
-   Typography
-   Shapes
-   Elevation

Let's go through each of them in detail.

### Dynamic color

Let's start with Dynamic color, which enables you to apply consistent colors across your app. It contains some key colors and neutral colors related to separate tonal palettes. Colors from these tonal palettes are applied across the UI. Use the [Material Theme Builder web app](https://m3.material.io/theme-builder#/dynamic) or the [Figma plugin](https://www.figma.com/community/plugin/1034969338659738588/Material-Theme-Builder) to visualize the dynamic color for your app and create a custom color scheme.

Flutter uses a low-level [`material_color_utilities`](https://pub.dev/packages/material_color_utilities) package that contains algorithms to create a Material Design 3 color system. You can create color schemes for your apps using [`dynamic_color`](https://pub.dev/packages/dynamic_color) based on a platform's implementation of dynamic color.

The easiest way to create an M3 `ColorScheme` is by providing a `seedColor` color in the app's theme.

For instance, add `colorSchemeSeed: Colors.green` to the starter app. Notice that the `FAB` is now using a lighter green color instead of the light purple from the default color scheme.

> Adding `colorSchemeSeed` when `primarySwatch` is present will throw `assertion` : `'package:flutter/src/material/theme_data.dart': Failed assertion: line 477 pos 12: 'colorSchemeSeed == null || primarySwatch == null': is not true.`

To fix this, remove `primarySwatch: Colors.blue,` from the starter app's theme.

```
	///...
	primarySwatch: Colors.blue,
  useMaterial3: true,
  colorSchemeSeed: Colors.green,
),

```

![](https://blog.codemagic.io/uploads/2022/12/color_scheme_seed.png#center)

Here, I've created an example that shows all the colors from the M3 `ColorScheme`. On the left, we have the default `ColorScheme`, which is available when setting the `useMaterial` flag to true. And on the right, we're using the custom `ColorScheme`, generated using the `colorSchemeSeed` parameter, which takes a seed color or key color to generate a full Material 3 `ColorScheme`.

| Default M3 `ColorScheme` | Custom M3 `ColorScheme` |
| --- | --- |
| ![](https://blog.codemagic.io/uploads/2022/12/default_color_scheme.png#center) | ![](https://blog.codemagic.io/uploads/2022/12/custom_color_scheme.png#center) |

You can take this to the next level using both [flex_seed_scheme](https://pub.dev/packages/flex_seed_scheme), which allows you to create a more flexible version of Flutter's `ColorScheme.fromSeed`, and [flex_color_scheme](https://pub.dev/packages/flex_color_scheme), which ensures UI components get themed completely by the color schemes and custom colors you provide.

### Typography

Material 3 simplified the typography naming by splitting the typescales into five key groups:

-   Display
-   Headline
-   Title
-   Body
-   Label

The role of each key group is more descriptive, and it's much easier to use different sizes in a particular typography group, e.g., `BodyLarge`, `BodyMedium`, and `BodySmall` instead of `bodyText1`, `bodyText2`, and `caption`. This helps when implementing typography for devices with different screen sizes.

The scaling of the typography has become consistent across the groups. Here is a comparison between the M3 and M2 typescales:

![](https://blog.codemagic.io/typescale_comparison_16973925797358865740_hu9559f954705c0743cbd660c9e255659f_0_1280x1800_fit_linear_3.png)

### Elevation

In Material 2, each elevated component gets a shadow. The higher the elevation, the bigger the shadow. Going even further, Material 3 introduces a new `surfaceTintColor` color property. When applied to elevated components, the surface of the elevated components gets this color, and its intensity depends on the elevation value.

![](https://blog.codemagic.io/elevation_surface_16501195752006919127_huc594a07f071ee0e54ec69d7628a99bc9_0_1280x1800_fit_linear_3.png) Source: <https://m3.material.io/styles/elevation/overview>

The `surfaceTintColor` property is added to all the elevated widgets in Flutter, along with the `elevation` and `shadow` properties.

Try out this Material elevation demo: Turn off shadows by tapping on the icon button in the top right and switch between M2 and M3. Notice that elevated surfaces take on the `surfaceTintColor` color, which makes them visible even when no shadow is provided.

When comparing the M2 `AppBar` with the M3 `AppBar` in the starter app, you'll notice that the `AppBar` doesn't have a default `elevation` value, `surfaceTintColor` color, or `shadow` color.

| M2 `AppBar` | M3 `AppBar` |
| --- | --- |
| ![](https://blog.codemagic.io/uploads/2022/12/m2_app_bar.png#center) | ![](https://blog.codemagic.io/uploads/2022/12/m3_app_bar.png#center) |

Providing a custom `elevation` value shows the default `surfaceTintColor` color in effect and applies the theme's shadow color to the `AppBar` so that the AppBar casts a shadow as well.

> Note: This `AppBar.elevation` property is different from the new `AppBar.scrolledUnderElevation` property, which is only in effect when the content is scrolled underneath the `AppBar`. Learn more about this further below.

```
  appBar: AppBar(
    title: Text(widget.title),
    elevation: 4,
  ),

```

![](https://blog.codemagic.io/uploads/2022/12/m3_app_bar_elevated.png#center)

```
  appBar: AppBar(
    title: Text(widget.title),
    elevation: 4,
    shadowColor: Theme.of(context).shadowColor,
  ),

```

![](https://blog.codemagic.io/uploads/2022/12/m3_app_bar_elevated_with_shadow.png#center)

### Shapes

Material 3 offers a wider range of shapes, including squared, rounded, and rounded rectangular shapes. The `FAB`, which was previously circled, now has a rounded rectangular shape, and material buttons went from rounded rectangular to pill shaped. Widgets like `Card`, `Dialog`, and `BottomSheet` are also more rounded in M3.

![](https://blog.codemagic.io/uploads/2022/12/m3_fab.png#center)![](https://blog.codemagic.io/uploads/2022/12/m3_buttons.png#center)

Migrating from Material 2 to Material 3
---------------------------------------

Here, I'll walk you through the process of migrating a Material 2 demo app to Material 3.

This demo app contains some Material 2 Flutter widgets. Some of them will be updated when enabling M3, and some of the M2 widgets can be replaced with new M3-style widgets. For example, `ElevatedButton` can be replaced with the new `FilledButton` to preserve the visual design, and `BottomNavigationBar` can be replaced with the new M3-style `NavigationBar` widget. The demo app also contains some customization needed in an M2 app for some widgets to stack well. For instance, `InputDecorationTheme` applies a custom `fillColor` so that the `TextField` is visible when placed in the `AppBar` in an M2 app.

```
  theme: ThemeData(
    colorScheme: const ColorScheme.light().copyWith(
      primary: Colors.green[700],
      secondary: Colors.green[700],
    ),
    inputDecorationTheme: InputDecorationTheme(
      filled: true,
      fillColor: Theme.of(context).colorScheme.onPrimary,
      hintStyle: TextStyle(
        color: Colors.green[700],
      ),
    ),
    floatingActionButtonTheme: const FloatingActionButtonThemeData(
      foregroundColor: Colors.white,
    ),
  ),

```

![](https://blog.codemagic.io/uploads/2022/12/m2_demo_1.png#center)![](https://blog.codemagic.io/uploads/2022/12/m2_demo_2.png#center)![](https://blog.codemagic.io/uploads/2022/12/m2_demo_3.png#center)

One of the best things about Material 3 is that widgets use consistent colors, and the overall theming experience has also been improved. For example, in the demo, we used a custom `InputDecorationTheme` to make the `TextField` visible in the dark green `AppBar`. But when migrating to M3, we can remove this, and the `TextField` will be visible without any customization.

In the demo, remove the existing `colorScheme` property, `inputDecorationTheme`, and `floatingActionButtonTheme`. Then add the following lines:

```
	theme: ThemeData(
    useMaterial3: true,
    colorSchemeSeed: Colors.green[700]
  ),

```

We now have a new beautiful `ColorScheme` that's applied to all the components in the demo app. Each UI component is using specific tonal palette colors. `TextField` uses an appropriate `fillColor`, and cards have the default greenish `surfaceTintColor`.

![](https://blog.codemagic.io/uploads/2022/12/m3_demo_1.png#center)

`IconButton` now supports the `ButtonStyle` property, which you can use to customize the `IconButton` to get an M3 visual and a new selected state. Let's update the `IconButton` from the `AppBar` in the demo app to an M3 filled-style icon button.

![](https://blog.codemagic.io/uploads/2022/12/m3_demo_icon_button.png#center)

Check out <https://api.flutter.dev/flutter/material/IconButton-class.html> and <https://m3.material.io/components/icon-buttons/overview> to learn more.

Here's my favorite part: When you scroll through the content, the `AppBar`'s default `scrollUnderElevation` kicks in. Notice that the `surfaceTintColor` intensified when we're scrolling, and as a result, the `AppBar` changes color. This is because the `AppBar` is elevated based on the `scrollUnderElevation` value when the content is scrolled underneath. List views send scroll notifications to the `AppBar` that they're being scrolled beneath.

> You can implement `AppBar.notificationPredicate` and listen to scroll notifications from a nested list view for more complex layouts.

The Material 3 `AppBar` is elevated when content is scrolled underneath the `AppBar`. You can adjust this elevation using the new `scrolledUnderElevation` property.

Check out the official `scrolledUnderElevation` code sample I've added in the `AppBar` [docs](https://api.flutter.dev/flutter/material/AppBar-class.html).

Execute `flutter create --sample=material.AppBar.2 mysample` to create a local project with this code sample.

The migration process for our demo app isn't complete yet. It still uses the M2-style `BottomNavigationBar`, so let's replace it with the new M3-style `NavigationBar` widget. It's taller and easier to interact with, and it isn't elevated.

| M2-style `BottomNavigationBar` | M3-style `NavigationBar` |
| --- | --- |
| ![](https://blog.codemagic.io/uploads/2022/12/m3_demo_bottom_navigation_bar.png#center) | ![](https://blog.codemagic.io/uploads/2022/12/m3_demo_navigation_bar.png#center) |

Check out the documentation for the [NavigationBar class](https://api.flutter.dev/flutter/material/NavigationBar-class.html) for more details.

Tapping on the `FAB` on the home screen opens a dialog with a rounded rectangular shape. Since the dialog is elevated by default, we can see that the default `surfaceTintColor` has been applied and the content padding has been slightly modified, as it has an optional `icon` property.

![](https://blog.codemagic.io/uploads/2022/12/m3_dialog.png#center)

Check out the documentation for the [showDialog function](https://api.flutter.dev/flutter/material/showDialog.html) for more details.

Now, navigate to the details page by tapping on one of the list items. This page contains a `SliverAppBar` with `expandedHeight` and `flexibleSpace` to make the app bar title large and the `SliverAppBar` collapsable. This can be replaced with the new `SliverAppBar.large`, which supports large titles and is also collapsable. When doing so, we can remove `expandedHeight` and `flexibleSpace`.

```
	SliverAppBar.large(
    title: const Text('Lorem Ipsum'),
  ),

```

For the new M3 `AppBar` variants, which support medium and large titles, use the new `SliverAppBar.medium` and `SliverAppBar.large`.

Check out the documentation for the [SilverAppBar.medium constructor](https://api.flutter.dev/flutter/material/SliverAppBar/SliverAppBar.medium.html) and [SilverAppBar.large constructor](https://api.flutter.dev/flutter/material/SliverAppBar/SliverAppBar.large.html) for more details.

Here are the screenshots of the final M3 demo.

![](https://blog.codemagic.io/uploads/2022/12/m3_demo_final_1.png#center)![](https://blog.codemagic.io/uploads/2022/12/m3_demo_final_2.png#center)![](https://blog.codemagic.io/uploads/2022/12/m3_demo_final_3.png#center)

The source code for all the demos is available [on GitHub](https://github.com/TahaTesser/material_3_demos).

Conclusion
----------

Material 3 makes it possible to create beautiful, personalized, and accessible designs. When combining Material 3 with Flutter, you can create a consistent and unified UI experience across mobile, web, and desktop platforms. It makes it much easier to create complex algorithmic color schemes and scale typography for devices with varying screen sizes. Furthermore, accessibility has been improved, and visual feedback is clearer.

The Flutter team has been working hard on adding full support for Material 3 to Flutter. As demonstrated above, you can already migrate your existing Material 2 app to Material 3. If you use some widgets that are yet to receive Material 3 support, you can track their progress in the Material 3 [issue](https://github.com/flutter/flutter/issues/91605).