Migrate from Material 2.5 to Material 3 in Compose for Wear OS

Material 3 Expressive is the next evolution of Material Design. It includes updated theming, components, and personalization features like dynamic color.

This guide focuses on migrating from the Wear Compose Material 2.5 (androidx.wear.compose) Jetpack library to the Wear Compose Material 3 (androidx.wear.compose.material3) Jetpack library for apps.

Approaches

For migrating your app code from M2.5 to M3, follow the same approach described in the Compose Material migration phone guidance, in particular:

Dependencies

M3 has a separate package and version to M2.5:

M2.5

implementation("androidx.wear.compose:compose-material:1.4.0")

M3

implementation("androidx.wear.compose:compose-material3:1.5.0-beta01")

See the latest M3 versions on the Wear Compose Material 3 releases page.

Wear Compose Foundation library version 1.5.0-beta01 introduces some new components that are designed to work with Material 3 components. Similarly, SwipeDismissableNavHost from Wear Compose Navigation library has an updated animation when running on Wear OS 6 (API level 36) or higher. When updating to Wear Compose Material 3 version, we suggest to also update the Wear Compose Foundation and Navigation libraries:

implementation("androidx.wear.compose:compose-foundation:1.5.0-beta01")
implementation("androidx.wear.compose:compose-navigation:1.5.0-beta01")

Theming

In both M2.5 and M3, the theme composable is named MaterialTheme, but the import packages and parameters differ. In M3, the Colors parameter has been renamed to ColorScheme and MotionScheme has been introduced for implementing transitions.

M2.5

import androidx.wear.compose.material.MaterialTheme

MaterialTheme(
        colors = AppColors,
        typography = AppTypography,
        shapes = AppShapes,
        content = content
)

M3

import androidx.wear.compose.material3.MaterialTheme

MaterialTheme(
        colorScheme = AppColorScheme,
        typography = AppTypography,
        shapes = AppShapes,
        motionScheme = AppMotionScheme,
        content = content
)

Color

The color system in M3 is significantly different from M2.5. The number of color parameters has increased, they have different names, and they map differently to M3 components. In Compose, this applies to the M2.5 Colors class, the M3 ColorScheme class, and related functions:

M2.5

import androidx.wear.compose.material.Colors

val appColorScheme: Colors = Colors(
   // M2.5 Color parameters
)

M3

import androidx.wear.compose.material3.ColorScheme

val appColorScheme: ColorScheme = ColorScheme(
   // M3 ColorScheme parameters
)

The following table describes the key differences between M2.5 and M3:

M2.5

M3

Color

has been renamed to ColorScheme

13 Colors

28 Colors

N/A

new dynamic color theming

N/A

new tertiary colors for more expression

Dynamic Color Theming

A new feature in M3 is dynamic color theming. If users change the watch face colors, the colors in the UI change to match.

Use the dynamicColorScheme function to implement dynamic color scheme and provide a defaultColorScheme as a fallback in case dynamic color scheme is not available.

@Composable
fun myApp() {
  val myColorScheme = myBrandColors()
  val dynamicColorScheme = dynamicColorScheme(LocalContext.current)
  MaterialTheme(colorScheme = dynamicColorScheme ?: myBrandColors) {...}
}

Typography

The typography system in M3 is different to M2 and it includes the following features:

  • Nine new text styles
  • Flex fonts, which allow for customization of the type scales for different weights, widths, and roundness
  • AnimatedText, which uses flex fonts

M2.5

import androidx.wear.compose.material.Typography

val Typography = Typography(
   // M2.5 TextStyle parameters
)

M3

import androidx.wear.compose.material3.Typography

val Typography = Typography(
   // M3 TextStyle parameters
)

Flex Fonts

Flex Fonts allow designers to specify the type width and weight for specific sizes.

Text Styles

The following TextStyles are available in M3. These are employed by default by M3 various components.

Typography

TextStyle

Display

displayLarge, displayMedium, displaySmall

Title

titleLarge, titleMedium, titleSmall

Label

labelLarge, labelMedium, labelSmall

Body

bodyLarge, bodyMedium, bodySmall, bodyExtraSmall

Numeral

numeralExtraLarge, numeralLarge, numeralMedium, numeralSmall, numeralExtraSmall

Arc

arcLarge, arcMedium, arcSmall

Shape

The shape system in M3 is different to M2. The number of shape parameters has increased, they're named differently, and they map differently to M3 components. The following shape sizes are available:

  • Extra-small
  • Small
  • Medium
  • Large
  • Extra-large

In Compose, this applies to the M2 Shapes class and the M3 Shapes class:

M2.5

import androidx.wear.compose.material.Shapes

val Shapes = Shapes(
   // M2.5 Shapes parameters
)

M3

import androidx.wear.compose.material3.Shapes

val Shapes = Shapes(
   // M3 Shapes parameters
)

Use the Shapes parameter mapping from Migrate from Material 2 to Material 3 in Compose as a starting point.

Shape morphing

M3 introduces Shape Morphing: shapes now morph in response to interactions.

Shape Morphing behavior is available as a variation on a number of round buttons, see below:

Buttons

Shape morphing function

IconButton

IconButtonDefaults.animatedShape() animates the icon button on press

IconToggleButton

IconToggleButtonDefaults.animatedShape() animates the icon toggle button on press and

IconToggleButtonDefaults.variantAnimatedShapes() animates the icon toggle button on press and check/uncheck

TextButton

TextButtonDefaults.animatedShape() animates the text button on press

TextToggleButton

TextToggleButtonDefaults.animatedShapes() animates the text toggle on press and TextToggleButtonDefaults.variantAnimatedShapes() animates the text toggle on press and check/uncheck

Components and Layout

Most components and layouts from M2.5 are available in M3. However, some M3 components and layouts didn't exist in M2.5. Furthermore, some M3 components have more variations than their equivalents in M2.5.

While some components require special considerations, the following function mappings are recommended as a starting point:

Material 2.5

Material 3

androidx.wear.compose.material.dialog.Alert

androidx.wear.compose.material3.AlertDialog

androidx.wear.compose.material.Button

androidx.wear.compose.material3.IconButton or androidx.wear.compose.material3.TextButton

androidx.wear.compose.material.Card

androidx.wear.compose.material3.Card

androidx.wear.compose.material.TitleCard

androidx.wear.compose.material3.TitleCard

androidx.wear.compose.material.AppCard

androidx.wear.compose.material3.AppCard

androidx.wear.compose.material.Checkbox

No M3 equivalent, migrate to androidx.wear.compose.material3.CheckboxButton or androidx.wear.compose.material3.SplitCheckboxButton

androidx.wear.compose.material.Chip

androidx.wear.compose.material3.Button or
androidx.wear.compose.material3.OutlinedButton or
androidx.wear.compose.material3.FilledTonalButton or
androidx.wear.compose.material3.ChildButton

androidx.wear.compose.material.CompactChip

androidx.wear.compose.material3.CompactButton

androidx.wear.compose.material.InlineSlider

androidx.wear.compose.material3.Slider

androidx.wear.compose.material.LocalContentAlpha

Has been removed as not used by Text or Icon in Material 3

androidx.wear.compose.material.PositionIndicator

androidx.wear.compose.material3.ScrollIndicator

androidx.wear.compose.material.RadioButton

No M3 equivalent, migrate to androidx.wear.compose.material3.RadioButton or androidx.wear.compose.material3.SplitRadioButton

androidx.wear.compose.material.SwipeToRevealCard

androidx.wear.compose.material3.SwipeToReveal

androidx.wear.compose.material.SwipeToRevealChip

androidx.wear.compose.material3.SwipeToReveal

android.wear.compose.material.Scaffold

androidx.wear.compose material3.AppScaffold and androidx.wear.compose.material3.ScreenScaffold

androidx.wear.compose.material.SplitToggleChip

No M3 equivalent, migrate to androidx.wear.compose.material3.SplitCheckboxButton, androidx.wear.compose.material3.SplitSwitchButton, or androidx.wear.compose.material3.SplitRadioButton

androidx.wear.compose.material.Switch

No M3 equivalent, migrate to androidx.wear.compose.material3.SwitchButton or androidx.wear.compose.material3.SplitSwitchButton

androidx.wear.compose.material.ToggleButton

androidx.wear.compose.material3.IconToggleButton or androidx.wear.compose.material3.TextToggleButton

androidx.wear.compose.material.ToggleChip

androidx.wear.compose.material3.CheckboxButton or
androidx.wear.compose.material3.RadioButton or
androidx.wear.compose.material3.SwitchButton

androidx.wear.compose.material.Vignette

Removed as not included in Material 3 Expressive design for Wear OS

Here is a full list of all the Material 3 components:

Material 3

Material 2.5 equivalent component (if not new in M3)

androidx.wear.compose.material3.AlertDialog

androidx.wear.compose.material.dialog.Alert

androix.wear.compose.material3.AnimatedPage

New

androidx.wear.compose.material3.AnimatedText

New

androidx.wear.compose material3.AppScaffold

android.wear.compose.material.Scaffold (with androidx.wear.compose.material3.ScreenScaffold )

androidx.wear.compose.material3.Button

androidx.wear.compose.material.Chip

androidx.wear.compose.material3.ButtonGroup

New

androidx.wear.compose.material3.Card

androidx.wear.compose.material.Card

androidx.wear.compose.material3.CheckboxButton

androidx.wear.compose.material.ToggleChip with a checkbox toggle control

androidx.wear.compose.material3.ChildButton

androidx.wear.compose.material.Chip (only when no background is required)

androidx.wear.compose.material3.CircularProgressIndicator

androidx.wear.compose.material.CircularProgressIndicator

androidx.wear.compose.material3.CompactButton

androidx.wear.compose.material.CompactChip

androidx.wear.compose.material3.ConfirmationDialog

androidx.wear.compose.material.dialog.Confirmation

androidx.wear.compose.material3.curvedText

androidx.wear.compose.material.curvedText

androidx.wear.compose.material3.DatePicker

New

androidx.wear.compose.material3.Dialog

androidx.wear.compose.material.dialog.Dialog

androidx.wear.compose.material3.EdgeButton

New

androidx.wear.compose.material3.FadingExpandingLabel

New

androidx.wear.compose.material3.FilledTonalButton

androidx.wear.compose.material.Chip when a tonal button background is required

androidx.wear.compose.material3.HorizontalPageIndicator

androidx.wear.compose.material.HorizontalPageIndicator

androidx.wear.compose.material3.HorizontalPagerScaffold

New

androidx.wear.compose.material3.Icon

androidx.wear.compose.material.Icon

androidx.wear.compose.material3.IconButton

androidx.wear.compose.material.Button

androidx.wear.compose.material3.IconToggleButton

androidx.wear.compose.material.ToggleButton

androidx.wear.compose.material3.LevelIndicator

New

androidx.wear.compose.material3.LinearProgressIndicator

New

androidx.wear.compose.material3.ListHeader

androidx.wear.compose.material.ListHeader

androidx.wear.compose.material3.ListSubHeader

New

androidx.wear.compose.material3.MaterialTheme

androidx.wear.compose.material.MaterialTheme

androidx.wear.compose.material3.OpenOnPhoneDialog

New

androidx.wear.compose.material3.Picker

androidx.wear.compose.material.Picker

androidx.wear.compose.material3.PickerGroup

androidx.wear.compose.material.PickerGroup

androix.wear.compose.material3.RadioButton

androidx.wear.compose.material.ToggleChip with a radio button toggle control

androidx.wear.compose.material3.ScreenScaffold

android.wear.compose.material.Scaffold (with androidx.wear.compose material3.AppScaffold)

androidx.wear.compose.material3.ScrollIndicator

androidx.wear.compose.material.PositionIndicator

androidx.wear.compose.material3.scrollaway

androidx.wear.compose.material.scrollaway

androidx.wear.compose.material3.SegmentedCircularProgressIndicator

New

androidx.wear.compose.material3.Slider

androidx.wear.compose.material.InlineSlider

androidx.wear.compose.material3.SplitRadioButton

androidx.wear.compose.material.SplitToggleChip

androidx.wear.compose.material3.SplitCheckboxButton

androidx.wear.compose.material.SplitToggleChip

androidx.wear.compose.material3.SplitSwitchButton

androidx.wear.compose.material.SplitToggleChip

androidx.wear.compose.material3.Stepper

androidx.wear.compose.material.Stepper

androidx.wear.compose.material3.SwipeToDismissBox

androidx.wear.compose.material.SwipeToDismissBox

androidx.wear.compose.material3.SwipeToReveal

androidx.wear.compose.material.SwipeToRevealCard and androidx.wear.compose.material.SwipeToRevealChip

androidx.wear.compose.material3.SwitchButton

androidx.wear.compose.material.ToggleChip with a switch toggle control

androidx.wear.compose.material3.Text

androidx.wear.compose.material.Text

androidx.wear.compose.material3.TextButton

androidx.wear.compose.material.Button

androidx.wear.compose.material3.TextToggleButton

androidx.wear.compose.material.ToggleButton

androidx.wear.compose.material3.TimeText

androidx.wear.compose.material.TimeText

androidx.wear.compose.material3.VerticalPagerScaffold

New

And finally a list of some relevant components from Wear Compose Foundation library version 1.5.0-beta01:

Wear Compose Foundation 1.5.0-beta

androidx.wear.compose.foundation.hierarchicalFocusGroup

Used to annotate composables in an application, to keep track of the active part of the composition and coordinate focus.

androidx.compose.foundation.pager.HorizontalPager

A horizontally scrolling pager, built on the Compose Foundation components with Wear-specific enhancements to improve performance and adherence to Wear OS guidelines.

androidx.compose.foundation.pager.VerticalPager

A vertically scrolling pager, built on the Compose Foundation components with Wear-specific enhancements to improve performance and adherence to Wear OS guidelines.

androidx.wear.foundation.lazy.TransformingLazyColumn

Can be used instead of ScalingLazyColumn to add scroll transform effects to each item.

Buttons

Buttons in M3 are different from M2.5. The M2.5 Chip has been replaced by Button. Button implementation provides default values for Text maxLines and textAlign. Those default values can be overridden in the Text element.

M2.5

import androidx.wear.compose.material.Chip

//M2.5 Buttons
Chip(...)
CompactChip(...)
Button(...)

M3

import androidx.wear.compose.material3.Button

//M3 Buttons
Button(...)
CompactButton(...)
IconButton(...)
TextButton(...)

M3 also includes new button variations. Check them out on the Compose Material 3 API reference overview.

M3 introduces a new button: EdgeButton. EdgeButton is available in 4 different sizes: extra small, small, medium, and large. EdgeButton implementation provide a default value for maxLines depending on the size which can be customized.

If you are using TransformingLazyColumn and ScalingLazyColumn, pass the EdgeButton into the ScreenScaffold so that it morphs, changing its shape with scrolling. See the code below to check how to use EdgeButton with ScreenScaffold and TransformingLazyColumn.

import androidx.wear.compose.material3.EdgeButton
import androidx.wear.compose.material3.ScreenScaffold

ScreenScaffold(
   scrollState = state,
   contentPadding = contentPadding,
   edgeButton = {
      EdgeButton(...)
   }
){ contentPadding ->
   TransformingLazyColumn(state = state, contentPadding = contentPadding,){
   // additional code here
   }
}

Scaffold

Scaffold in M3 is different from M2.5. In M3, AppScaffold and the new ScreenScaffold composable have replaced Scaffold. AppScaffold and ScreenScaffold lay out the structure of a screen and coordinate transitions of the ScrollIndicator and TimeText components.

AppScaffold allows static screen elements such as TimeText to remain visible during in-app transitions such as swipe-to-dismiss. ​​It provides a slot for the main application content, which will usually be supplied by a navigation component such as SwipeDismissableNavHost

You declare one AppScaffold for Activity and use a ScreenScaffold for each Screen.

M2.5

import androidx.wear.compose.material.Scaffold

Scaffold {...}

M3

import androidx.wear.compose.material3.AppScaffold
import androidx.wear.compose.material3.ScreenScaffold

AppScaffold {
   // Define the navigation hierarchy within the AppScaffold,
   // such as using SwipeDismissableNavHost.
   SwipeDismissableNavHost(...) {
      composable("home") {
         HomeScreen()
      }
      //other screens
   }
}
fun HomeScreen() {
    val scrollState = rememberScrollState()
    ScreenScaffold(scrollState = scrollState) {
    //rest of the screen code
    }
}

If you are using a HorizontalPager with HorizontalPagerIndicator, you can migrate to HorizontalPagerScaffold. HorizontalPagerScaffold is placed within an AppScaffold. AppScaffold and HorizontalPagerScaffold lay out the structure of a Pager and coordinate transitions of the HorizontalPageIndicator andvTimeText components.

HorizontalPagerScaffold displays the HorizontalPageIndicator at the center-end of the screen by default and coordinates showing/hiding TimeText and HorizontalPageIndicator according to whether the Pager is being paged, this is determined by the PagerState.

There's also a new AnimatedPage component, which animates a page within a Pager with a scaling and scrim effect based on its position.

import androidx.wear.compose.material3.AppScaffold
import androidx.wear.compose.material3.HorizontalPagerScaffold
import androidx.wear.compose.material3.ScreenScaffold
import androidx.wear.compose.foundation.pager.HorizontalPager
import androidx.wear.compose.foundation.pager.rememberPagerState

AppScaffold {
    val pagerState = rememberPagerState(pageCount = { 10 })

    HorizontalPagerScaffold(pagerState = pagerState) {
       HorizontalPager(
          state = pagerState,
        ) { page ->
            AnimatedPage(pageIndex = page, pagerState = pagerState) {
                ScreenScaffold {

   }
}

Finally, M3 introduces a VerticalPagerScaffold which follows the same pattern as the HorizontalPagerScaffold:

import androidx.wear.compose.material3.AppScaffold
import androidx.wear.compose.material3.HorizontalPagerScaffold
import androidx.wear.compose.material3.ScreenScaffold
import androidx.wear.compose.foundation.pager.VerticalPager
import androidx.wear.compose.foundation.pager.rememberPagerState

AppScaffold {
   val pagerState = rememberPagerState(pageCount = { 10 })

   VerticalPagerScaffold(pagerState = pagerState) {
      VerticalPager(
         state = pagerState
      ) { page ->
             AnimatedPage(pageIndex = page, pagerState = pagerState){
                ScreenScaffold {
        
   }
}

Placeholder

There are some API changes between M2.5 and M3. Placeholder.PlaceholderDefaults now provides two modifiers:

  • Modifier.placeholder, which is drawn instead of content that is not yet loaded
  • A placeholder shimmer effect Modifier.placeholderShimmer which provides a placeholder shimmer effect which runs in an animation loop while waiting for the data to load.

See below for additional changes to the Placeholder component.

M2.5

M3

PlaceholderState.startPlaceholderAnimation

Has been removed

PlaceholderState.placeholderProgression

Has been removed

PlaceholderState.isShowContent

Has been renamed to !PlaceholderState.isVisible

PlaceholderState.isWipeOff

Has been removed

PlaceholderDefaults.painterWithPlaceholderOverlayBackgroundBrush

has been removed

PlaceholderDefaults.placeholderBackgroundBrush

Has been removed

PlaceholderDefaults.placeholderChipColors

Has been removed

SwipeDismissableNavHost

SwipeDismissableNavHost is part of wear.compose.navigation. When this component is used with M3, the M3 MaterialTheme updates the LocalSwipeToDismissBackgroundScrimColor and LocalSwipeToDismissContentScrimColor.

TransformingLazyColumn

TransformingLazyColumn is part of wear.compose.lazy.foundation and adds support for scaling and morphing animations on list items during scrolling , enhancing the user experience.

Similarly to ScalingLazyColumn, it provides rememberTransformingLazyColumnState() to create a TransformingLazyColumnState that is remembered across compositions.

For adding scaling and morphing animations, add the following to each list item:

  • Modifier.transformedHeight, which allows you to calculate transformed height of the items using a TransformationSpec, you can use rememberTransformationSpec() unless you need further customization.
  • A SurfaceTransformation
import androidx.wear.compose.material3.AppScaffold
import androidx.wear.compose.material3.ScreenScaffold
import androidx.wear.compose.material3.SurfaceTransformation
import androidx.wear.compose.material3.lazy.rememberTransformationSpec
import androidx.wear.compose.material3.lazy.transformedHeight
import androidx.wear.compose.foundation.lazy.rememberTransformingLazyColumnState
import androidx.wear.compose.foundation.lazy.TransformingLazyColumn

val state = rememberTransformingLazyColumnState()
val transformationSpec = rememberTransformationSpec()
AppScaffold {
   ScreenScaffold(state) { contentPadding ->
      TransformingLazyColumn(state = state, contentPadding = contentPadding) {
         items(count = 50) {
            Button(
               onClick = {},
               modifier =
                        Modifier.fillMaxWidth().transformedHeight(this, transformationSpec),
                        transformation = SurfaceTransformation(transformationSpec),
                    ) {
                        Text("Item $it")
                    }
                }
            }
        }
    }

Useful links

To learn more about migrating from M2.5 to M3 in Compose, consult the following additional resources.

Samples

Wear OS samples in the Material3 branch on GitHub

Compose for Wear OS codelab

API reference and source code

Design