androidx.wear.compose.material3

Interfaces

MotionScheme

A motion scheme provides all the FiniteAnimationSpecs for a MaterialTheme.

PickerScope

Receiver scope which is used by Picker.

TimeSource

Classes

AngularDirection

Class to define angular direction - Clockwise and Counter Clockwise.

AnimatedTextFontRegistry

Generates fonts to be used by AnimatedText throughout the animation.

ButtonColors

Represents the container and content colors used in buttons in different states.

ButtonGroupScope

Scope for the children of a ButtonGroup

CardColors

Represents Colors used in Card.

CheckboxButtonColors

Represents the different container and content colors used for CheckboxButton in various states, that are checked, unchecked, enabled and disabled.

ColorScheme

A ColorScheme holds all the named color parameters for a MaterialTheme.

ConfirmationColors

Represents the colors used in Confirmation, SuccessConfirmation and FailureConfirmation.

DatePickerColors
DatePickerType

Specifies the types of columns to display in the DatePicker.

EdgeButtonSize

Size of the EdgeButton.

IconButtonColors

Represents the container and content colors used in an icon button in different states.

IconButtonShapes

Represents the shapes used for IconButton in various states.

IconToggleButtonColors

Represents the different container and content colors used for IconToggleButton in various states, that are checked, unchecked, enabled and disabled.

IconToggleButtonShapes

Represents the shapes used for IconToggleButton in various states.

LevelIndicatorColors

Represents the indicator and track colors used in LevelIndicator.

OpenOnPhoneDialogColors

Represents the colors used in OpenOnPhoneDialog.

PickerGroupScope
PickerState

A state object that can be hoisted to observe item selection.

PlaceholderState

A state object that can be used to control placeholders.

ProgressIndicatorColors

Represents the indicator and track colors used in progress indicator.

RadioButtonColors

Represents the different container and content colors used for RadioButton in various states, that are selected, unselected, enabled and disabled.

ScreenStage

ScreenStage represents the different stages for a screen, which affect visibility of scaffold components such as TimeText and ScrollIndicator with scrollAway and other animations.

Shapes

Material surfaces can be displayed in different shapes.

SliderColors

Represents the background and content colors used in Slider in different states.

SplitCheckboxButtonColors

Represents the different colors used in SplitCheckboxButton in different states.

SplitRadioButtonColors

Represents the different colors used in SplitRadioButton in different states.

SplitSwitchButtonColors

Represents the different colors used in SplitSwitchButton in different states.

StepperColors

Represents Colors used in Stepper.

SwipeToRevealScope

Scope for the actions of a SwipeToReveal composable.

SwitchButtonColors

Represents the different container and content colors used for SwitchButton, in various states, that are checked, unchecked, enabled and disabled.

TextButtonColors

Represents the container and content colors used in a text button in different states.

TextButtonShapes

Represents the shapes used for TextButton in various states.

TextConfiguration

Class representing aspects of Text that can be configured with LocalTextConfiguration.

TextToggleButtonColors

Represents the different container and content colors used for TextToggleButton in various states, that are checked, unchecked, enabled and disabled.

TextToggleButtonShapes

Represents the shapes used for TextToggleButton in various states.

TimePickerColors

Represents the colors used by a TimePicker.

TimePickerType

Specifies the types of columns to display in the TimePicker.

TimeTextScope

Receiver scope which is used by TimeText.

Typography

Class holding typography definitions as defined by the Wear Material typography specification.

Objects

AlertDialogDefaults

Contains the default values used by AlertDialog

AnimatedTextDefaults

Defaults for AnimatedText.

ArcProgressIndicatorDefaults

Contains default values for ArcProgressIndicator.

ButtonDefaults

Contains the default values used by Button

ButtonGroupDefaults

Contains the default values used by ButtonGroup

CardDefaults

Contains the default values used by Card

CheckboxButtonDefaults

Contains the default values used by CheckboxButtons and SplitCheckboxButtons

CircularProgressIndicatorDefaults

Contains default values for CircularProgressIndicator.

ConfirmationDefaults

Contains default values used by Confirmation composable.

CurvedTextDefaults
DatePickerDefaults

Contains the default values used by DatePicker

EdgeButtonDefaults

Contains the default values used by EdgeButton.

IconButtonDefaults

Contains the default values used by IconButton.

IconToggleButtonDefaults

Contains the default values used by IconToggleButton.

LevelIndicatorDefaults

Contains the default values used for LevelIndicator.

LinearProgressIndicatorDefaults

Contains defaults for Linear Progress Indicator.

ListHeaderDefaults
MaterialTheme
OpenOnPhoneDialogDefaults

Contains the default values used by OpenOnPhoneDialog.

PageIndicatorDefaults

Contains the default values used by HorizontalPageIndicator and VerticalPageIndicator

PagerScaffoldDefaults

Contains default values used for HorizontalPagerScaffold and VerticalPagerScaffold.

PickerDefaults

Contains the default values used by Picker.

PlaceholderDefaults

Contains the default values used for providing placeholders.

ProgressIndicatorDefaults

Contains defaults for Progress Indicators.

RadioButtonDefaults

Contains the default values used by RadioButtons and SplitRadioButtons

ScreenScaffoldDefaults

Contains the default values used by ScreenScaffold

ScrollIndicatorDefaults

Contains the default values used for ScrollIndicator.

ShapeDefaults

Contains the default values used by Shapes

SliderDefaults

Defaults used by slider.

StepperDefaults

Defaults used by Stepper.

SwipeToRevealDefaults
SwitchButtonDefaults

Contains the default values used by SwitchButtons and SplitSwitchButtons

TextButtonDefaults

Contains the default values used by TextButton.

TextConfigurationDefaults

Default values for TextConfiguration

TextToggleButtonDefaults

Contains the default values used by TextToggleButton.

TimePickerDefaults

Contains the default values used by TimePicker

TimeTextDefaults

Contains the default values used by TimeText.

Annotations

Top-level functions summary

Unit
@Composable
AlertDialog(
    show: Boolean,
    onDismissRequest: () -> Unit,
    title: @Composable () -> Unit,
    modifier: Modifier,
    icon: (@Composable () -> Unit)?,
    text: (@Composable () -> Unit)?,
    verticalArrangement: Arrangement.Vertical,
    contentPadding: PaddingValues,
    properties: DialogProperties,
    content: (ScalingLazyListScope.() -> Unit)?
)

Dialogs provide important prompts in a user flow.

Unit
@Composable
AlertDialog(
    show: Boolean,
    onDismissRequest: () -> Unit,
    edgeButton: @Composable BoxScope.() -> Unit,
    title: @Composable () -> Unit,
    modifier: Modifier,
    icon: (@Composable () -> Unit)?,
    text: (@Composable () -> Unit)?,
    verticalArrangement: Arrangement.Vertical,
    contentPadding: PaddingValues,
    properties: DialogProperties,
    content: (ScalingLazyListScope.() -> Unit)?
)

Dialogs provide important prompts in a user flow.

Unit
@Composable
AlertDialog(
    show: Boolean,
    onDismissRequest: () -> Unit,
    confirmButton: @Composable RowScope.() -> Unit,
    title: @Composable () -> Unit,
    modifier: Modifier,
    dismissButton: @Composable RowScope.() -> Unit,
    icon: (@Composable () -> Unit)?,
    text: (@Composable () -> Unit)?,
    verticalArrangement: Arrangement.Vertical,
    contentPadding: PaddingValues,
    properties: DialogProperties,
    content: (ScalingLazyListScope.() -> Unit)?
)

AlertDialogs provide important prompts in a user flow.

Unit
@Composable
AlertDialogContent(
    title: @Composable () -> Unit,
    modifier: Modifier,
    icon: (@Composable () -> Unit)?,
    text: (@Composable () -> Unit)?,
    verticalArrangement: Arrangement.Vertical,
    contentPadding: PaddingValues,
    content: (ScalingLazyListScope.() -> Unit)?
)

This AlertDialogContent overload provides the content for an AlertDialog without any dedicated slots for buttons.

Unit
@Composable
AlertDialogContent(
    edgeButton: @Composable BoxScope.() -> Unit,
    title: @Composable () -> Unit,
    modifier: Modifier,
    icon: (@Composable () -> Unit)?,
    text: (@Composable () -> Unit)?,
    verticalArrangement: Arrangement.Vertical,
    contentPadding: PaddingValues,
    content: (ScalingLazyListScope.() -> Unit)?
)

This AlertDialogContent overload provides the content for an AlertDialog with a single EdgeButton to confirm an action.

Unit
@Composable
AlertDialogContent(
    confirmButton: @Composable RowScope.() -> Unit,
    title: @Composable () -> Unit,
    dismissButton: @Composable RowScope.() -> Unit,
    modifier: Modifier,
    icon: (@Composable () -> Unit)?,
    text: (@Composable () -> Unit)?,
    verticalArrangement: Arrangement.Vertical,
    contentPadding: PaddingValues,
    content: (ScalingLazyListScope.() -> Unit)?
)

This AlertDialogContent overload provides the content for an AlertDialog with 2 buttons to confirm or dismiss an action.

Unit
@Composable
@RequiresApi(value = 31)
AnimatedText(
    text: String,
    fontRegistry: AnimatedTextFontRegistry,
    progressFraction: () -> Float,
    modifier: Modifier,
    contentAlignment: Alignment
)

A composable that displays an animated text.

Unit
@Composable
AppCard(
    onClick: () -> Unit,
    appName: @Composable RowScope.() -> Unit,
    title: @Composable RowScope.() -> Unit,
    modifier: Modifier,
    onLongClick: (() -> Unit)?,
    onLongClickLabel: String?,
    enabled: Boolean,
    shape: Shape,
    colors: CardColors,
    border: BorderStroke?,
    contentPadding: PaddingValues,
    interactionSource: MutableInteractionSource?,
    appImage: (@Composable RowScope.() -> Unit)?,
    time: (@Composable RowScope.() -> Unit)?,
    content: @Composable ColumnScope.() -> Unit
)

Opinionated Wear Material 3 Card that offers a specific 5 slot layout to show information about an application, e.g. a notification.

Unit
@Composable
AppScaffold(
    modifier: Modifier,
    timeText: @Composable () -> Unit,
    content: @Composable BoxScope.() -> Unit
)

AppScaffold is one of the Wear Material3 scaffold components.

Unit
@Composable
ArcProgressIndicator(
    startAngle: Float,
    endAngle: Float,
    modifier: Modifier,
    angularDirection: AngularDirection,
    colors: ProgressIndicatorColors,
    strokeWidth: Dp,
    gapSize: Dp
)

Indeterminate Material Design arc progress indicator.

Unit
@Composable
Button(
    onClick: () -> Unit,
    modifier: Modifier,
    onLongClick: (() -> Unit)?,
    onLongClickLabel: String?,
    enabled: Boolean,
    shape: Shape,
    colors: ButtonColors,
    border: BorderStroke?,
    contentPadding: PaddingValues,
    interactionSource: MutableInteractionSource?,
    content: @Composable RowScope.() -> Unit
)

Base level Wear Material3 Button that offers a single slot to take any content.

Unit
@Composable
Button(
    onClick: () -> Unit,
    modifier: Modifier,
    onLongClick: (() -> Unit)?,
    onLongClickLabel: String?,
    secondaryLabel: (@Composable RowScope.() -> Unit)?,
    icon: (@Composable BoxScope.() -> Unit)?,
    enabled: Boolean,
    shape: Shape,
    colors: ButtonColors,
    border: BorderStroke?,
    contentPadding: PaddingValues,
    interactionSource: MutableInteractionSource?,
    label: @Composable RowScope.() -> Unit
)

Wear Material3 Button that offers three slots and a specific layout for an icon, label and secondaryLabel.

Unit
@Composable
ButtonGroup(
    modifier: Modifier,
    spacing: Dp,
    expansionWidth: Dp,
    contentPadding: PaddingValues,
    verticalAlignment: Alignment.Vertical,
    content: ButtonGroupScope.() -> Unit
)

Layout component to implement an expressive group of buttons, that react to touch by growing the touched button, (while the neighbor(s) shrink to accommodate and keep the group width constant).

Unit
@Composable
Card(
    onClick: () -> Unit,
    modifier: Modifier,
    onLongClick: (() -> Unit)?,
    onLongClickLabel: String?,
    enabled: Boolean,
    shape: Shape,
    colors: CardColors,
    border: BorderStroke?,
    contentPadding: PaddingValues,
    interactionSource: MutableInteractionSource?,
    content: @Composable ColumnScope.() -> Unit
)

Base level Wear Material 3 Card that offers a single slot to take any content.

Unit
@Composable
CheckboxButton(
    checked: Boolean,
    onCheckedChange: (Boolean) -> Unit,
    modifier: Modifier,
    enabled: Boolean,
    shape: Shape,
    colors: CheckboxButtonColors,
    contentPadding: PaddingValues,
    interactionSource: MutableInteractionSource?,
    icon: (@Composable BoxScope.() -> Unit)?,
    secondaryLabel: (@Composable RowScope.() -> Unit)?,
    label: @Composable RowScope.() -> Unit
)

The Wear Material CheckboxButton offers three slots and a specific layout for an icon, a label, and a secondaryLabel.

Unit
@Composable
ChildButton(
    onClick: () -> Unit,
    modifier: Modifier,
    onLongClick: (() -> Unit)?,
    onLongClickLabel: String?,
    enabled: Boolean,
    shape: Shape,
    colors: ButtonColors,
    border: BorderStroke?,
    contentPadding: PaddingValues,
    interactionSource: MutableInteractionSource?,
    content: @Composable RowScope.() -> Unit
)

Base level Wear Material3 ChildButton that offers a single slot to take any content.

Unit
@Composable
ChildButton(
    onClick: () -> Unit,
    modifier: Modifier,
    onLongClick: (() -> Unit)?,
    onLongClickLabel: String?,
    secondaryLabel: (@Composable RowScope.() -> Unit)?,
    icon: (@Composable BoxScope.() -> Unit)?,
    enabled: Boolean,
    shape: Shape,
    colors: ButtonColors,
    border: BorderStroke?,
    contentPadding: PaddingValues,
    interactionSource: MutableInteractionSource?,
    label: @Composable RowScope.() -> Unit
)

Wear Material3 ChildButton that offers three slots and a specific layout for an icon, label and secondaryLabel.

Unit
@Composable
CircularProgressIndicator(
    modifier: Modifier,
    colors: ProgressIndicatorColors,
    strokeWidth: Dp,
    gapSize: Dp
)

Indeterminate Material Design circular progress indicator.

Unit
@Composable
CircularProgressIndicator(
    progress: () -> Float,
    modifier: Modifier,
    allowProgressOverflow: Boolean,
    startAngle: Float,
    endAngle: Float,
    colors: ProgressIndicatorColors,
    strokeWidth: Dp,
    gapSize: Dp,
    enabled: Boolean
)

Material Design circular progress indicator.

Unit
@Composable
CircularProgressIndicatorContent(
    progress: () -> Float,
    modifier: Modifier,
    allowProgressOverflow: Boolean,
    startAngle: Float,
    endAngle: Float,
    colors: ProgressIndicatorColors,
    strokeWidth: Dp,
    gapSize: Dp,
    enabled: Boolean
)

Simple circular progress indicator without any progress animations.

Unit
@Composable
CompactButton(
    onClick: () -> Unit,
    modifier: Modifier,
    onLongClick: (() -> Unit)?,
    onLongClickLabel: String?,
    icon: (@Composable BoxScope.() -> Unit)?,
    enabled: Boolean,
    shape: Shape,
    colors: ButtonColors,
    border: BorderStroke?,
    contentPadding: PaddingValues,
    interactionSource: MutableInteractionSource?,
    label: (@Composable RowScope.() -> Unit)?
)

A Wear Material3 CompactButton that offers two slots and a specific layout for an icon and label.

Unit
@Composable
Confirmation(
    show: Boolean,
    onDismissRequest: () -> Unit,
    curvedText: (CurvedScope.() -> Unit)?,
    modifier: Modifier,
    colors: ConfirmationColors,
    properties: DialogProperties,
    durationMillis: Long,
    content: @Composable BoxScope.() -> Unit
)

Shows a Confirmation dialog with an icon and optional very short curved text.

Unit
@Composable
Confirmation(
    show: Boolean,
    onDismissRequest: () -> Unit,
    text: (@Composable ColumnScope.() -> Unit)?,
    modifier: Modifier,
    colors: ConfirmationColors,
    properties: DialogProperties,
    durationMillis: Long,
    content: @Composable BoxScope.() -> Unit
)

Shows a Confirmation dialog with an icon and optional short text.

Unit
@RequiresApi(value = 26)
@Composable
DatePicker(
    initialDate: LocalDate,
    onDatePicked: (LocalDate) -> Unit,
    modifier: Modifier,
    minDate: LocalDate?,
    maxDate: LocalDate?,
    datePickerType: DatePickerType,
    colors: DatePickerColors
)

Full screen date picker with day, month, year.

Unit
@Composable
Dialog(
    show: Boolean,
    onDismissRequest: () -> Unit,
    modifier: Modifier,
    properties: DialogProperties,
    content: @Composable () -> Unit
)

A base dialog component used by AlertDialog and Confirmation variations.

Unit
@Composable
EdgeButton(
    onClick: () -> Unit,
    modifier: Modifier,
    buttonSize: EdgeButtonSize,
    enabled: Boolean,
    colors: ButtonColors,
    border: BorderStroke?,
    interactionSource: MutableInteractionSource?,
    content: @Composable RowScope.() -> Unit
)

Wear Material3 EdgeButton that offers a single slot to take any content.

Unit
@Composable
FailureConfirmation(
    show: Boolean,
    onDismissRequest: () -> Unit,
    modifier: Modifier,
    curvedText: (CurvedScope.() -> Unit)?,
    colors: ConfirmationColors,
    properties: DialogProperties,
    durationMillis: Long,
    content: @Composable BoxScope.() -> Unit
)

Shows a Confirmation dialog with a failure icon and an optional short curved text.

Unit
@Composable
FilledIconButton(
    onClick: () -> Unit,
    modifier: Modifier,
    onLongClick: (() -> Unit)?,
    onLongClickLabel: String?,
    enabled: Boolean,
    shapes: IconButtonShapes,
    colors: IconButtonColors,
    border: BorderStroke?,
    interactionSource: MutableInteractionSource?,
    content: @Composable BoxScope.() -> Unit
)

Wear Material FilledIconButton is a circular, icon-only button with a colored background and a contrasting content color.

Unit
@Composable
FilledTonalButton(
    onClick: () -> Unit,
    modifier: Modifier,
    onLongClick: (() -> Unit)?,
    onLongClickLabel: String?,
    enabled: Boolean,
    shape: Shape,
    colors: ButtonColors,
    border: BorderStroke?,
    contentPadding: PaddingValues,
    interactionSource: MutableInteractionSource?,
    content: @Composable RowScope.() -> Unit
)

Base level Wear Material3 FilledTonalButton that offers a single slot to take any content.

Unit
@Composable
FilledTonalButton(
    onClick: () -> Unit,
    modifier: Modifier,
    onLongClick: (() -> Unit)?,
    onLongClickLabel: String?,
    secondaryLabel: (@Composable RowScope.() -> Unit)?,
    icon: (@Composable BoxScope.() -> Unit)?,
    enabled: Boolean,
    shape: Shape,
    colors: ButtonColors,
    border: BorderStroke?,
    contentPadding: PaddingValues,
    interactionSource: MutableInteractionSource?,
    label: @Composable RowScope.() -> Unit
)

Wear Material3 FilledTonalButton that offers three slots and a specific layout for an icon, label and secondaryLabel.

Unit
@Composable
FilledTonalIconButton(
    onClick: () -> Unit,
    modifier: Modifier,
    onLongClick: (() -> Unit)?,
    onLongClickLabel: String?,
    enabled: Boolean,
    shapes: IconButtonShapes,
    colors: IconButtonColors,
    border: BorderStroke?,
    interactionSource: MutableInteractionSource?,
    content: @Composable BoxScope.() -> Unit
)

Wear Material FilledTonalIconButton is a circular, icon-only button with a muted, colored background and a contrasting icon color.

Unit
@Composable
HorizontalPageIndicator(
    pagerState: PagerState,
    modifier: Modifier,
    selectedColor: Color,
    unselectedColor: Color,
    backgroundColor: Color
)

Horizontal page indicator for use with HorizontalPager, representing the currently active page and the approximate number of pages.

Unit
@Composable
HorizontalPagerScaffold(
    pagerState: PagerState,
    modifier: Modifier,
    pageIndicator: (@Composable BoxScope.() -> Unit)?,
    pageIndicatorAnimationSpec: AnimationSpec<Float>?,
    rotaryScrollableBehavior: RotaryScrollableBehavior?,
    content: @Composable PagerScope.(page: Int) -> Unit
)

HorizontalPagerScaffold is one of the Wear Material3 scaffold components.

Unit
@Composable
Icon(
    bitmap: ImageBitmap,
    contentDescription: String?,
    modifier: Modifier,
    tint: Color
)

Icon component that draws bitmap using tint, defaulting to LocalContentColor.

Unit
@Composable
Icon(
    imageVector: ImageVector,
    contentDescription: String?,
    modifier: Modifier,
    tint: Color
)

Icon component that draws imageVector using tint, defaulting to LocalContentColor.

Unit
@Composable
Icon(
    painter: Painter,
    contentDescription: String?,
    modifier: Modifier,
    tint: Color
)

Icon component that draws a painter using tint, defaulting to LocalContentColor.

Unit
@Composable
IconButton(
    onClick: () -> Unit,
    modifier: Modifier,
    onLongClick: (() -> Unit)?,
    onLongClickLabel: String?,
    enabled: Boolean,
    shapes: IconButtonShapes,
    colors: IconButtonColors,
    border: BorderStroke?,
    interactionSource: MutableInteractionSource?,
    content: @Composable BoxScope.() -> Unit
)

Wear Material IconButton is a circular, icon-only button with transparent background and no border.

Unit
@Composable
IconToggleButton(
    checked: Boolean,
    onCheckedChange: (Boolean) -> Unit,
    modifier: Modifier,
    enabled: Boolean,
    colors: IconToggleButtonColors,
    interactionSource: MutableInteractionSource?,
    shapes: IconToggleButtonShapes,
    border: BorderStroke?,
    content: @Composable BoxScope.() -> Unit
)

Wear Material IconToggleButton is a filled icon toggle button which switches between primary colors and tonal colors depending on checked value, and offers a single slot for icon or image.

Unit
@Composable
LevelIndicator(
    value: () -> Float,
    modifier: Modifier,
    valueRange: ClosedFloatingPointRange<Float>,
    enabled: Boolean,
    colors: LevelIndicatorColors,
    strokeWidth: Dp,
    sweepAngle: Float,
    reverseDirection: Boolean
)

Creates a LevelIndicator for screens that that control a setting such as volume with either rotating side button, rotating bezel or a Stepper.

Unit
@Composable
LevelIndicator(
    value: () -> Int,
    valueProgression: IntProgression,
    modifier: Modifier,
    enabled: Boolean,
    colors: LevelIndicatorColors,
    strokeWidth: Dp,
    sweepAngle: Float,
    reverseDirection: Boolean
)

Creates a LevelIndicator for screens that that control a setting such as volume with either rotating side button, rotating bezel or a Stepper.

Unit
@Composable
LinearProgressIndicator(
    progress: () -> Float,
    modifier: Modifier,
    colors: ProgressIndicatorColors,
    strokeWidth: Dp,
    enabled: Boolean
)

Material Design linear progress indicator.

Unit
@Composable
LinearProgressIndicatorContent(
    progress: () -> Float,
    modifier: Modifier,
    colors: ProgressIndicatorColors,
    strokeWidth: Dp,
    enabled: Boolean
)

Linear progress indicator content with no progress animations.

Unit
@Composable
ListHeader(
    modifier: Modifier,
    backgroundColor: Color,
    contentColor: Color,
    contentPadding: PaddingValues,
    content: @Composable RowScope.() -> Unit
)

A slot based composable for creating a list header item.

Unit
@Composable
ListSubHeader(
    modifier: Modifier,
    backgroundColor: Color,
    contentColor: Color,
    contentPadding: PaddingValues,
    icon: (@Composable BoxScope.() -> Unit)?,
    label: @Composable RowScope.() -> Unit
)

A two slot based composable for creating a list sub-header item.

Unit
@Composable
MaterialTheme(
    colorScheme: ColorScheme,
    typography: Typography,
    shapes: Shapes,
    motionScheme: MotionScheme,
    content: @Composable () -> Unit
)

MaterialTheme defines the styling principles from the Wear Material3 design specification which extends the Material design specification.

Unit
@Composable
OpenOnPhoneDialog(
    show: Boolean,
    onDismissRequest: () -> Unit,
    modifier: Modifier,
    curvedText: (CurvedScope.() -> Unit)?,
    colors: OpenOnPhoneDialogColors,
    properties: DialogProperties,
    durationMillis: Long,
    content: @Composable BoxScope.() -> Unit
)

A full-screen dialog that displays an animated icon with a curved text at the bottom.

Unit
@Composable
OutlinedButton(
    onClick: () -> Unit,
    modifier: Modifier,
    onLongClick: (() -> Unit)?,
    onLongClickLabel: String?,
    enabled: Boolean,
    shape: Shape,
    colors: ButtonColors,
    border: BorderStroke?,
    contentPadding: PaddingValues,
    interactionSource: MutableInteractionSource?,
    content: @Composable RowScope.() -> Unit
)

Base level Wear Material3 OutlinedButton that offers a single slot to take any content.

Unit
@Composable
OutlinedButton(
    onClick: () -> Unit,
    modifier: Modifier,
    onLongClick: (() -> Unit)?,
    onLongClickLabel: String?,
    secondaryLabel: (@Composable RowScope.() -> Unit)?,
    icon: (@Composable BoxScope.() -> Unit)?,
    enabled: Boolean,
    shape: Shape,
    colors: ButtonColors,
    border: BorderStroke?,
    contentPadding: PaddingValues,
    interactionSource: MutableInteractionSource?,
    label: @Composable RowScope.() -> Unit
)

Wear Material3 OutlinedButton that offers three slots and a specific layout for an icon, label and secondaryLabel.

Unit
@Composable
OutlinedCard(
    onClick: () -> Unit,
    modifier: Modifier,
    onLongClick: (() -> Unit)?,
    onLongClickLabel: String?,
    enabled: Boolean,
    shape: Shape,
    colors: CardColors,
    border: BorderStroke,
    contentPadding: PaddingValues,
    interactionSource: MutableInteractionSource?,
    content: @Composable ColumnScope.() -> Unit
)

Outlined Wear Material 3 Card that offers a single slot to take any content.

Unit
@Composable
OutlinedIconButton(
    onClick: () -> Unit,
    modifier: Modifier,
    onLongClick: (() -> Unit)?,
    onLongClickLabel: String?,
    enabled: Boolean,
    shapes: IconButtonShapes,
    colors: IconButtonColors,
    border: BorderStroke?,
    interactionSource: MutableInteractionSource?,
    content: @Composable BoxScope.() -> Unit
)

Wear Material OutlinedIconButton is a circular, icon-only button with a transparent background, contrasting icon color and border.

Unit
@Composable
Picker(
    state: PickerState,
    contentDescription: String?,
    modifier: Modifier,
    readOnly: Boolean,
    readOnlyLabel: (@Composable BoxScope.() -> Unit)?,
    onSelected: () -> Unit,
    spacing: Dp,
    gradientRatio: @FloatRange(from = 0.0, to = 0.5) Float,
    gradientColor: Color,
    userScrollEnabled: Boolean,
    rotaryScrollableBehavior: RotaryScrollableBehavior?,
    option: @Composable PickerScope.(index: Int) -> Unit
)

A scrollable list of items to pick from.

Unit
@Composable
PickerGroup(
    selectedPickerIndex: Int,
    onPickerSelected: (selectedIndex: Int) -> Unit,
    modifier: Modifier,
    autoCenter: Boolean,
    separator: (@Composable (Int) -> Unit)?,
    propagateMinConstraints: Boolean,
    content: PickerGroupScope.() -> Unit
)

A group of Pickers to build components where multiple pickers are required to be combined together.

Unit

This function is used to set the current value of LocalTextStyle, merging the given style with the current style values for any missing attributes.

Unit
@Composable
RadioButton(
    selected: Boolean,
    onSelect: () -> Unit,
    modifier: Modifier,
    enabled: Boolean,
    shape: Shape,
    colors: RadioButtonColors,
    contentPadding: PaddingValues,
    interactionSource: MutableInteractionSource?,
    icon: (@Composable BoxScope.() -> Unit)?,
    secondaryLabel: (@Composable RowScope.() -> Unit)?,
    label: @Composable RowScope.() -> Unit
)

The Wear Material RadioButton offers slots and a specific layout for an icon, a label and a secondaryLabel.

Unit
@Composable
ScreenScaffold(
    modifier: Modifier,
    timeText: (@Composable () -> Unit)?,
    scrollInfoProvider: ScrollInfoProvider?,
    scrollIndicator: (@Composable BoxScope.() -> Unit)?,
    content: @Composable BoxScope.() -> Unit
)

ScreenScaffold is one of the Wear Material3 scaffold components.

Unit
@Composable
ScreenScaffold(
    scrollState: ScrollState,
    modifier: Modifier,
    timeText: (@Composable () -> Unit)?,
    scrollIndicator: (@Composable BoxScope.() -> Unit)?,
    content: @Composable BoxScope.() -> Unit
)

ScreenScaffold is one of the Wear Material3 scaffold components.

Unit
@Composable
ScreenScaffold(
    edgeButton: @Composable BoxScope.() -> Unit,
    scrollInfoProvider: ScrollInfoProvider,
    modifier: Modifier,
    timeText: (@Composable () -> Unit)?,
    scrollIndicator: (@Composable BoxScope.() -> Unit)?,
    content: @Composable BoxScope.() -> Unit
)

ScreenScaffold is one of the Wear Material3 scaffold components.

Unit
@Composable
ScreenScaffold(
    scrollState: LazyListState,
    modifier: Modifier,
    timeText: (@Composable () -> Unit)?,
    scrollIndicator: (@Composable BoxScope.() -> Unit)?,
    edgeButton: (@Composable BoxScope.() -> Unit)?,
    content: @Composable BoxScope.() -> Unit
)

ScreenScaffold is one of the Wear Material3 scaffold components.

Unit
@Composable
ScreenScaffold(
    scrollState: ScalingLazyListState,
    modifier: Modifier,
    timeText: (@Composable () -> Unit)?,
    scrollIndicator: (@Composable BoxScope.() -> Unit)?,
    edgeButton: (@Composable BoxScope.() -> Unit)?,
    content: @Composable BoxScope.() -> Unit
)

ScreenScaffold is one of the Wear Material3 scaffold components.

Unit
@Composable
ScreenScaffold(
    scrollState: TransformingLazyColumnState,
    modifier: Modifier,
    timeText: (@Composable () -> Unit)?,
    scrollIndicator: (@Composable BoxScope.() -> Unit)?,
    edgeButton: (@Composable BoxScope.() -> Unit)?,
    content: @Composable BoxScope.() -> Unit
)

ScreenScaffold is one of the Wear Material3 scaffold components.

Unit
@Composable
ScrollIndicator(
    state: LazyListState,
    modifier: Modifier,
    reverseDirection: Boolean,
    positionAnimationSpec: AnimationSpec<Float>
)

A composable that displays a visual indicator of scrolling progress within a scrollable container.

Unit
@Composable
ScrollIndicator(
    state: ScalingLazyListState,
    modifier: Modifier,
    reverseDirection: Boolean,
    positionAnimationSpec: AnimationSpec<Float>
)

A composable that displays a visual indicator of scrolling progress within a scrollable container.

Unit
@Composable
ScrollIndicator(
    state: ScrollState,
    modifier: Modifier,
    reverseDirection: Boolean,
    positionAnimationSpec: AnimationSpec<Float>
)

A composable that displays a visual indicator of scrolling progress within a scrollable container.

Unit
@Composable
ScrollIndicator(
    state: TransformingLazyColumnState,
    modifier: Modifier,
    reverseDirection: Boolean,
    positionAnimationSpec: AnimationSpec<Float>
)
Unit
@Composable
SegmentedCircularProgressIndicator(
    segmentCount: @IntRange(from = 1) Int,
    segmentValue: (segmentIndex: Int) -> Boolean,
    modifier: Modifier,
    startAngle: Float,
    endAngle: Float,
    colors: ProgressIndicatorColors,
    strokeWidth: Dp,
    gapSize: Dp,
    enabled: Boolean
)

Material Design segmented circular progress indicator.

Unit
@Composable
SegmentedCircularProgressIndicator(
    segmentCount: @IntRange(from = 1) Int,
    progress: () -> Float,
    modifier: Modifier,
    allowProgressOverflow: Boolean,
    startAngle: Float,
    endAngle: Float,
    colors: ProgressIndicatorColors,
    strokeWidth: Dp,
    gapSize: Dp,
    enabled: Boolean
)

Material Design segmented circular progress indicator.

Unit
@Composable
Slider(
    value: Int,
    onValueChange: (Int) -> Unit,
    valueProgression: IntProgression,
    modifier: Modifier,
    decreaseIcon: @Composable () -> Unit,
    increaseIcon: @Composable () -> Unit,
    enabled: Boolean,
    segmented: Boolean,
    shape: Shape,
    colors: SliderColors
)

Slider allows users to make a selection from a range of values.

Unit
@Composable
Slider(
    value: Float,
    onValueChange: (Float) -> Unit,
    steps: Int,
    modifier: Modifier,
    decreaseIcon: @Composable () -> Unit,
    increaseIcon: @Composable () -> Unit,
    enabled: Boolean,
    valueRange: ClosedFloatingPointRange<Float>,
    segmented: Boolean,
    shape: Shape,
    colors: SliderColors
)

Slider allows users to make a selection from a range of values.

Unit
@Composable
SplitCheckboxButton(
    checked: Boolean,
    onCheckedChange: (Boolean) -> Unit,
    toggleContentDescription: String?,
    onContainerClick: () -> Unit,
    modifier: Modifier,
    enabled: Boolean,
    shape: Shape,
    colors: SplitCheckboxButtonColors,
    toggleInteractionSource: MutableInteractionSource?,
    containerInteractionSource: MutableInteractionSource?,
    containerClickLabel: String?,
    contentPadding: PaddingValues,
    secondaryLabel: (@Composable RowScope.() -> Unit)?,
    label: @Composable RowScope.() -> Unit
)

The Wear Material SplitCheckboxButton offers slots and a specific layout for a label and secondaryLabel.

Unit
@Composable
SplitRadioButton(
    selected: Boolean,
    onSelectionClick: () -> Unit,
    selectionContentDescription: String?,
    onContainerClick: () -> Unit,
    modifier: Modifier,
    enabled: Boolean,
    shape: Shape,
    colors: SplitRadioButtonColors,
    selectionInteractionSource: MutableInteractionSource?,
    containerInteractionSource: MutableInteractionSource?,
    containerClickLabel: String?,
    contentPadding: PaddingValues,
    secondaryLabel: (@Composable RowScope.() -> Unit)?,
    label: @Composable RowScope.() -> Unit
)

The Wear Material SplitRadioButton offers two slots and a specific layout for a label and secondaryLabel.

Unit
@Composable
SplitSwitchButton(
    checked: Boolean,
    onCheckedChange: (Boolean) -> Unit,
    toggleContentDescription: String?,
    onContainerClick: () -> Unit,
    modifier: Modifier,
    enabled: Boolean,
    shape: Shape,
    colors: SplitSwitchButtonColors,
    toggleInteractionSource: MutableInteractionSource?,
    containerInteractionSource: MutableInteractionSource?,
    containerClickLabel: String?,
    contentPadding: PaddingValues,
    secondaryLabel: (@Composable RowScope.() -> Unit)?,
    label: @Composable RowScope.() -> Unit
)

The Wear Material SplitSwitchButton offers slots and a specific layout for a label and secondary label.

Unit
@Composable
Stepper(
    value: Int,
    onValueChange: (Int) -> Unit,
    valueProgression: IntProgression,
    decreaseIcon: @Composable () -> Unit,
    increaseIcon: @Composable () -> Unit,
    modifier: Modifier,
    enabled: Boolean,
    colors: StepperColors,
    content: @Composable BoxScope.() -> Unit
)

Stepper allows users to make a selection from a range of values.

Unit
@Composable
Stepper(
    value: Float,
    onValueChange: (Float) -> Unit,
    steps: Int,
    decreaseIcon: @Composable () -> Unit,
    increaseIcon: @Composable () -> Unit,
    modifier: Modifier,
    enabled: Boolean,
    valueRange: ClosedFloatingPointRange<Float>,
    colors: StepperColors,
    content: @Composable BoxScope.() -> Unit
)

Stepper allows users to make a selection from a range of values.

Unit
@Composable
SuccessConfirmation(
    show: Boolean,
    onDismissRequest: () -> Unit,
    modifier: Modifier,
    curvedText: (CurvedScope.() -> Unit)?,
    colors: ConfirmationColors,
    properties: DialogProperties,
    durationMillis: Long,
    content: @Composable BoxScope.() -> Unit
)

Shows a Confirmation dialog with a success icon and optional short curved text.

Unit
@Composable
SwipeToDismissBox(
    state: SwipeToDismissBoxState,
    modifier: Modifier,
    backgroundScrimColor: Color,
    contentScrimColor: Color,
    backgroundKey: Any,
    contentKey: Any,
    userSwipeEnabled: Boolean,
    content: @Composable BoxScope.(isBackground: Boolean) -> Unit
)

Wear Material 3 SwipeToDismissBox that handles the swipe-to-dismiss gesture.

Unit
@Composable
SwipeToDismissBox(
    onDismissed: () -> Unit,
    modifier: Modifier,
    state: SwipeToDismissBoxState,
    backgroundScrimColor: Color,
    contentScrimColor: Color,
    backgroundKey: Any,
    contentKey: Any,
    userSwipeEnabled: Boolean,
    content: @Composable BoxScope.(isBackground: Boolean) -> Unit
)

Wear Material 3 SwipeToDismissBox that handles the swipe-to-dismiss gesture.

Unit
@Composable
SwipeToReveal(
    actions: SwipeToRevealScope.() -> Unit,
    modifier: Modifier,
    revealState: RevealState,
    actionButtonHeight: Dp,
    content: @Composable () -> Unit
)

SwipeToReveal Material composable.

Unit
@Composable
SwitchButton(
    checked: Boolean,
    onCheckedChange: (Boolean) -> Unit,
    modifier: Modifier,
    enabled: Boolean,
    shape: Shape,
    colors: SwitchButtonColors,
    contentPadding: PaddingValues,
    interactionSource: MutableInteractionSource?,
    icon: (@Composable BoxScope.() -> Unit)?,
    secondaryLabel: (@Composable RowScope.() -> Unit)?,
    label: @Composable RowScope.() -> Unit
)

The Wear Material SwitchButton offers three slots and a specific layout for an icon, a label, and a secondaryLabel.

Unit
@Composable
Text(
    text: String,
    modifier: Modifier,
    color: Color,
    fontSize: TextUnit,
    fontStyle: FontStyle?,
    fontWeight: FontWeight?,
    fontFamily: FontFamily?,
    letterSpacing: TextUnit,
    textDecoration: TextDecoration?,
    textAlign: TextAlign?,
    lineHeight: TextUnit,
    overflow: TextOverflow,
    softWrap: Boolean,
    maxLines: Int,
    minLines: Int,
    onTextLayout: (TextLayoutResult) -> Unit,
    style: TextStyle
)

High level element that displays text and provides semantics / accessibility information.

Unit
@Composable
Text(
    text: AnnotatedString,
    modifier: Modifier,
    color: Color,
    fontSize: TextUnit,
    fontStyle: FontStyle?,
    fontWeight: FontWeight?,
    fontFamily: FontFamily?,
    letterSpacing: TextUnit,
    textDecoration: TextDecoration?,
    textAlign: TextAlign?,
    lineHeight: TextUnit,
    overflow: TextOverflow,
    softWrap: Boolean,
    maxLines: Int,
    minLines: Int,
    inlineContent: Map<StringInlineTextContent>,
    onTextLayout: (TextLayoutResult) -> Unit,
    style: TextStyle
)

High level element that displays text and provides semantics / accessibility information.

Unit
@Composable
TextButton(
    onClick: () -> Unit,
    modifier: Modifier,
    onLongClick: (() -> Unit)?,
    onLongClickLabel: String?,
    enabled: Boolean,
    shapes: TextButtonShapes,
    colors: TextButtonColors,
    border: BorderStroke?,
    interactionSource: MutableInteractionSource?,
    content: @Composable BoxScope.() -> Unit
)

Wear Material TextButton is a circular, text-only button with transparent background and no border.

Unit
@Composable
TextToggleButton(
    checked: Boolean,
    onCheckedChange: (Boolean) -> Unit,
    modifier: Modifier,
    enabled: Boolean,
    colors: TextToggleButtonColors,
    interactionSource: MutableInteractionSource?,
    shapes: TextToggleButtonShapes,
    border: BorderStroke?,
    content: @Composable BoxScope.() -> Unit
)

Wear Material TextToggleButton is a filled text toggle button which switches between primary colors and tonal colors depending on checked value, and offers a single slot for text.

Unit
@RequiresApi(value = 26)
@Composable
TimePicker(
    initialTime: LocalTime,
    onTimePicked: (LocalTime) -> Unit,
    modifier: Modifier,
    timePickerType: TimePickerType,
    colors: TimePickerColors
)

A full screen TimePicker with configurable columns that allows users to select a time.

Unit
@Composable
TimeText(
    modifier: Modifier,
    curvedModifier: CurvedModifier,
    maxSweepAngle: Float,
    timeSource: TimeSource,
    timeTextStyle: TextStyle,
    contentColor: Color,
    contentPadding: PaddingValues,
    content: TimeTextScope.() -> Unit
)

Layout to show the current time and a label at the top of the screen.

Unit
@Composable
TitleCard(
    onClick: () -> Unit,
    title: @Composable RowScope.() -> Unit,
    modifier: Modifier,
    onLongClick: (() -> Unit)?,
    onLongClickLabel: String?,
    time: (@Composable () -> Unit)?,
    subtitle: (@Composable ColumnScope.() -> Unit)?,
    enabled: Boolean,
    shape: Shape,
    colors: CardColors,
    border: BorderStroke?,
    contentPadding: PaddingValues,
    interactionSource: MutableInteractionSource?,
    content: (@Composable () -> Unit)?
)

Opinionated Wear Material 3 Card that offers a specific layout to show interactive information about an application, e.g. a message.

Unit
@Composable
VerticalPageIndicator(
    pagerState: PagerState,
    modifier: Modifier,
    selectedColor: Color,
    unselectedColor: Color,
    backgroundColor: Color
)

Vertical page indicator for use with VerticalPager, representing the currently active page and the approximate number of pages.

Unit
@Composable
VerticalPagerScaffold(
    pagerState: PagerState,
    modifier: Modifier,
    pageIndicator: (@Composable BoxScope.() -> Unit)?,
    pageIndicatorAnimationSpec: AnimationSpec<Float>?,
    rotaryScrollableBehavior: RotaryScrollableBehavior?,
    content: @Composable PagerScope.(page: Int) -> Unit
)

VerticalPagerScaffold is one of the Wear Material3 scaffold components.

Color
@Composable
contentColorFor(backgroundColor: Color)

The Material color system contains pairs of colors that are typically used for the background and content color inside a component.

ColorScheme?

Creates a dynamic color scheme.

AnimatedTextFontRegistry
@Composable
@RequiresApi(value = 31)
rememberAnimatedTextFontRegistry(
    startFontVariationSettings: FontVariation.Settings,
    endFontVariationSettings: FontVariation.Settings,
    textStyle: TextStyle,
    startFontSize: TextUnit,
    endFontSize: TextUnit
)

Generates an AnimatedTextFontRegistry to use within composition.

PickerState
@Composable
rememberPickerState(
    initialNumberOfOptions: @IntRange(from = 1) Int,
    initiallySelectedIndex: @IntRange(from = 0) Int,
    shouldRepeatOptions: Boolean
)

Creates a PickerState that is remembered across compositions.

PlaceholderState

Creates a PlaceholderState that is remembered across compositions.

RevealState
@Composable
rememberRevealState(
    initialValue: RevealValue,
    anchorWidth: Dp,
    useAnchoredActions: Boolean,
    swipeDirection: SwipeDirection
)

Creates a reveal state with Material3 specs.

IndicationNodeFactory
ripple(bounded: Boolean, radius: Dp, color: Color)

Creates a Ripple using the provided values and values inferred from the theme.

IndicationNodeFactory
ripple(color: ColorProducer, bounded: Boolean, radius: Dp)

Creates a Ripple using the provided values and values inferred from the theme.

Extension functions summary

Color
ColorScheme.contentColorFor(backgroundColor: Color)

The Material color system contains pairs of colors that are typically used for the background and content color inside a component.

Unit
CurvedScope.curvedText(
    text: String,
    modifier: CurvedModifier,
    maxSweepAngle: Float,
    background: Color,
    color: Color,
    fontSize: TextUnit,
    fontFamily: FontFamily?,
    fontWeight: FontWeight?,
    fontStyle: FontStyle?,
    fontSynthesis: FontSynthesis?,
    style: CurvedTextStyle?,
    angularDirection: CurvedDirection.Angular?,
    overflow: TextOverflow
)

CurvedText is a component allowing developers to easily write curved text following the curvature a circle (usually at the edge of a circular screen).

Modifier

Reserves at least 48.dp in size to disambiguate touch interactions if the element would measure smaller.

Modifier
@Composable
Modifier.placeholder(
    placeholderState: PlaceholderState,
    shape: Shape,
    color: Color
)

Draws a placeholder shape over the top of a composable and animates a wipe off effect to remove the placeholder.

Modifier
@Composable
Modifier.placeholderShimmer(
    placeholderState: PlaceholderState,
    shape: Shape,
    color: Color
)

Modifier to draw a placeholder shimmer over a component.

Modifier
Modifier.rangeSemantics(
    value: Float,
    enabled: Boolean,
    onValueChange: (Float) -> Unit,
    valueRange: ClosedFloatingPointRange<Float>,
    steps: Int
)

Modifier to add semantics signifying progress of the Stepper/Slider.

Modifier
Modifier.scrollAway(
    scrollInfoProvider: ScrollInfoProvider,
    screenStage: () -> ScreenStage
)

Scroll an item vertically in/out of view based on scroll state provided by a scrolling list.

Modifier

Modifier to set both the size and recommended touch target for IconButton and TextButton.

Top-level properties summary

ProvidableCompositionLocal<Color>

CompositionLocal containing the preferred content color for a given position in the hierarchy.

ProvidableCompositionLocal<Boolean>

CompositionLocal that configures whether Wear Material components that have a visual size that is lower than the minimum touch target size for accessibility (such as Button) will include extra space outside the component to ensure that they are accessible.

ProvidableCompositionLocal<TextConfiguration>

CompositionLocal containing the preferred TextConfiguration that will be used by Text components by default consisting of text alignment, overflow specification and max lines.

ProvidableCompositionLocal<TextStyle>

CompositionLocal containing the preferred TextStyle that will be used by Text components by default.

Top-level functions

@Composable
fun AlertDialog(
    show: Boolean,
    onDismissRequest: () -> Unit,
    title: @Composable () -> Unit,
    modifier: Modifier = Modifier,
    icon: (@Composable () -> Unit)? = null,
    text: (@Composable () -> Unit)? = null,
    verticalArrangement: Arrangement.Vertical = AlertDialogDefaults.VerticalArrangement,
    contentPadding: PaddingValues = AlertDialogDefaults.contentPadding(),
    properties: DialogProperties = DialogProperties(),
    content: (ScalingLazyListScope.() -> Unit)? = null
): Unit

Dialogs provide important prompts in a user flow. They can require an action, communicate information, or help users accomplish a task. The dialog is scrollable by default if the content exceeds the viewport height.

This overload doesn't have any dedicated slots for buttons. It has a content slot so that the caller has flexibility in how to seek user input. In most cases, we recommend using other AlertDialog variations with 2 confirm/dismiss buttons or a single confirmation button.

Parameters
show: Boolean

A boolean indicating whether the dialog should be displayed.

onDismissRequest: () -> Unit

A lambda function to be called when the dialog is dismissed by swiping to the right or by other dismiss action.

title: @Composable () -> Unit

A slot for displaying the title of the dialog. Title should contain a summary of the dialog's purpose or content and should not exceed 3 lines of text. By default, TextOverflow.Ellipsis will be applied when text exceeds 3 lines.

modifier: Modifier = Modifier

Modifier to be applied to the dialog content.

icon: (@Composable () -> Unit)? = null

Optional slot for an icon to be shown at the top of the dialog.

text: (@Composable () -> Unit)? = null

Optional slot for displaying the message of the dialog below the title. Should contain additional text that presents further details about the dialog's purpose if the title is insufficient.

verticalArrangement: Arrangement.Vertical = AlertDialogDefaults.VerticalArrangement

The vertical arrangement of the dialog's children. There is a default padding between icon, title, and text, which will be added to the spacing specified in this verticalArrangement parameter.

contentPadding: PaddingValues = AlertDialogDefaults.contentPadding()

The padding to apply around the entire dialog's contents.

properties: DialogProperties = DialogProperties()

An optional DialogProperties object for configuring the dialog's behavior.

content: (ScalingLazyListScope.() -> Unit)? = null

A slot for additional content, displayed within a scrollable ScalingLazyColumn.

@Composable
fun AlertDialog(
    show: Boolean,
    onDismissRequest: () -> Unit,
    edgeButton: @Composable BoxScope.() -> Unit,
    title: @Composable () -> Unit,
    modifier: Modifier = Modifier,
    icon: (@Composable () -> Unit)? = null,
    text: (@Composable () -> Unit)? = null,
    verticalArrangement: Arrangement.Vertical = AlertDialogDefaults.VerticalArrangement,
    contentPadding: PaddingValues = AlertDialogDefaults.contentPaddingWithEdgeButton(),
    properties: DialogProperties = DialogProperties(),
    content: (ScalingLazyListScope.() -> Unit)? = null
): Unit

Dialogs provide important prompts in a user flow. They can require an action, communicate information, or help users accomplish a task. The dialog is scrollable by default if the content exceeds the viewport height.

This overload has a single slot for a confirm EdgeButton at the bottom of the dialog. It should be used when the user will be presented with a single acknowledgement.

Example of an AlertDialog with an icon, title, text and bottom EdgeButton:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.AccountCircle
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.wear.compose.material3.AlertDialog
import androidx.wear.compose.material3.AlertDialogDefaults
import androidx.wear.compose.material3.FilledTonalButton
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.MaterialTheme
import androidx.wear.compose.material3.Text

var showDialog by remember { mutableStateOf(false) }

Box(Modifier.fillMaxSize()) {
    FilledTonalButton(
        modifier = Modifier.align(Alignment.Center),
        onClick = { showDialog = true },
        label = { Text("Show Dialog") }
    )
}

AlertDialog(
    show = showDialog,
    onDismissRequest = { showDialog = false },
    icon = {
        Icon(
            Icons.Rounded.AccountCircle,
            modifier = Modifier.size(32.dp),
            contentDescription = null,
            tint = MaterialTheme.colorScheme.primary
        )
    },
    title = { Text("Mobile network is not currently available") },
    edgeButton = {
        AlertDialogDefaults.EdgeButton(
            onClick = {
                // Perform confirm action here
                showDialog = false
            }
        )
    }
)

Example of an AlertDialog with content groups and a bottom EdgeButton:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.material3.AlertDialog
import androidx.wear.compose.material3.AlertDialogDefaults
import androidx.wear.compose.material3.FilledTonalButton
import androidx.wear.compose.material3.SwitchButton
import androidx.wear.compose.material3.Text

var showDialog by remember { mutableStateOf(false) }
var weatherEnabled by remember { mutableStateOf(false) }
var calendarEnabled by remember { mutableStateOf(false) }

Box(Modifier.fillMaxSize()) {
    FilledTonalButton(
        modifier = Modifier.align(Alignment.Center),
        onClick = { showDialog = true },
        label = { Text("Show Dialog") }
    )
}
AlertDialog(
    show = showDialog,
    onDismissRequest = { showDialog = false },
    title = { Text("Share your location") },
    text = { Text(" The following apps have asked you to share your location") },
    edgeButton = {
        AlertDialogDefaults.EdgeButton(
            onClick = {
                // Perform confirm action here
                showDialog = false
            }
        ) {
            Text("Share once")
        }
    }
) {
    item {
        SwitchButton(
            modifier = Modifier.fillMaxWidth(),
            checked = weatherEnabled,
            onCheckedChange = { weatherEnabled = it },
            label = { Text("Weather") }
        )
    }
    item {
        SwitchButton(
            modifier = Modifier.fillMaxWidth(),
            checked = calendarEnabled,
            onCheckedChange = { calendarEnabled = it },
            label = { Text("Calendar") }
        )
    }
    item { AlertDialogDefaults.GroupSeparator() }
    item {
        FilledTonalButton(
            modifier = Modifier.fillMaxWidth(),
            onClick = {},
            label = { Text(modifier = Modifier.fillMaxWidth(), text = "Never share") }
        )
    }
    item {
        FilledTonalButton(
            modifier = Modifier.fillMaxWidth(),
            onClick = {},
            label = { Text(modifier = Modifier.fillMaxWidth(), text = "Share always") }
        )
    }
}
Parameters
show: Boolean

A boolean indicating whether the dialog should be displayed.

onDismissRequest: () -> Unit

A lambda function to be called when the dialog is dismissed by swiping to the right or by other dismiss action.

edgeButton: @Composable BoxScope.() -> Unit

Slot for an EdgeButton indicating positive sentiment. Clicking the button must remove the dialog from the composition hierarchy e.g. by setting show to false. It's recommended to use AlertDialogDefaults.EdgeButton in this slot with onClick callback. Note that when using an EdgeButton which is not Medium size, the contentPadding parameters should be specified.

title: @Composable () -> Unit

A slot for displaying the title of the dialog. Title should contain a summary of the dialog's purpose or content and should not exceed 3 lines of text.By default, TextOverflow.Ellipsis will be applied when text exceeds 3 lines.

modifier: Modifier = Modifier

Modifier to be applied to the dialog content.

icon: (@Composable () -> Unit)? = null

Optional slot for an icon to be shown at the top of the dialog.

text: (@Composable () -> Unit)? = null

Optional slot for displaying the message of the dialog below the title. Should contain additional text that presents further details about the dialog's purpose if the title is insufficient.

verticalArrangement: Arrangement.Vertical = AlertDialogDefaults.VerticalArrangement

The vertical arrangement of the dialog's children. There is a default padding between icon, title, and text, which will be added to the spacing specified in this verticalArrangement parameter.

contentPadding: PaddingValues = AlertDialogDefaults.contentPaddingWithEdgeButton()

The padding to apply around the entire dialog's contents. Ensure there is enough space for the EdgeButton, for example, using AlertDialogDefaults.contentPaddingWithEdgeButton

properties: DialogProperties = DialogProperties()

An optional DialogProperties object for configuring the dialog's behavior.

content: (ScalingLazyListScope.() -> Unit)? = null

A slot for additional content, displayed within a scrollable ScalingLazyColumn.

@Composable
fun AlertDialog(
    show: Boolean,
    onDismissRequest: () -> Unit,
    confirmButton: @Composable RowScope.() -> Unit,
    title: @Composable () -> Unit,
    modifier: Modifier = Modifier,
    dismissButton: @Composable RowScope.() -> Unit = { AlertDialogDefaults.DismissButton(onDismissRequest) },
    icon: (@Composable () -> Unit)? = null,
    text: (@Composable () -> Unit)? = null,
    verticalArrangement: Arrangement.Vertical = AlertDialogDefaults.VerticalArrangement,
    contentPadding: PaddingValues = AlertDialogDefaults.confirmDismissContentPadding(),
    properties: DialogProperties = DialogProperties(),
    content: (ScalingLazyListScope.() -> Unit)? = null
): Unit

AlertDialogs provide important prompts in a user flow. They can require an action, communicate information, or help users accomplish a task. The AlertDialog is scrollable by default if the content exceeds the viewport height.

This overload has 2 IconButtons for confirmation and cancellation, placed horizontally at the bottom of the dialog. It should be used when the user will be presented with a binary decision, to either confirm or dismiss an action.

Example of an AlertDialog with an icon, title and two buttons to confirm and dismiss:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.AccountCircle
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.wear.compose.material3.AlertDialog
import androidx.wear.compose.material3.AlertDialogDefaults
import androidx.wear.compose.material3.FilledTonalButton
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.MaterialTheme
import androidx.wear.compose.material3.Text

var showDialog by remember { mutableStateOf(false) }

Box(Modifier.fillMaxSize()) {
    FilledTonalButton(
        modifier = Modifier.align(Alignment.Center),
        onClick = { showDialog = true },
        label = { Text("Show Dialog") }
    )
}
AlertDialog(
    show = showDialog,
    onDismissRequest = { showDialog = false },
    icon = {
        Icon(
            Icons.Rounded.AccountCircle,
            modifier = Modifier.size(32.dp),
            contentDescription = null,
            tint = MaterialTheme.colorScheme.primary
        )
    },
    title = { Text("Enable Battery Saver Mode?") },
    text = { Text("Your battery is low. Turn on battery saver.") },
    confirmButton = {
        AlertDialogDefaults.ConfirmButton(
            onClick = {
                // Perform confirm action here
                showDialog = false
            }
        )
    },
    dismissButton = {
        AlertDialogDefaults.DismissButton(
            onClick = {
                // Perform dismiss action here
                showDialog = false
            }
        )
    }
)
Parameters
show: Boolean

A boolean indicating whether the dialog should be displayed.

onDismissRequest: () -> Unit

A lambda function to be called when the dialog is dismissed by swiping right (typically also called by the dismissButton).

confirmButton: @Composable RowScope.() -> Unit

A slot for a Button indicating positive sentiment. Clicking the button must remove the dialog from the composition hierarchy e.g. by setting show to false. It's recommended to use AlertDialogDefaults.ConfirmButton in this slot with onClick callback.

title: @Composable () -> Unit

A slot for displaying the title of the dialog. Title should contain a summary of the dialog's purpose or content and should not exceed 3 lines of text. By default, TextOverflow.Ellipsis will be applied when text exceeds 3 lines.

modifier: Modifier = Modifier

Modifier to be applied to the dialog content.

dismissButton: @Composable RowScope.() -> Unit = { AlertDialogDefaults.DismissButton(onDismissRequest) }

A slot for a Button indicating negative sentiment. Clicking the button must remove the dialog from the composition hierarchy e.g. by setting show to false. It's recommended to use AlertDialogDefaults.DismissButton in this slot with onClick callback.

icon: (@Composable () -> Unit)? = null

Optional slot for an icon to be shown at the top of the dialog.

text: (@Composable () -> Unit)? = null

Optional slot for displaying the message of the dialog below the title. Should contain additional text that presents further details about the dialog's purpose if the title is insufficient.

verticalArrangement: Arrangement.Vertical = AlertDialogDefaults.VerticalArrangement

The vertical arrangement of the dialog's children. There is a default padding between icon, title, and text, which will be added to the spacing specified in this verticalArrangement parameter.

contentPadding: PaddingValues = AlertDialogDefaults.confirmDismissContentPadding()

The padding to apply around the entire dialog's contents.

properties: DialogProperties = DialogProperties()

An optional DialogProperties object for configuring the dialog's behavior.

content: (ScalingLazyListScope.() -> Unit)? = null

A slot for additional content, displayed within a scrollable ScalingLazyColumn.

AlertDialogContent

@Composable
fun AlertDialogContent(
    title: @Composable () -> Unit,
    modifier: Modifier = Modifier,
    icon: (@Composable () -> Unit)? = null,
    text: (@Composable () -> Unit)? = null,
    verticalArrangement: Arrangement.Vertical = AlertDialogDefaults.VerticalArrangement,
    contentPadding: PaddingValues = AlertDialogDefaults.contentPadding(),
    content: (ScalingLazyListScope.() -> Unit)? = null
): Unit

This AlertDialogContent overload provides the content for an AlertDialog without any dedicated slots for buttons. Prefer using AlertDialog directly, which provides built-in animations and a streamlined API. This composable may be used to provide the content for an alert dialog if custom animations are required.

Parameters
title: @Composable () -> Unit

A slot for displaying the title of the dialog. Title should contain a summary of the dialog's purpose or content and should not exceed 3 lines of text. By default, TextOverflow.Ellipsis will be applied when text exceeds 3 lines.

modifier: Modifier = Modifier

Modifier to be applied to the dialog content.

icon: (@Composable () -> Unit)? = null

Optional slot for an icon to be shown at the top of the dialog.

text: (@Composable () -> Unit)? = null

Optional slot for displaying the message of the dialog below the title. Should contain additional text that presents further details about the dialog's purpose if the title is insufficient.

verticalArrangement: Arrangement.Vertical = AlertDialogDefaults.VerticalArrangement

The vertical arrangement of the dialog's children. There is a default padding between icon, title, and text, which will be added to the spacing specified in this verticalArrangement parameter.

contentPadding: PaddingValues = AlertDialogDefaults.contentPadding()

The padding to apply around the entire dialog's contents.

content: (ScalingLazyListScope.() -> Unit)? = null

A slot for additional content, displayed within a scrollable ScalingLazyColumn.

AlertDialogContent

@Composable
fun AlertDialogContent(
    edgeButton: @Composable BoxScope.() -> Unit,
    title: @Composable () -> Unit,
    modifier: Modifier = Modifier,
    icon: (@Composable () -> Unit)? = null,
    text: (@Composable () -> Unit)? = null,
    verticalArrangement: Arrangement.Vertical = AlertDialogDefaults.VerticalArrangement,
    contentPadding: PaddingValues = AlertDialogDefaults.contentPaddingWithEdgeButton(),
    content: (ScalingLazyListScope.() -> Unit)? = null
): Unit

This AlertDialogContent overload provides the content for an AlertDialog with a single EdgeButton to confirm an action. Prefer using AlertDialog directly, which provides built-in animations and a streamlined API. This composable may be used to provide the content for an alert dialog if custom animations are required.

Parameters
edgeButton: @Composable BoxScope.() -> Unit

Slot for an EdgeButton indicating positive sentiment. Clicking the button must remove the dialog from the composition hierarchy. It's recommended to use AlertDialogDefaults.EdgeButton in this slot with onClick callback. Note that when using an EdgeButton which is not Medium size, the contentPadding parameters should be specified.

title: @Composable () -> Unit

A slot for displaying the title of the dialog. Title should contain a summary of the dialog's purpose or content and should not exceed 3 lines of text. By default, TextOverflow.Ellipsis will be applied when text exceeds 3 lines.

modifier: Modifier = Modifier

Modifier to be applied to the dialog content.

icon: (@Composable () -> Unit)? = null

Optional slot for an icon to be shown at the top of the dialog.

text: (@Composable () -> Unit)? = null

Optional slot for displaying the message of the dialog below the title. Should contain additional text that presents further details about the dialog's purpose if the title is insufficient.

verticalArrangement: Arrangement.Vertical = AlertDialogDefaults.VerticalArrangement

The vertical arrangement of the dialog's children. There is a default padding between icon, title, and text, which will be added to the spacing specified in this verticalArrangement parameter.

contentPadding: PaddingValues = AlertDialogDefaults.contentPaddingWithEdgeButton()

The padding to apply around the entire dialog's contents. Ensure there is enough space for the EdgeButton, for example, using AlertDialogDefaults.contentPaddingWithEdgeButton

content: (ScalingLazyListScope.() -> Unit)? = null

A slot for additional content, displayed within a scrollable ScalingLazyColumn.

AlertDialogContent

@Composable
fun AlertDialogContent(
    confirmButton: @Composable RowScope.() -> Unit,
    title: @Composable () -> Unit,
    dismissButton: @Composable RowScope.() -> Unit,
    modifier: Modifier = Modifier,
    icon: (@Composable () -> Unit)? = null,
    text: (@Composable () -> Unit)? = null,
    verticalArrangement: Arrangement.Vertical = AlertDialogDefaults.VerticalArrangement,
    contentPadding: PaddingValues = AlertDialogDefaults.confirmDismissContentPadding(),
    content: (ScalingLazyListScope.() -> Unit)? = null
): Unit

This AlertDialogContent overload provides the content for an AlertDialog with 2 buttons to confirm or dismiss an action. Prefer using AlertDialog directly, which provides built-in animations and a streamlined API. This composable may be used to provide the content for an alert dialog if custom animations are required.

Parameters
confirmButton: @Composable RowScope.() -> Unit

A slot for a Button indicating positive sentiment. Clicking the button must remove the dialog from the composition hierarchy. It's recommended to use AlertDialogDefaults.ConfirmButton in this slot with onClick callback.

title: @Composable () -> Unit

A slot for displaying the title of the dialog. Title should contain a summary of the dialog's purpose or content and should not exceed 3 lines of text. By default, TextOverflow.Ellipsis will be applied when text exceeds 3 lines.

dismissButton: @Composable RowScope.() -> Unit

A slot for a Button indicating negative sentiment. Clicking the button must remove the dialog from the composition hierarchy. It's recommended to use AlertDialogDefaults.DismissButton in this slot with onClick callback.

modifier: Modifier = Modifier

Modifier to be applied to the dialog content.

icon: (@Composable () -> Unit)? = null

Optional slot for an icon to be shown at the top of the dialog.

text: (@Composable () -> Unit)? = null

Optional slot for displaying the message of the dialog below the title. Should contain additional text that presents further details about the dialog's purpose if the title is insufficient.

verticalArrangement: Arrangement.Vertical = AlertDialogDefaults.VerticalArrangement

The vertical arrangement of the dialog's children. There is a default padding between icon, title, and text, which will be added to the spacing specified in this verticalArrangement parameter.

contentPadding: PaddingValues = AlertDialogDefaults.confirmDismissContentPadding()

The padding to apply around the entire dialog's contents.

content: (ScalingLazyListScope.() -> Unit)? = null

A slot for additional content, displayed within a scrollable ScalingLazyColumn.

@Composable
@RequiresApi(value = 31)
fun AnimatedText(
    text: String,
    fontRegistry: AnimatedTextFontRegistry,
    progressFraction: () -> Float,
    modifier: Modifier = Modifier,
    contentAlignment: Alignment = Alignment.Center
): Unit

A composable that displays an animated text.

AnimatedText can be used to animate a text along font variation axes and size. It requires an AnimatedTextFontRegistry to improve performance.

AnimatedTextFontRegistry can be generated using rememberAnimatedTextFontRegistry method, which requires start and end font variation axes, and start and end font sizes for the animation.

Start of the animation is when the animatable is at 0f and end of the animation is when the animatable is at 1f. Current animation progress is provided by the progressFraction function. This should be between 0f and 1f, but might go beyond in some cases such as overshooting spring animations.

Example of a one-shot animation with AnimatedText

import androidx.compose.animation.core.Animatable
import androidx.compose.foundation.clickable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontVariation
import androidx.compose.ui.unit.sp
import androidx.wear.compose.material3.AnimatedText
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.rememberAnimatedTextFontRegistry

val scope = rememberCoroutineScope()
val animatable = remember { Animatable(0f) }
val animate = {
    scope.launch {
        // Animate from 0 to 1 and then back to 0.
        animatable.animateTo(1f)
        animatable.animateTo(0f)
    }
}
val animatedTextFontRegistry =
    rememberAnimatedTextFontRegistry(
        // Variation axes at the start of the animation, width 10, weight 200
        startFontVariationSettings =
            FontVariation.Settings(
                FontVariation.width(10f),
                FontVariation.weight(200),
            ),
        // Variation axes at the end of the animation, width 100, weight 500
        endFontVariationSettings =
            FontVariation.Settings(
                FontVariation.width(100f),
                FontVariation.weight(500),
            ),
        startFontSize = 30.sp,
        endFontSize = 40.sp,
    )
AnimatedText(
    text = "Hello!",
    fontRegistry = animatedTextFontRegistry,
    // Content alignment anchors the animation at the vertical center, expanding horizontally
    contentAlignment = Alignment.CenterStart,
    progressFraction = { animatable.value },
    modifier = Modifier.clickable(onClick = { animate() })
)
LaunchedEffect(Unit) { animate() }

Example of an animation in response to a button press with AnimatedText

import androidx.compose.animation.core.Animatable
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontVariation
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.wear.compose.material3.AnimatedText
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.rememberAnimatedTextFontRegistry

val scope = rememberCoroutineScope()
val animatedTextFontRegistry =
    rememberAnimatedTextFontRegistry(
        // Variation axes at the start of the animation, width 10, weight 200
        startFontVariationSettings =
            FontVariation.Settings(
                FontVariation.width(10f),
                FontVariation.weight(200),
            ),
        // Variation axes at the end of the animation, width 100, weight 500
        endFontVariationSettings =
            FontVariation.Settings(
                FontVariation.width(100f),
                FontVariation.weight(500),
            ),
        startFontSize = 30.sp,
        endFontSize = 30.sp,
    )
val number = remember { mutableIntStateOf(0) }
val textAnimatable = remember { Animatable(0f) }
Row(verticalAlignment = Alignment.CenterVertically) {
    Button(
        modifier = Modifier.padding(horizontal = 16.dp),
        onClick = {
            number.value -= 1
            scope.launch {
                textAnimatable.animateTo(1f)
                textAnimatable.animateTo(0f)
            }
        },
        label = { Text("-") }
    )
    AnimatedText(
        text = "${number.value}",
        fontRegistry = animatedTextFontRegistry,
        progressFraction = { textAnimatable.value },
    )
    Button(
        modifier = Modifier.padding(horizontal = 16.dp),
        onClick = {
            number.value += 1
            scope.launch {
                textAnimatable.animateTo(1f)
                textAnimatable.animateTo(0f)
            }
        },
        label = { Text("+") }
    )
}

Example showing how AnimatedTextFontRegistry can be reused and shared between two AnimatedText composables

import androidx.compose.animation.core.Animatable
import androidx.compose.foundation.layout.Column
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.text.font.FontVariation
import androidx.compose.ui.unit.sp
import androidx.wear.compose.material3.AnimatedText
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.rememberAnimatedTextFontRegistry

val animatedTextFontRegistry =
    rememberAnimatedTextFontRegistry(
        // Variation axes at the start of the animation, width 50, weight 300
        startFontVariationSettings =
            FontVariation.Settings(
                FontVariation.width(50f),
                FontVariation.weight(300),
            ),
        // Variation axes at the end of the animation are the same as the start axes
        endFontVariationSettings =
            FontVariation.Settings(
                FontVariation.width(50f),
                FontVariation.weight(300),
            ),
        startFontSize = 15.sp,
        endFontSize = 25.sp,
    )
val firstAnimatable = remember { Animatable(0f) }
val secondAnimatable = remember { Animatable(0f) }
Column(horizontalAlignment = Alignment.CenterHorizontally) {
    AnimatedText(
        text = "Top Text",
        fontRegistry = animatedTextFontRegistry,
        progressFraction = { firstAnimatable.value },
    )
    AnimatedText(
        text = "Bottom Text",
        fontRegistry = animatedTextFontRegistry,
        progressFraction = { secondAnimatable.value },
    )
}
LaunchedEffect(Unit) {
    firstAnimatable.animateTo(1f)
    firstAnimatable.animateTo(0f)
    secondAnimatable.animateTo(1f)
    secondAnimatable.animateTo(0f)
}
Parameters
text: String

The text to be displayed.

fontRegistry: AnimatedTextFontRegistry

The font registry to be used to animate the text.

progressFraction: () -> Float

A provider for the current state of the animation. Provided value should be between 0f and 1f, but might go beyond in some cases such as overshooting spring animations.

modifier: Modifier = Modifier

Modifier to be applied to the composable.

contentAlignment: Alignment = Alignment.Center

Alignment within the bounds of the Canvas.

@Composable
fun AppCard(
    onClick: () -> Unit,
    appName: @Composable RowScope.() -> Unit,
    title: @Composable RowScope.() -> Unit,
    modifier: Modifier = Modifier,
    onLongClick: (() -> Unit)? = null,
    onLongClickLabel: String? = null,
    enabled: Boolean = true,
    shape: Shape = CardDefaults.shape,
    colors: CardColors = CardDefaults.cardColors(),
    border: BorderStroke? = null,
    contentPadding: PaddingValues = CardDefaults.ContentPadding,
    interactionSource: MutableInteractionSource? = null,
    appImage: (@Composable RowScope.() -> Unit)? = null,
    time: (@Composable RowScope.() -> Unit)? = null,
    content: @Composable ColumnScope.() -> Unit
): Unit

Opinionated Wear Material 3 Card that offers a specific 5 slot layout to show information about an application, e.g. a notification. AppCards are designed to show interactive elements from multiple applications. They will typically be used by the system UI, e.g. for showing a list of notifications from different applications. However it could also be adapted by individual application developers to show information about different parts of their application.

The first row of the layout has three slots, 1) a small optional application Image or Icon of size CardDefaults.AppImageSizexCardDefaults.AppImageSize dp, 2) an application name (emphasised with the CardColors.appColor() color), it is expected to be a short start aligned Text composable, and 3) the time that the application activity has occurred which will be shown on the top row of the card, this is expected to be an end aligned Text composable showing a time relevant to the contents of the Card.

The second row shows a title, this is expected to be a single row of start aligned Text.

The rest of the Card contains the content which can be either Text or an Image. If the content is text it can be single or multiple line and is expected to be Top and Start aligned.

If more than one composable is provided in the content slot it is the responsibility of the caller to determine how to layout the contents, e.g. provide either a row or a column.

AppCard scales itself appropriately when used within the scope of a TransformingLazyColumn.

Example of an AppCard:

import androidx.wear.compose.material3.AppCard
import androidx.wear.compose.material3.Card
import androidx.wear.compose.material3.Text

AppCard(
    onClick = { /* Do something */ },
    appName = { Text("App name") },
    title = { Text("Card title") },
    time = { Text("Now") },
) {
    Text("Card content")
}

Example of an AppCard with icon:

import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.semantics.contentDescription
import androidx.wear.compose.material3.AppCard
import androidx.wear.compose.material3.Card
import androidx.wear.compose.material3.CardDefaults
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.MaterialTheme
import androidx.wear.compose.material3.Text

AppCard(
    onClick = { /* Do something */ },
    appName = { Text("App name") },
    appImage = {
        Icon(
            painter = painterResource(id = android.R.drawable.star_big_off),
            contentDescription = "Star icon",
            modifier =
                Modifier.size(CardDefaults.AppImageSize)
                    .wrapContentSize(align = Alignment.Center),
            tint = MaterialTheme.colorScheme.primary
        )
    },
    title = { Text("Card title") },
    time = { Text("Now") },
) {
    Text("Card content")
}

Example of an AppCard with image content:

import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.unit.dp
import androidx.wear.compose.material3.AppCard
import androidx.wear.compose.material3.Card
import androidx.wear.compose.material3.CardDefaults
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.MaterialTheme
import androidx.wear.compose.material3.Text

val configuration = LocalConfiguration.current
// Add padding to the end of the image in order to maintain the correct proportions
// between the image and the card.
val imageEndPaddingDp = (0.15f * configuration.screenWidthDp).dp
AppCard(
    onClick = { /* Do something */ },
    appName = { Text("App name") },
    appImage = {
        Icon(
            painter = painterResource(id = android.R.drawable.star_big_off),
            contentDescription = "Star icon",
            modifier =
                Modifier.size(CardDefaults.AppImageSize)
                    .wrapContentSize(align = Alignment.Center),
            tint = MaterialTheme.colorScheme.primary
        )
    },
    title = { Text("With image") },
    time = { Text("Now") },
) {
    Spacer(modifier = Modifier.height(4.dp))
    Row(modifier = Modifier.fillMaxWidth()) {
        Image(
            modifier =
                Modifier.weight(1f).aspectRatio(16f / 9f).clip(RoundedCornerShape(16.dp)),
            painter = painterResource(id = R.drawable.card_content_image),
            contentScale = ContentScale.Crop,
            contentDescription = null
        )
        Spacer(modifier = Modifier.width(imageEndPaddingDp))
    }
}

Example of an outlined AppCard:

import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.ui.Modifier
import androidx.compose.ui.semantics.contentDescription
import androidx.wear.compose.material3.AppCard
import androidx.wear.compose.material3.Card
import androidx.wear.compose.material3.CardDefaults
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.Text

AppCard(
    onClick = { /* Do something */ },
    appName = { Text("App name") },
    appImage = {
        Icon(
            Icons.Filled.Favorite,
            contentDescription = "Favorite icon",
            modifier = Modifier.size(CardDefaults.AppImageSize)
        )
    },
    title = { Text("App card") },
    time = { Text("Now") },
    colors = CardDefaults.outlinedCardColors(),
    border = CardDefaults.outlinedCardBorder(),
) {
    Text("Card content")
}

For more information, see the Cards guide.

Parameters
onClick: () -> Unit

Will be called when the user clicks the card

appName: @Composable RowScope.() -> Unit

A slot for displaying the application name, expected to be a single line of start aligned text of Typography.labelSmall

title: @Composable RowScope.() -> Unit

A slot for displaying the title of the card, expected to be one or two lines of start aligned text of Typography.titleMedium

modifier: Modifier = Modifier

Modifier to be applied to the card

onLongClick: (() -> Unit)? = null

Called when this card is long clicked (long-pressed). When this callback is set, onLongClickLabel should be set as well.

onLongClickLabel: String? = null

Semantic / accessibility label for the onLongClick action.

enabled: Boolean = true

Controls the enabled state of the card. When false, this card will not be clickable and there will be no ripple effect on click. Wear cards do not have any specific elevation or alpha differences when not enabled - they are simply not clickable.

shape: Shape = CardDefaults.shape

Defines the card's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material Theme

colors: CardColors = CardDefaults.cardColors()

CardColors that will be used to resolve the colors used for this card in different states. See CardDefaults.cardColors.

border: BorderStroke? = null

A BorderStroke object which is used for drawing outlines.

contentPadding: PaddingValues = CardDefaults.ContentPadding

The spacing values to apply internally between the container and the content

interactionSource: MutableInteractionSource? = null

an optional hoisted MutableInteractionSource for observing and emitting Interactions for this card. You can use this to change the card's appearance or preview the card in different states. Note that if null is provided, interactions will still happen internally.

appImage: (@Composable RowScope.() -> Unit)? = null

A slot for a small (CardDefaults.AppImageSizexCardDefaults.AppImageSize ) Image associated with the application.

time: (@Composable RowScope.() -> Unit)? = null

A slot for displaying the time relevant to the contents of the card, expected to be a short piece of end aligned text of Typography.labelSmall.

content: @Composable ColumnScope.() -> Unit

The main slot for a content of this card

@Composable
fun AppScaffold(
    modifier: Modifier = Modifier,
    timeText: @Composable () -> Unit = { TimeText { time() } },
    content: @Composable BoxScope.() -> Unit
): Unit

AppScaffold is one of the Wear Material3 scaffold components.

The scaffold components 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.

Example of using AppScaffold and ScreenScaffold:

import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.Modifier
import androidx.wear.compose.foundation.lazy.ScalingLazyColumn
import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState
import androidx.wear.compose.material3.AppScaffold
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.ScreenScaffold
import androidx.wear.compose.material3.Text

// Declare just one [AppScaffold] per app such as in the activity.
// [AppScaffold] allows static screen elements (i.e. [TimeText]) to remain visible
// during in-app transitions such as swipe-to-dismiss.
AppScaffold {
    // Define the navigation hierarchy within the AppScaffold,
    // such as using SwipeDismissableNavHost.
    // For this sample, we will define a single screen inline.
    val listState = rememberScalingLazyListState()

    // By default, ScreenScaffold will handle transitions showing/hiding ScrollIndicator
    // and showing/hiding/scrolling away TimeText.
    ScreenScaffold(scrollState = listState) {
        ScalingLazyColumn(state = listState, modifier = Modifier.fillMaxSize()) {
            items(10) {
                Button(
                    onClick = {},
                    label = { Text("Item ${it + 1}") },
                )
            }
        }
    }
}
Parameters
modifier: Modifier = Modifier

The modifier for the top level of the scaffold.

timeText: @Composable () -> Unit = { TimeText { time() } }

The default time (and potentially status message) to display at the top middle of the screen in this app. When AppScaffold is used in combination with ScreenScaffold, the time text will be scrolled away and shown/hidden according to the scroll state of the screen.

content: @Composable BoxScope.() -> Unit

The main content for this application.

ArcProgressIndicator

@Composable
fun ArcProgressIndicator(
    startAngle: Float = ArcProgressIndicatorDefaults.IndeterminateStartAngle,
    endAngle: Float = ArcProgressIndicatorDefaults.IndeterminateEndAngle,
    modifier: Modifier = Modifier,
    angularDirection: AngularDirection = AngularDirection.CounterClockwise,
    colors: ProgressIndicatorColors = ProgressIndicatorDefaults.colors(),
    strokeWidth: Dp = ArcProgressIndicatorDefaults.IndeterminateStrokeWidth,
    gapSize: Dp = ArcProgressIndicatorDefaults.calculateRecommendedGapSize(strokeWidth)
): Unit

Indeterminate Material Design arc progress indicator.

Indeterminate progress indicator expresses an unspecified wait time and animates indefinitely. This overload provides a variation over the usual circular spinner by allowing the start and end angles to be specified.

Example of indeterminate arc progress indicator:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.material3.ArcProgressIndicator
import androidx.wear.compose.material3.ArcProgressIndicatorDefaults
import androidx.wear.compose.material3.ProgressIndicatorDefaults

Box(modifier = Modifier.fillMaxSize()) {
    ArcProgressIndicator(
        modifier =
            Modifier.align(Alignment.Center)
                .size(ArcProgressIndicatorDefaults.recommendedIndeterminateDiameter),
    )
}
Parameters
startAngle: Float = ArcProgressIndicatorDefaults.IndeterminateStartAngle

the start angle of this progress indicator arc (specified in degrees). It is recommended to use ArcProgressIndicatorDefaults.IndeterminateStartAngle. Measured clockwise from the three o'clock position.

endAngle: Float = ArcProgressIndicatorDefaults.IndeterminateEndAngle

the end angle of this progress indicator arc (specified in degrees). It is recommended to use ArcProgressIndicatorDefaults.IndeterminateEndAngle. Measured clockwise from the three o'clock position.

modifier: Modifier = Modifier

Modifier to be applied to the ArcProgressIndicator.

angularDirection: AngularDirection = AngularDirection.CounterClockwise

Determines whether the animation is in the clockwise or counter-clockwise direction.

colors: ProgressIndicatorColors = ProgressIndicatorDefaults.colors()

ProgressIndicatorColors that will be used to resolve the indicator and track color for this progress indicator.

strokeWidth: Dp = ArcProgressIndicatorDefaults.IndeterminateStrokeWidth

The stroke width for the progress indicator. The recommended value is ArcProgressIndicatorDefaults.IndeterminateStrokeWidth.

gapSize: Dp = ArcProgressIndicatorDefaults.calculateRecommendedGapSize(strokeWidth)

The size (in Dp) of the gap between the ends of the progress indicator and the track. The stroke end caps are not included in this distance.

@Composable
fun Button(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    onLongClick: (() -> Unit)? = null,
    onLongClickLabel: String? = null,
    enabled: Boolean = true,
    shape: Shape = ButtonDefaults.shape,
    colors: ButtonColors = ButtonDefaults.buttonColors(),
    border: BorderStroke? = null,
    contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
    interactionSource: MutableInteractionSource? = null,
    content: @Composable RowScope.() -> Unit
): Unit

Base level Wear Material3 Button that offers a single slot to take any content. Used as the container for more opinionated Button components that take specific content such as icons and labels.

The Button is stadium-shaped by default and its standard height is designed to take 2 lines of text of Typography.labelMedium style. With localisation and/or large font sizes, the text can extend to a maximum of 3 lines in which case, the Button height adjusts to accommodate the contents.

Button takes the ButtonDefaults.buttonColors color scheme by default, with colored background, contrasting content color and no border. This is a high-emphasis button for the primary, most important or most common action on a screen.

Other recommended buttons with ButtonColors for different levels of emphasis are: FilledTonalButton which defaults to ButtonDefaults.filledTonalButtonColors, OutlinedButton which defaults to ButtonDefaults.outlinedButtonColors and ChildButton which defaults to ButtonDefaults.childButtonColors. Buttons can also take an image background using ButtonDefaults.imageBackgroundButtonColors.

Button can be enabled or disabled. A disabled button will not respond to click events.

Button scales itself appropriately when used within the scope of a TransformingLazyColumn.

Example of a Button:

import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.Text

Button(onClick = { /* Do something */ }, label = { Text("Simple Button") }, modifier = modifier)
Parameters
onClick: () -> Unit

Will be called when the user clicks the button

modifier: Modifier = Modifier

Modifier to be applied to the button

onLongClick: (() -> Unit)? = null

Called when this button is long clicked (long-pressed). When this callback is set, onLongClickLabel should be set as well.

onLongClickLabel: String? = null

Semantic / accessibility label for the onLongClick action.

enabled: Boolean = true

Controls the enabled state of the button. When false, this button will not be clickable

shape: Shape = ButtonDefaults.shape

Defines the button's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material3 Theme

colors: ButtonColors = ButtonDefaults.buttonColors()

ButtonColors that will be used to resolve the background and content color for this button in different states. See ButtonDefaults.buttonColors.

border: BorderStroke? = null

Optional BorderStroke that will be used to resolve the border for this button in different states.

contentPadding: PaddingValues = ButtonDefaults.ContentPadding

The spacing values to apply internally between the container and the content

interactionSource: MutableInteractionSource? = null

an optional hoisted MutableInteractionSource for observing and emitting Interactions for this button. You can use this to change the button's appearance or preview the button in different states. Note that if null is provided, interactions will still happen internally.

content: @Composable RowScope.() -> Unit

Slot for composable body content displayed on the Button

@Composable
fun Button(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    onLongClick: (() -> Unit)? = null,
    onLongClickLabel: String? = null,
    secondaryLabel: (@Composable RowScope.() -> Unit)? = null,
    icon: (@Composable BoxScope.() -> Unit)? = null,
    enabled: Boolean = true,
    shape: Shape = ButtonDefaults.shape,
    colors: ButtonColors = ButtonDefaults.buttonColors(),
    border: BorderStroke? = null,
    contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
    interactionSource: MutableInteractionSource? = null,
    label: @Composable RowScope.() -> Unit
): Unit

Wear Material3 Button that offers three slots and a specific layout for an icon, label and secondaryLabel. The icon and secondaryLabel are optional. The items are laid out with the icon, if provided, at the start of a row, with a column next containing the two label slots.

The Button is stadium-shaped by default and its standard height is designed to take 2 lines of text of Typography.labelMedium style - either a two-line label or both a single line label and a secondary label. With localisation and/or large font sizes, the Button height adjusts to accommodate the contents. The label and secondary label should be consistently aligned.

If a icon is provided then the labels should be "start" aligned, e.g. left aligned in ltr so that the text starts next to the icon.

Button takes the ButtonDefaults.buttonColors color scheme by default, with colored background, contrasting content color and no border. This is a high-emphasis button for the primary, most important or most common action on a screen.

Other recommended buttons with ButtonColors for different levels of emphasis are: FilledTonalButton which defaults to ButtonDefaults.filledTonalButtonColors, OutlinedButton which defaults to ButtonDefaults.outlinedButtonColors and ChildButton which defaults to ButtonDefaults.childButtonColors. Buttons can also take an image background using ButtonDefaults.imageBackgroundButtonColors.

Button can be enabled or disabled. A disabled button will not respond to click events.

Button scales itself appropriately when used within the scope of a TransformingLazyColumn.

Example of a Button with an icon and secondary label:

import androidx.compose.foundation.layout.size
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.ButtonDefaults
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.Text

Button(
    onClick = { /* Do something */ },
    label = { Text("Button") },
    secondaryLabel = { Text("Secondary label") },
    icon = {
        Icon(
            painter = painterResource(R.drawable.ic_favorite_rounded),
            contentDescription = "Favorite icon",
            modifier = Modifier.size(ButtonDefaults.IconSize)
        )
    },
    modifier = modifier
)

Example of a Button with a large icon and adjusted content padding:

import androidx.compose.foundation.layout.size
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.ButtonDefaults
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.Text

// When customising the icon size, it is recommended to also specify
// the associated content padding
Button(
    onClick = { /* Do something */ },
    enabled = enabled,
    label = { Text("Button") },
    secondaryLabel = { Text("Secondary label") },
    icon = {
        Icon(
            painter = painterResource(R.drawable.ic_favorite_rounded),
            contentDescription = "Favorite icon",
            modifier = Modifier.size(ButtonDefaults.LargeIconSize)
        )
    },
    contentPadding = ButtonDefaults.ButtonWithLargeIconContentPadding,
    modifier = modifier
)

Example of a Button with an extra large icon and adjusted content padding:

import androidx.compose.foundation.layout.size
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.ButtonDefaults
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.Text

// When customising the icon size, it is recommended to also specify
// the associated content padding
Button(
    onClick = { /* Do something */ },
    enabled = enabled,
    label = { Text("Button") },
    secondaryLabel = { Text("Secondary label") },
    icon = {
        Icon(
            painter = painterResource(R.drawable.ic_favorite_rounded),
            contentDescription = "Favorite icon",
            modifier = Modifier.size(ButtonDefaults.ExtraLargeIconSize)
        )
    },
    contentPadding = ButtonDefaults.ButtonWithExtraLargeIconContentPadding,
    modifier = modifier
)
Parameters
onClick: () -> Unit

Will be called when the user clicks the button

modifier: Modifier = Modifier

Modifier to be applied to the button

onLongClick: (() -> Unit)? = null

Called when this button is long clicked (long-pressed). When this callback is set, onLongClickLabel should be set as well.

onLongClickLabel: String? = null

Semantic / accessibility label for the onLongClick action.

secondaryLabel: (@Composable RowScope.() -> Unit)? = null

A slot for providing the button's secondary label. The contents are expected to be text which is "start" aligned if there is an icon preset and "start" or "center" aligned if not. label and secondaryLabel contents should be consistently aligned.

icon: (@Composable BoxScope.() -> Unit)? = null

A slot for providing the button's icon. The contents are expected to be a horizontally and vertically aligned icon of size ButtonDefaults.IconSize or ButtonDefaults.LargeIconSize.

enabled: Boolean = true

Controls the enabled state of the button. When false, this button will not be clickable

shape: Shape = ButtonDefaults.shape

Defines the button's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material3 Theme

colors: ButtonColors = ButtonDefaults.buttonColors()

ButtonColors that will be used to resolve the background and content color for this button in different states. See ButtonDefaults.buttonColors. Defaults to ButtonDefaults.buttonColors

border: BorderStroke? = null

Optional BorderStroke that will be used to resolve the button border in different states.

contentPadding: PaddingValues = ButtonDefaults.ContentPadding

The spacing values to apply internally between the container and the content

interactionSource: MutableInteractionSource? = null

an optional hoisted MutableInteractionSource for observing and emitting Interactions for this button. You can use this to change the button's appearance or preview the button in different states. Note that if null is provided, interactions will still happen internally.

label: @Composable RowScope.() -> Unit

A slot for providing the button's main label. The contents are expected to be text which is "start" aligned if there is an icon preset and "start" or "center" aligned if not.

@Composable
fun ButtonGroup(
    modifier: Modifier = Modifier,
    spacing: Dp = ButtonGroupDefaults.Spacing,
    expansionWidth: Dp = ButtonGroupDefaults.ExpansionWidth,
    contentPadding: PaddingValues = ButtonGroupDefaults.fullWidthPaddings(),
    verticalAlignment: Alignment.Vertical = Alignment.CenterVertically,
    content: ButtonGroupScope.() -> Unit
): Unit

Layout component to implement an expressive group of buttons, that react to touch by growing the touched button, (while the neighbor(s) shrink to accommodate and keep the group width constant).

Example of a ButtonGroup:

import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.ButtonGroup
import androidx.wear.compose.material3.Text

val interactionSourceLeft = remember { MutableInteractionSource() }
val interactionSourceRight = remember { MutableInteractionSource() }
Box(Modifier.size(300.dp), contentAlignment = Alignment.Center) {
    ButtonGroup(Modifier.fillMaxWidth()) {
        buttonGroupItem(interactionSource = interactionSourceLeft) {
            Button(onClick = {}, interactionSource = interactionSourceLeft) {
                Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Text("L") }
            }
        }
        buttonGroupItem(interactionSource = interactionSourceRight) {
            Button(onClick = {}, interactionSource = interactionSourceRight) {
                Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Text("R") }
            }
        }
    }
}
Parameters
modifier: Modifier = Modifier

Modifier to be applied to the button group

spacing: Dp = ButtonGroupDefaults.Spacing

the amount of spacing between buttons

expansionWidth: Dp = ButtonGroupDefaults.ExpansionWidth

how much buttons grow when pressed

contentPadding: PaddingValues = ButtonGroupDefaults.fullWidthPaddings()

The spacing values to apply internally between the container and the content

verticalAlignment: Alignment.Vertical = Alignment.CenterVertically

the vertical alignment of the button group's children.

content: ButtonGroupScope.() -> Unit

the content and properties of each button. The Ux guidance is to use no more than 3 buttons within a ButtonGroup.

@Composable
fun Card(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    onLongClick: (() -> Unit)? = null,
    onLongClickLabel: String? = null,
    enabled: Boolean = true,
    shape: Shape = CardDefaults.shape,
    colors: CardColors = CardDefaults.cardColors(),
    border: BorderStroke? = null,
    contentPadding: PaddingValues = CardDefaults.ContentPadding,
    interactionSource: MutableInteractionSource? = null,
    content: @Composable ColumnScope.() -> Unit
): Unit

Base level Wear Material 3 Card that offers a single slot to take any content.

Is used as the container for more opinionated Card components that take specific content such as icons, images, titles, subtitles and labels.

The Card is Rectangle shaped rounded corners by default.

Cards can be enabled or disabled. A disabled card will not respond to click events.

Card scales itself appropriately when used within the scope of a TransformingLazyColumn.

Example of a Card:

import androidx.wear.compose.material3.Card
import androidx.wear.compose.material3.Text

Card(
    onClick = { /* Do something */ },
) {
    Text("Card")
}

Example of Card with onLongClick:

import androidx.wear.compose.material3.Card
import androidx.wear.compose.material3.Text

Card(
    onClick = { /* Do something */ },
    onLongClick = onLongClickHandler,
    onLongClickLabel = "Long click"
) {
    Text("Card with long click")
}

For more information, see the Cards Wear OS Material design guide.

Parameters
onClick: () -> Unit

Will be called when the user clicks the card

modifier: Modifier = Modifier

Modifier to be applied to the card

onLongClick: (() -> Unit)? = null

Called when this card is long clicked (long-pressed). When this callback is set, onLongClickLabel should be set as well.

onLongClickLabel: String? = null

Semantic / accessibility label for the onLongClick action.

enabled: Boolean = true

Controls the enabled state of the card. When false, this card will not be clickable and there will be no ripple effect on click. Wear cards do not have any specific elevation or alpha differences when not enabled - they are simply not clickable.

shape: Shape = CardDefaults.shape

Defines the card's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material Theme

colors: CardColors = CardDefaults.cardColors()

CardColors that will be used to resolve the colors used for this card in different states. See CardDefaults.cardColors.

border: BorderStroke? = null

A BorderStroke object which is used for drawing outlines.

contentPadding: PaddingValues = CardDefaults.ContentPadding

The spacing values to apply internally between the container and the content

interactionSource: MutableInteractionSource? = null

an optional hoisted MutableInteractionSource for observing and emitting Interactions for this card. You can use this to change the card's appearance or preview the card in different states. Note that if null is provided, interactions will still happen internally.

content: @Composable ColumnScope.() -> Unit

The main slot for a content of this card

@Composable
fun CheckboxButton(
    checked: Boolean,
    onCheckedChange: (Boolean) -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    shape: Shape = CheckboxButtonDefaults.checkboxButtonShape,
    colors: CheckboxButtonColors = CheckboxButtonDefaults.checkboxButtonColors(),
    contentPadding: PaddingValues = CheckboxButtonDefaults.ContentPadding,
    interactionSource: MutableInteractionSource? = null,
    icon: (@Composable BoxScope.() -> Unit)? = null,
    secondaryLabel: (@Composable RowScope.() -> Unit)? = null,
    label: @Composable RowScope.() -> Unit
): Unit

The Wear Material CheckboxButton offers three slots and a specific layout for an icon, a label, and a secondaryLabel. The icon and secondaryLabel are optional. The items are laid out in a row with the optional icon at the start and a column containing the two label slots in the middle.

The CheckboxButton is Stadium shaped. The label should take no more than 3 lines of text. The secondary label should take no more than 2 lines of text. With localisation and/or large font sizes, the CheckboxButton height adjusts to accommodate the contents. The label and secondary label are start aligned by default.

Samples: Example of a CheckboxButton:

import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.text.style.TextOverflow
import androidx.wear.compose.material3.CheckboxButton
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.Text

var checked by remember { mutableStateOf(true) }
CheckboxButton(
    label = { Text("Checkbox Button", maxLines = 3, overflow = TextOverflow.Ellipsis) },
    secondaryLabel = {
        Text("With secondary label", maxLines = 2, overflow = TextOverflow.Ellipsis)
    },
    checked = checked,
    onCheckedChange = { checked = it },
    icon = { Icon(Icons.Filled.Favorite, contentDescription = "Favorite icon") },
    enabled = true,
)

CheckboxButton can be enabled or disabled. A disabled button will not respond to click events.

The recommended set of CheckboxButton colors can be obtained from CheckboxButtonDefaults, e.g. CheckboxButtonDefaults.checkboxButtonColors.

Parameters
checked: Boolean

Boolean flag indicating whether this button is currently checked.

onCheckedChange: (Boolean) -> Unit

Callback to be invoked when this button's checked status is changed.

modifier: Modifier = Modifier

Modifier to be applied to the CheckboxButton.

enabled: Boolean = true

Controls the enabled state of the button. When false, this button will not be clickable.

shape: Shape = CheckboxButtonDefaults.checkboxButtonShape

Defines the button's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material Theme.

colors: CheckboxButtonColors = CheckboxButtonDefaults.checkboxButtonColors()

CheckboxButtonColors that will be used to resolve the background and content color for this button in different states.

contentPadding: PaddingValues = CheckboxButtonDefaults.ContentPadding

The spacing values to apply internally between the container and the content.

interactionSource: MutableInteractionSource? = null

an optional hoisted MutableInteractionSource for observing and emitting Interactions for this button's "toggleable" tap area. You can use this to change the button's appearance or preview the button in different states. Note that if null is provided, interactions will still happen internally.

icon: (@Composable BoxScope.() -> Unit)? = null

An optional slot for providing an icon to indicate the purpose of the button. The contents are expected to be a horizontally and vertically center aligned icon of size 24.dp.

secondaryLabel: (@Composable RowScope.() -> Unit)? = null

A slot for providing the button's secondary label. The contents are expected to be text which is "start" aligned and no more than 2 lines of text.

label: @Composable RowScope.() -> Unit

A slot for providing the button's main label. The contents are expected to be text which is "start" aligned and no more than 3 lines of text.

@Composable
fun ChildButton(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    onLongClick: (() -> Unit)? = null,
    onLongClickLabel: String? = null,
    enabled: Boolean = true,
    shape: Shape = ButtonDefaults.shape,
    colors: ButtonColors = ButtonDefaults.childButtonColors(),
    border: BorderStroke? = null,
    contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
    interactionSource: MutableInteractionSource? = null,
    content: @Composable RowScope.() -> Unit
): Unit

Base level Wear Material3 ChildButton that offers a single slot to take any content. Used as the container for more opinionated ChildButton components that take specific content such as icons and labels.

The ChildButton is stadium-shaped by default and its standard height is designed to take 2 lines of text of Typography.labelMedium style. With localisation and/or large font sizes, the text can extend to a maximum of 3 lines in which case, the ChildButton height adjusts to accommodate the contents. The ChildButton can have an icon or image horizontally parallel to the two lines of text.

ChildButton takes the ButtonDefaults.childButtonColors color scheme by default, with a transparent background and no border. This is a low-emphasis button for optional or supplementary actions with the least amount of prominence.

Other recommended buttons with ButtonColors for different levels of emphasis are: Button which defaults to ButtonDefaults.buttonColors, FilledTonalButton which defaults to ButtonDefaults.filledTonalButtonColors, OutlinedButton which defaults to ButtonDefaults.outlinedButtonColors and Buttons can also take an image background using ButtonDefaults.imageBackgroundButtonColors.

ChildButton can be enabled or disabled. A disabled button will not respond to click events.

ChildButton scales itself appropriately when used within the scope of a TransformingLazyColumn.

Example of a ChildButton:

import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.ChildButton
import androidx.wear.compose.material3.Text

ChildButton(
    onClick = { /* Do something */ },
    label = {
        Text("Child Button", textAlign = TextAlign.Center, modifier = Modifier.fillMaxWidth())
    },
    modifier = modifier,
)
Parameters
onClick: () -> Unit

Will be called when the user clicks the button

modifier: Modifier = Modifier

Modifier to be applied to the button

onLongClick: (() -> Unit)? = null

Called when this button is long clicked (long-pressed). When this callback is set, onLongClickLabel should be set as well.

onLongClickLabel: String? = null

Semantic / accessibility label for the onLongClick action.

enabled: Boolean = true

Controls the enabled state of the button. When false, this button will not be clickable

shape: Shape = ButtonDefaults.shape

Defines the button's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material3 Theme

colors: ButtonColors = ButtonDefaults.childButtonColors()

ButtonColors that will be used to resolve the background and content color for this button in different states. See ButtonDefaults.childButtonColors.

border: BorderStroke? = null

Optional BorderStroke that will be used to resolve the border for this button in different states.

contentPadding: PaddingValues = ButtonDefaults.ContentPadding

The spacing values to apply internally between the container and the content

interactionSource: MutableInteractionSource? = null

an optional hoisted MutableInteractionSource for observing and emitting Interactions for this button. You can use this to change the button's appearance or preview the button in different states. Note that if null is provided, interactions will still happen internally.

content: @Composable RowScope.() -> Unit

Slot for composable body content displayed on the ChildButton

@Composable
fun ChildButton(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    onLongClick: (() -> Unit)? = null,
    onLongClickLabel: String? = null,
    secondaryLabel: (@Composable RowScope.() -> Unit)? = null,
    icon: (@Composable BoxScope.() -> Unit)? = null,
    enabled: Boolean = true,
    shape: Shape = ButtonDefaults.shape,
    colors: ButtonColors = ButtonDefaults.childButtonColors(),
    border: BorderStroke? = null,
    contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
    interactionSource: MutableInteractionSource? = null,
    label: @Composable RowScope.() -> Unit
): Unit

Wear Material3 ChildButton that offers three slots and a specific layout for an icon, label and secondaryLabel. The icon and secondaryLabel are optional. The items are laid out with the icon, if provided, at the start of a row, with a column next containing the two label slots.

The ChildButton is stadium-shaped by default and its standard height is designed to take 2 lines of text of Typography.labelMedium style - either a two-line label or both a single line label and a secondary label. With localisation and/or large font sizes, the ChildButton height adjusts to accommodate the contents. The label and secondary label should be consistently aligned.

If a icon is provided then the labels should be "start" aligned, e.g. left aligned in ltr so that the text starts next to the icon.

ChildButton takes the ButtonDefaults.childButtonColors color scheme by default, with a transparent background and no border. This is a low-emphasis button for optional or supplementary actions with the least amount of prominence.

Other recommended buttons with ButtonColors for different levels of emphasis are: Button which defaults to ButtonDefaults.buttonColors, FilledTonalButton which defaults to ButtonDefaults.filledTonalButtonColors, OutlinedButton which defaults to ButtonDefaults.outlinedButtonColors. Buttons can also take an image background using ButtonDefaults.imageBackgroundButtonColors.

ChildButton can be enabled or disabled. A disabled button will not respond to click events.

ChildButton scales itself appropriately when used within the scope of a TransformingLazyColumn.

Example of a ChildButton with an icon and secondary label:

import androidx.compose.foundation.layout.size
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.ButtonDefaults
import androidx.wear.compose.material3.ChildButton
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.Text

ChildButton(
    onClick = { /* Do something */ },
    label = { Text("Child Button") },
    secondaryLabel = { Text("Secondary label") },
    icon = {
        Icon(
            painter = painterResource(R.drawable.ic_favorite_rounded),
            contentDescription = "Favorite icon",
            modifier = Modifier.size(ButtonDefaults.IconSize)
        )
    },
    modifier = modifier
)
Parameters
onClick: () -> Unit

Will be called when the user clicks the button

modifier: Modifier = Modifier

Modifier to be applied to the button

onLongClick: (() -> Unit)? = null

Called when this button is long clicked (long-pressed). When this callback is set, onLongClickLabel should be set as well.

onLongClickLabel: String? = null

Semantic / accessibility label for the onLongClick action.

secondaryLabel: (@Composable RowScope.() -> Unit)? = null

A slot for providing the button's secondary label. The contents are expected to be text which is "start" aligned if there is an icon preset and "start" or "center" aligned if not. label and secondaryLabel contents should be consistently aligned.

icon: (@Composable BoxScope.() -> Unit)? = null

A slot for providing the button's icon. The contents are expected to be a horizontally and vertically aligned icon of size ButtonDefaults.IconSize or ButtonDefaults.LargeIconSize.

enabled: Boolean = true

Controls the enabled state of the button. When false, this button will not be clickable

shape: Shape = ButtonDefaults.shape

Defines the button's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material3 Theme

colors: ButtonColors = ButtonDefaults.childButtonColors()

ButtonColors that will be used to resolve the background and content color for this button in different states. See ButtonDefaults.childButtonColors.

border: BorderStroke? = null

Optional BorderStroke that will be used to resolve the button border in different states.

contentPadding: PaddingValues = ButtonDefaults.ContentPadding

The spacing values to apply internally between the container and the content

interactionSource: MutableInteractionSource? = null

an optional hoisted MutableInteractionSource for observing and emitting Interactions for this button. You can use this to change the button's appearance or preview the button in different states. Note that if null is provided, interactions will still happen internally.

label: @Composable RowScope.() -> Unit

A slot for providing the button's main label. The contents are expected to be text which is "start" aligned if there is an icon preset and "start" or "center" aligned if not.

CircularProgressIndicator

@Composable
fun CircularProgressIndicator(
    modifier: Modifier = Modifier,
    colors: ProgressIndicatorColors = ProgressIndicatorDefaults.colors(),
    strokeWidth: Dp = CircularProgressIndicatorDefaults.IndeterminateStrokeWidth,
    gapSize: Dp = CircularProgressIndicatorDefaults.calculateRecommendedGapSize(strokeWidth)
): Unit

Indeterminate Material Design circular progress indicator.

Indeterminate progress indicator expresses an unspecified wait time and spins indefinitely.

Example of indeterminate circular progress indicator:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.material3.CircularProgressIndicator

Box(modifier = Modifier.fillMaxSize()) {
    CircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
}
Parameters
modifier: Modifier = Modifier

Modifier to be applied to the CircularProgressIndicator.

colors: ProgressIndicatorColors = ProgressIndicatorDefaults.colors()

ProgressIndicatorColors that will be used to resolve the indicator and track color for this progress indicator.

strokeWidth: Dp = CircularProgressIndicatorDefaults.IndeterminateStrokeWidth

The stroke width for the progress indicator. The recommended values is CircularProgressIndicatorDefaults.IndeterminateStrokeWidth.

gapSize: Dp = CircularProgressIndicatorDefaults.calculateRecommendedGapSize(strokeWidth)

The size (in Dp) of the gap between the ends of the progress indicator and the track. The stroke endcaps are not included in this distance.

CircularProgressIndicator

@Composable
fun CircularProgressIndicator(
    progress: () -> Float,
    modifier: Modifier = Modifier,
    allowProgressOverflow: Boolean = false,
    startAngle: Float = CircularProgressIndicatorDefaults.StartAngle,
    endAngle: Float = startAngle,
    colors: ProgressIndicatorColors = ProgressIndicatorDefaults.colors(),
    strokeWidth: Dp = CircularProgressIndicatorDefaults.largeStrokeWidth,
    gapSize: Dp = CircularProgressIndicatorDefaults.calculateRecommendedGapSize(strokeWidth),
    enabled: Boolean = true
): Unit

Material Design circular progress indicator. Progress changes are animated.

Example of a full screen CircularProgressIndicator. Note that the padding CircularProgressIndicatorDefaults.FullScreenPadding should be applied:

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.ui.Modifier
import androidx.wear.compose.material3.CircularProgressIndicator
import androidx.wear.compose.material3.CircularProgressIndicatorDefaults
import androidx.wear.compose.material3.MaterialTheme
import androidx.wear.compose.material3.ProgressIndicatorDefaults

Box(
    modifier =
        Modifier.background(MaterialTheme.colorScheme.background)
            .padding(CircularProgressIndicatorDefaults.FullScreenPadding)
            .fillMaxSize()
) {
    CircularProgressIndicator(
        progress = { 0.25f },
        startAngle = 120f,
        endAngle = 60f,
    )
}

Example of progress showing overflow value (more than 1) by CircularProgressIndicator:

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.ui.Modifier
import androidx.wear.compose.material3.CircularProgressIndicator
import androidx.wear.compose.material3.CircularProgressIndicatorDefaults
import androidx.wear.compose.material3.MaterialTheme
import androidx.wear.compose.material3.ProgressIndicatorDefaults

Box(
    modifier =
        Modifier.background(MaterialTheme.colorScheme.background)
            .padding(CircularProgressIndicatorDefaults.FullScreenPadding)
            .fillMaxSize()
) {
    CircularProgressIndicator(
        // Overflow value of 120%
        progress = { 1.2f },
        allowProgressOverflow = true,
        startAngle = 120f,
        endAngle = 60f,
    )
}

Example of progress indicator wrapping media control by CircularProgressIndicator:

import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.PlayArrow
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.dp
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.CircularProgressIndicator
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.IconButton
import androidx.wear.compose.material3.IconButtonDefaults
import androidx.wear.compose.material3.MaterialTheme

var isPlaying by remember { mutableStateOf(false) }
val buttonPadding = 4.dp
val progressStrokeWidth = 4.dp
val progress = 0.75f

Box(modifier = Modifier.fillMaxSize().background(MaterialTheme.colorScheme.background)) {
    // The CircularProgressIndicator should be around the IconButton, with an extra gap between
    // then of 'buttonPadding'. We multiply by 2 because the size includes progressStrokeWidth
    // at top and bottom and the buttonPadding at top and bottom.
    CircularProgressIndicator(
        modifier =
            Modifier.align(Alignment.Center)
                .size(
                    IconButtonDefaults.DefaultButtonSize +
                        progressStrokeWidth * 2 +
                        buttonPadding * 2
                ),
        progress = { progress },
        strokeWidth = progressStrokeWidth
    )

    IconButton(
        modifier =
            Modifier.align(Alignment.Center)
                .semantics {
                    // Set custom progress semantics for accessibility.
                    contentDescription =
                        String.format(
                            "Play/pause button, track progress: %.0f%%",
                            progress * 100
                        )
                }
                .clip(CircleShape)
                .background(MaterialTheme.colorScheme.surfaceContainerLow),
        onClick = { isPlaying = !isPlaying }
    ) {
        Icon(
            imageVector = if (isPlaying) Icons.Filled.Close else Icons.Filled.PlayArrow,
            contentDescription = null,
        )
    }
}

Example of a CircularProgressIndicator with small progress values:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.wear.compose.material3.CircularProgressIndicator
import androidx.wear.compose.material3.CircularProgressIndicatorDefaults
import androidx.wear.compose.material3.ProgressIndicatorDefaults

Box {
    CircularProgressIndicator(
        // Small progress values like 2% will be rounded up to at least the stroke width.
        progress = { 0.02f },
        modifier =
            Modifier.fillMaxSize().padding(CircularProgressIndicatorDefaults.FullScreenPadding),
        startAngle = 120f,
        endAngle = 60f,
        strokeWidth = 10.dp,
        colors =
            ProgressIndicatorDefaults.colors(
                indicatorColor = Color.Green,
                trackColor = Color.White
            ),
    )
}

Progress indicators express the proportion of completion of an ongoing task.

Parameters
progress: () -> Float

The progress of this progress indicator where 0.0 represents no progress and 1.0 represents completion. Progress changes will be animated.

modifier: Modifier = Modifier

Modifier to be applied to the CircularProgressIndicator.

allowProgressOverflow: Boolean = false

When progress overflow is allowed, values smaller than 0.0 will be coerced to 0, while values larger than 1.0 will be wrapped around and shown as overflow with a different track color ProgressIndicatorColors.overflowTrackBrush. For example values 1.2, 2.2 etc will be shown as 20% progress with the overflow color. When progress overflow is not allowed, progress values will be coerced into the range 0..1.

startAngle: Float = CircularProgressIndicatorDefaults.StartAngle

The starting position of the progress arc, measured clockwise in degrees (0 to 360) from the 3 o'clock position. For example, 0 and 360 represent 3 o'clock, 90 and 180 represent 6 o'clock and 9 o'clock respectively. Default is 270 degrees CircularProgressIndicatorDefaults.StartAngle (top of the screen).

endAngle: Float = startAngle

The ending position of the progress arc, measured clockwise in degrees (0 to 360) from the 3 o'clock position. For example, 0 and 360 represent 3 o'clock, 90 and 180 represent 6 o'clock and 9 o'clock respectively. By default equal to startAngle.

colors: ProgressIndicatorColors = ProgressIndicatorDefaults.colors()

ProgressIndicatorColors that will be used to resolve the indicator and track color for this progress indicator in different states.

strokeWidth: Dp = CircularProgressIndicatorDefaults.largeStrokeWidth

The stroke width for the progress indicator. The recommended values are CircularProgressIndicatorDefaults.largeStrokeWidth and CircularProgressIndicatorDefaults.smallStrokeWidth.

gapSize: Dp = CircularProgressIndicatorDefaults.calculateRecommendedGapSize(strokeWidth)

The size (in Dp) of the gap between the ends of the progress indicator and the track. The stroke endcaps are not included in this distance.

enabled: Boolean = true

controls the enabled state. Although this component is not clickable, it can be contained within a clickable component. When enabled is false, this component will appear visually disabled.

CircularProgressIndicatorContent

@Composable
fun CircularProgressIndicatorContent(
    progress: () -> Float,
    modifier: Modifier = Modifier,
    allowProgressOverflow: Boolean = false,
    startAngle: Float = CircularProgressIndicatorDefaults.StartAngle,
    endAngle: Float = startAngle,
    colors: ProgressIndicatorColors = ProgressIndicatorDefaults.colors(),
    strokeWidth: Dp = CircularProgressIndicatorDefaults.largeStrokeWidth,
    gapSize: Dp = CircularProgressIndicatorDefaults.calculateRecommendedGapSize(strokeWidth),
    enabled: Boolean = true
): Unit

Simple circular progress indicator without any progress animations.

Example of CircularProgressIndicatorContent with custom progress animation:

import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.CircularProgressIndicator
import androidx.wear.compose.material3.CircularProgressIndicatorContent
import androidx.wear.compose.material3.CircularProgressIndicatorDefaults
import androidx.wear.compose.material3.MaterialTheme
import androidx.wear.compose.material3.ProgressIndicatorDefaults
import androidx.wear.compose.material3.Text

val progress = remember { mutableFloatStateOf(0f) }
val animatedProgress = remember { Animatable(0f) }

LaunchedEffect(Unit) {
    snapshotFlow(progress::value).collectLatest {
        animatedProgress.animateTo(it, tween(durationMillis = 1024, easing = LinearEasing))
    }
}

Box(
    modifier =
        Modifier.background(MaterialTheme.colorScheme.background)
            .padding(CircularProgressIndicatorDefaults.FullScreenPadding)
            .fillMaxSize()
) {
    Button(
        modifier = Modifier.align(Alignment.Center).padding(12.dp),
        onClick = { progress.value = if (progress.value == 0f) 1f else 0f },
        label = { Text("Animate") },
    )

    // Since CircularProgressIndicatorContent does not have any built-in progress animations,
    // we can implement a custom progress animation by using an Animatable progress value.
    CircularProgressIndicatorContent(
        progress = animatedProgress::value,
        startAngle = 120f,
        endAngle = 60f,
    )
}
Parameters
progress: () -> Float

The progress of this progress indicator where 0.0 represents no progress and 1.0 represents completion.

modifier: Modifier = Modifier

Modifier to be applied to the CircularProgressIndicator.

allowProgressOverflow: Boolean = false

When progress overflow is allowed, values smaller than 0.0 will be coerced to 0, while values larger than 1.0 will be wrapped around and shown as overflow with a different track color ProgressIndicatorColors.overflowTrackBrush. For example values 1.2, 2.2 etc will be shown as 20% progress with the overflow color. When progress overflow is not allowed, progress values will be coerced into the range 0..1.

startAngle: Float = CircularProgressIndicatorDefaults.StartAngle

The starting position of the progress arc, measured clockwise in degrees (0 to 360) from the 3 o'clock position. For example, 0 and 360 represent 3 o'clock, 90 and 180 represent 6 o'clock and 9 o'clock respectively. Default is 270 degrees CircularProgressIndicatorDefaults.StartAngle (top of the screen).

endAngle: Float = startAngle

The ending position of the progress arc, measured clockwise in degrees (0 to 360) from the 3 o'clock position. For example, 0 and 360 represent 3 o'clock, 90 and 180 represent 6 o'clock and 9 o'clock respectively. By default equal to startAngle.

colors: ProgressIndicatorColors = ProgressIndicatorDefaults.colors()

ProgressIndicatorColors that will be used to resolve the indicator and track color for this progress indicator in different states.

strokeWidth: Dp = CircularProgressIndicatorDefaults.largeStrokeWidth

The stroke width for the progress indicator. The recommended values are CircularProgressIndicatorDefaults.largeStrokeWidth and CircularProgressIndicatorDefaults.smallStrokeWidth.

gapSize: Dp = CircularProgressIndicatorDefaults.calculateRecommendedGapSize(strokeWidth)

The size (in Dp) of the gap between the ends of the progress indicator and the track. The stroke endcaps are not included in this distance.

enabled: Boolean = true

controls the enabled state. Although this component is not clickable, it can be contained within a clickable component. When enabled is false, this component will appear visually disabled.

@Composable
fun CompactButton(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    onLongClick: (() -> Unit)? = null,
    onLongClickLabel: String? = null,
    icon: (@Composable BoxScope.() -> Unit)? = null,
    enabled: Boolean = true,
    shape: Shape = ButtonDefaults.compactButtonShape,
    colors: ButtonColors = ButtonDefaults.buttonColors(),
    border: BorderStroke? = null,
    contentPadding: PaddingValues = ButtonDefaults.CompactButtonContentPadding,
    interactionSource: MutableInteractionSource? = null,
    label: (@Composable RowScope.() -> Unit)? = null
): Unit

A Wear Material3 CompactButton that offers two slots and a specific layout for an icon and label. Both the icon and label are optional however it is expected that at least one will be provided.

The CompactButton is Stadium shaped and has a max height designed to take no more than one line of text and/or one icon. The default max height is ButtonDefaults.CompactButtonHeight. This includes a visible button height of 32.dp and 8.dp of padding above and below the button in order to meet accessibility guidelines that request a minimum of 48.dp height and width of tappable area.

If an icon is provided then the labels should be "start" aligned, e.g. left aligned in left-to-right mode so that the text starts next to the icon.

The items are laid out as follows.

  1. If a label is provided then the button will be laid out with the optional icon at the start of a row followed by the label with a default max height of ButtonDefaults.CompactButtonHeight.

  2. If only an icon is provided it will be laid out vertically and horizontally centered with a default height of ButtonDefaults.CompactButtonHeight and the default width of ButtonDefaults.IconOnlyCompactButtonWidth

If neither icon nor label is provided then the button will displayed like an icon only button but with no contents or background color.

CompactButton takes the ButtonDefaults.buttonColors color scheme by default, with colored background, contrasting content color and no border. This is a high-emphasis button for the primary, most important or most common action on a screen.

Other recommended ButtonColors for different levels of emphasis are: ButtonDefaults.filledTonalButtonColors, ButtonDefaults.outlinedButtonColors and ButtonDefaults.childButtonColors. Buttons can also take an image background using ButtonDefaults.imageBackgroundButtonColors.

CompactButton can be enabled or disabled. A disabled button will not respond to click events.

CompactButton scales itself appropriately when used within the scope of a TransformingLazyColumn.

Example of a CompactButton with an icon and a label

import androidx.compose.foundation.layout.size
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.ButtonDefaults
import androidx.wear.compose.material3.CompactButton
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.Text

CompactButton(
    onClick = { /* Do something */ },
    icon = {
        Icon(
            painter = painterResource(R.drawable.ic_favorite_rounded),
            contentDescription = "Favorite icon",
            modifier = Modifier.size(ButtonDefaults.ExtraSmallIconSize)
        )
    },
    modifier = modifier,
) {
    Text("Compact Button", maxLines = 1, overflow = TextOverflow.Ellipsis)
}

Example of a CompactButton with an icon and label and with ButtonDefaults.filledTonalButtonColors

import androidx.compose.foundation.layout.size
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.ButtonDefaults
import androidx.wear.compose.material3.CompactButton
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.Text

CompactButton(
    onClick = { /* Do something */ },
    icon = {
        Icon(
            painter = painterResource(R.drawable.ic_favorite_rounded),
            contentDescription = "Favorite icon",
            modifier = Modifier.size(ButtonDefaults.ExtraSmallIconSize)
        )
    },
    colors = ButtonDefaults.filledTonalButtonColors(),
    modifier = modifier,
) {
    Text("Filled Tonal Compact Button", maxLines = 1, overflow = TextOverflow.Ellipsis)
}

Example of a CompactButton with an icon and label and with ButtonDefaults.outlinedButtonBorder and ButtonDefaults.outlinedButtonColors

import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowDropDown
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextOverflow
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.ButtonDefaults
import androidx.wear.compose.material3.CompactButton
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.Text

CompactButton(
    onClick = { /* Do something */ },
    colors = ButtonDefaults.outlinedButtonColors(),
    border = ButtonDefaults.outlinedButtonBorder(enabled = true),
    modifier = modifier,
) {
    Text("Show More", maxLines = 1, overflow = TextOverflow.Ellipsis)
    Spacer(Modifier.width(ButtonDefaults.IconSpacing))
    Icon(
        Icons.Filled.ArrowDropDown,
        contentDescription = "Expand",
        modifier = Modifier.size(ButtonDefaults.ExtraSmallIconSize)
    )
}

Example of a CompactButton with onLongClick:

import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.CompactButton
import androidx.wear.compose.material3.Text

CompactButton(
    onClick = onClickHandler,
    onLongClick = onLongClickHandler,
    onLongClickLabel = "Long click",
    label = { Text("Long clickable") },
    modifier = modifier,
)
Parameters
onClick: () -> Unit

Will be called when the user clicks the button

modifier: Modifier = Modifier

Modifier to be applied to the button

onLongClick: (() -> Unit)? = null

Called when this button is long clicked (long-pressed). When this callback is set, onLongClickLabel should be set as well.

onLongClickLabel: String? = null

Semantic / accessibility label for the onLongClick action.

icon: (@Composable BoxScope.() -> Unit)? = null

A slot for providing the button's icon. The contents are expected to be a horizontally and vertically aligned icon of size ButtonDefaults.ExtraSmallIconSize when used with a label or ButtonDefaults.SmallIconSize when used as the only content in the button.

enabled: Boolean = true

Controls the enabled state of the button. When false, this button will not be clickable

shape: Shape = ButtonDefaults.compactButtonShape

Defines the button's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material3 Theme

colors: ButtonColors = ButtonDefaults.buttonColors()

ButtonColors that will be used to resolve the background and content color for this button in different states. See ButtonDefaults.buttonColors.

border: BorderStroke? = null

Optional BorderStroke that will be used to resolve the border for this button in different states.

contentPadding: PaddingValues = ButtonDefaults.CompactButtonContentPadding

The spacing values to apply internally between the container and the content

interactionSource: MutableInteractionSource? = null

an optional hoisted MutableInteractionSource for observing and emitting Interactions for this button. You can use this to change the button's appearance or preview the button in different states. Note that if null is provided, interactions will still happen internally.

label: (@Composable RowScope.() -> Unit)? = null

A slot for providing the button's main label. The contents are expected to be a single line of text which is "start" aligned if there is an icon preset and "center" aligned if not.

@Composable
fun Confirmation(
    show: Boolean,
    onDismissRequest: () -> Unit,
    curvedText: (CurvedScope.() -> Unit)?,
    modifier: Modifier = Modifier,
    colors: ConfirmationColors = ConfirmationDefaults.confirmationColors(),
    properties: DialogProperties = DialogProperties(),
    durationMillis: Long = ConfirmationDefaults.ConfirmationDurationMillis,
    content: @Composable BoxScope.() -> Unit
): Unit

Shows a Confirmation dialog with an icon and optional very short curved text. The length of the curved text should be very short and should not exceed 1-2 words. If a longer text required, then another Confirmation overload with a column content should be used instead.

The confirmation will be showing a message to the user for durationMillis. After a specified timeout, the onDismissRequest callback will be invoked, where it's up to the caller to handle the dismissal. To hide the confirmation, show parameter should be set to false.

Example of a Confirmation with an icon and a curved text content:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.material3.Confirmation
import androidx.wear.compose.material3.ConfirmationDefaults
import androidx.wear.compose.material3.FilledTonalButton
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.samples.icons.FavoriteIcon

var showConfirmation by remember { mutableStateOf(false) }

Box(Modifier.fillMaxSize()) {
    FilledTonalButton(
        modifier = Modifier.align(Alignment.Center),
        onClick = { showConfirmation = true },
        label = { Text("Show Confirmation") }
    )
}

// Has an icon and a short curved text content, which will be displayed along the bottom edge of
// the screen.
Confirmation(
    show = showConfirmation,
    onDismissRequest = { showConfirmation = false },
    curvedText = ConfirmationDefaults.curvedText("Confirmed")
) {
    FavoriteIcon(ConfirmationDefaults.IconSize)
}
Parameters
show: Boolean

A boolean indicating whether the confirmation should be displayed.

onDismissRequest: () -> Unit

A lambda function to be called when the dialog is dismissed - either by swiping right or when the durationMillis has passed.

curvedText: (CurvedScope.() -> Unit)?

A slot for displaying curved text content which will be shown along the bottom edge of the dialog.

modifier: Modifier = Modifier

Modifier to be applied to the confirmation content.

colors: ConfirmationColors = ConfirmationDefaults.confirmationColors()

A ConfirmationColors object for customizing the colors used in this Confirmation.

properties: DialogProperties = DialogProperties()

An optional DialogProperties object for configuring the dialog's behavior.

durationMillis: Long = ConfirmationDefaults.ConfirmationDurationMillis

The duration in milliseconds for which the dialog is displayed. Defaults to ConfirmationDefaults.ConfirmationDurationMillis.

content: @Composable BoxScope.() -> Unit

A slot for displaying an icon inside the confirmation dialog. It's recommended to set its size to ConfirmationDefaults.IconSize

@Composable
fun Confirmation(
    show: Boolean,
    onDismissRequest: () -> Unit,
    text: (@Composable ColumnScope.() -> Unit)?,
    modifier: Modifier = Modifier,
    colors: ConfirmationColors = ConfirmationDefaults.confirmationColors(),
    properties: DialogProperties = DialogProperties(),
    durationMillis: Long = ConfirmationDefaults.ConfirmationDurationMillis,
    content: @Composable BoxScope.() -> Unit
): Unit

Shows a Confirmation dialog with an icon and optional short text. The length of the text should not exceed 3 lines. If the text is very short and fits into 1-2 words, consider using another Confirmation overload with curvedContent instead.

The confirmation will show a message to the user for durationMillis. After a specified timeout, the onDismissRequest callback will be invoked, where it's up to the caller to handle the dismissal. To hide the confirmation, show parameter should be set to false.

Example of a Confirmation with an icon and a text which fits into 3 lines:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.Send
import androidx.compose.material.icons.filled.Send
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.material3.Confirmation
import androidx.wear.compose.material3.ConfirmationDefaults
import androidx.wear.compose.material3.FilledTonalButton
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.Text

var showConfirmation by remember { mutableStateOf(false) }

Box(Modifier.fillMaxSize()) {
    FilledTonalButton(
        modifier = Modifier.align(Alignment.Center),
        onClick = { showConfirmation = true },
        label = { Text("Show Confirmation") }
    )
}

// Has an icon and a text content. Text will be displayed in the center of the screen below the
// icon.
Confirmation(
    show = showConfirmation,
    onDismissRequest = { showConfirmation = false },
    text = { Text(text = "Your message has been sent") },
) {
    Icon(
        imageVector = Icons.AutoMirrored.Filled.Send,
        contentDescription = null,
        modifier = Modifier.size(ConfirmationDefaults.SmallIconSize),
    )
}
Parameters
show: Boolean

A boolean indicating whether the confirmation should be displayed.

onDismissRequest: () -> Unit

A lambda function to be called when the dialog is dismissed - either by swiping right or when the durationMillis has passed.

text: (@Composable ColumnScope.() -> Unit)?

A slot for displaying text below the icon. It should not exceed 3 lines.

modifier: Modifier = Modifier

Modifier to be applied to the confirmation content.

colors: ConfirmationColors = ConfirmationDefaults.confirmationColors()

A ConfirmationColors object for customizing the colors used in this Confirmation.

properties: DialogProperties = DialogProperties()

An optional DialogProperties object for configuring the dialog's behavior.

durationMillis: Long = ConfirmationDefaults.ConfirmationDurationMillis

The duration in milliseconds for which the dialog is displayed. Defaults to ConfirmationDefaults.ConfirmationDurationMillis.

content: @Composable BoxScope.() -> Unit

A slot for displaying an icon inside the confirmation dialog, which can be animated. It's recommended to set its size to ConfirmationDefaults.SmallIconSize

@RequiresApi(value = 26)
@Composable
fun DatePicker(
    initialDate: LocalDate,
    onDatePicked: (LocalDate) -> Unit,
    modifier: Modifier = Modifier,
    minDate: LocalDate? = null,
    maxDate: LocalDate? = null,
    datePickerType: DatePickerType = DatePickerDefaults.datePickerType,
    colors: DatePickerColors = DatePickerDefaults.datePickerColors()
): Unit

Full screen date picker with day, month, year.

This component is designed to take most/all of the screen and utilizes large fonts.

Example of a DatePicker:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Edit
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalConfiguration
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.DatePicker
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.Text

var showDatePicker by remember { mutableStateOf(true) }
var datePickerDate by remember { mutableStateOf(LocalDate.now()) }
val formatter =
    DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)
        .withLocale(LocalConfiguration.current.locales[0])
if (showDatePicker) {
    DatePicker(
        initialDate = datePickerDate, // Initialize with last picked date on reopen
        onDatePicked = {
            datePickerDate = it
            showDatePicker = false
        }
    )
} else {
    Box(
        modifier = Modifier.fillMaxSize(),
        contentAlignment = Alignment.Center,
    ) {
        Button(
            onClick = { showDatePicker = true },
            label = { Text("Selected Date") },
            secondaryLabel = { Text(datePickerDate.format(formatter)) },
            icon = { Icon(imageVector = Icons.Filled.Edit, contentDescription = "Edit") },
        )
    }
}

Example of a DatePicker shows the picker options in year-month-day order:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Edit
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.DatePicker
import androidx.wear.compose.material3.DatePickerType
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.Text

var showDatePicker by remember { mutableStateOf(true) }
var datePickerDate by remember { mutableStateOf(LocalDate.now()) }
val formatter = DateTimeFormatter.ofPattern("yyyy MMM d")
if (showDatePicker) {
    DatePicker(
        initialDate = datePickerDate, // Initialize with last picked date on reopen
        onDatePicked = {
            datePickerDate = it
            showDatePicker = false
        },
        datePickerType = DatePickerType.YearMonthDay
    )
} else {
    Box(
        modifier = Modifier.fillMaxSize(),
        contentAlignment = Alignment.Center,
    ) {
        Button(
            onClick = { showDatePicker = true },
            label = { Text("Selected Date") },
            secondaryLabel = { Text(datePickerDate.format(formatter)) },
            icon = { Icon(imageVector = Icons.Filled.Edit, contentDescription = "Edit") },
        )
    }
}

Example of a DatePicker with minDate and maxDate:

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Edit
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.unit.dp
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.DatePicker
import androidx.wear.compose.material3.DatePickerType
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.Text

var showDatePicker by remember { mutableStateOf(false) }
var datePickerDate by remember { mutableStateOf(LocalDate.of(2024, 9, 2)) }
val formatter =
    DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)
        .withLocale(LocalConfiguration.current.locales[0])
val minDate = LocalDate.of(2022, 10, 30)
val maxDate = LocalDate.of(2025, 2, 4)
if (showDatePicker) {
    DatePicker(
        initialDate = datePickerDate, // Initialize with last picked date on reopen
        onDatePicked = {
            datePickerDate = it
            showDatePicker = false
        },
        minDate = minDate,
        maxDate = maxDate,
        datePickerType = DatePickerType.YearMonthDay
    )
} else {
    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        Text(text = "${minDate.format(formatter)} ~ ${maxDate.format(formatter)}")
        Spacer(modifier = Modifier.height(6.dp))
        Button(
            onClick = { showDatePicker = true },
            label = { Text("Selected Date") },
            secondaryLabel = { Text(datePickerDate.format(formatter)) },
            icon = { Icon(imageVector = Icons.Filled.Edit, contentDescription = "Edit") },
        )
    }
}
Parameters
initialDate: LocalDate

The initial value to be displayed in the DatePicker.

onDatePicked: (LocalDate) -> Unit

The callback that is called when the user confirms the date selection. It provides the selected date as LocalDate

modifier: Modifier = Modifier

Modifier to be applied to the Box containing the UI elements.

minDate: LocalDate? = null

Optional minimum date that can be selected in the DatePicker (inclusive).

maxDate: LocalDate? = null

Optional maximum date that can be selected in the DatePicker (inclusive).

datePickerType: DatePickerType = DatePickerDefaults.datePickerType

The different DatePickerType supported by this date picker.

colors: DatePickerColors = DatePickerDefaults.datePickerColors()

DatePickerColors to be applied to the DatePicker.

@Composable
fun Dialog(
    show: Boolean,
    onDismissRequest: () -> Unit,
    modifier: Modifier = Modifier,
    properties: DialogProperties = DialogProperties(),
    content: @Composable () -> Unit
): Unit

A base dialog component used by AlertDialog and Confirmation variations. This dialog provides a full-screen experience with custom entry/exit animations.

Dialogs provide important prompts in a user flow. They can require an action, communicate information, or help users accomplish a task.

The caller should consider whether timeText or scrollIndicator are needed on this dialog, in this case they should provide that in their content by using ScreenScaffold (with suitable scrollState if that's required).

Parameters
show: Boolean

A boolean value that determines whether the dialog should be displayed.

onDismissRequest: () -> Unit

A lambda function to be called when the dialog is dismissed by swiping right.

modifier: Modifier = Modifier

Modifier to be applied to the dialog content.

properties: DialogProperties = DialogProperties()

An optional DialogProperties object for configuring the dialog's behavior.

content: @Composable () -> Unit

A composable function that defines the content of the dialog.

@Composable
fun EdgeButton(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    buttonSize: EdgeButtonSize = EdgeButtonSize.Small,
    enabled: Boolean = true,
    colors: ButtonColors = ButtonDefaults.buttonColors(),
    border: BorderStroke? = null,
    interactionSource: MutableInteractionSource? = null,
    content: @Composable RowScope.() -> Unit
): Unit

Wear Material3 EdgeButton that offers a single slot to take any content.

The EdgeButton has a special shape designed for the bottom of the screen, as it almost follows the screen's curvature, so it should be allowed to take the full width and touch the bottom of the screen. It has 4 standard sizes, taking 1 line of text for the extra small, 2 for small and medium, and 3 for the large. See the standard values on ButtonDefaults, and specify it using the buttonSize parameter. Optionally, a single icon can be used instead of the text.

This button represents the most important action on the screen, and must take the whole width of the screen as well as being anchored to the screen bottom.

EdgeButton takes the ButtonDefaults.buttonColors color scheme by default, with colored background, contrasting content color and no border. This is a high-emphasis button for the primary, most important or most common action on a screen. Other possible colors for different levels of emphasis are: FilledTonalButton which defaults to ButtonDefaults.filledTonalButtonColors and OutlinedButton which defaults to ButtonDefaults.outlinedButtonColors

EdgeButton is not intended to be used with an image background.

Edge button can be enabled or disabled. A disabled button will not respond to click events.

Example of an EdgeButton:

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Check
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.wear.compose.material3.ButtonDefaults
import androidx.wear.compose.material3.EdgeButton
import androidx.wear.compose.material3.EdgeButtonSize
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.TextButton
import androidx.wear.compose.material3.TextButtonDefaults

val sizes =
    listOf(
        EdgeButtonSize.ExtraSmall,
        EdgeButtonSize.Small,
        EdgeButtonSize.Medium,
        EdgeButtonSize.Large
    )
val sizeNames = listOf("XS", "S", "M", "L")
var size by remember { mutableIntStateOf(0) }

Box(Modifier.fillMaxSize()) {
    Column(
        Modifier.align(Alignment.TopCenter).fillMaxSize().padding(top = 0.dp),
        verticalArrangement = Arrangement.spacedBy(0.dp),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Column(modifier = Modifier.weight(1f)) {
            Row { Spacer(modifier = Modifier.height(16.dp)) }
            Row {
                Text("Sizes", modifier = Modifier.fillMaxWidth(), textAlign = TextAlign.Center)
            }
            Row(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.Center
            ) {
                repeat(sizeNames.size) {
                    TextButton(
                        onClick = { size = it },
                        modifier = Modifier.size(TextButtonDefaults.SmallButtonSize)
                    ) {
                        Text(sizeNames[it])
                    }
                }
            }
        }
        EdgeButton(
            onClick = { /* Do something */ },
            buttonSize = sizes[size],
        ) {
            Icon(
                Icons.Filled.Check,
                contentDescription = "Check icon",
                modifier = Modifier.size(ButtonDefaults.IconSize)
            )
        }
    }
}

For a sample integrating with ScalingLazyColumn, see:

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.selection.selectableGroup
import androidx.compose.material.icons.filled.Check
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.unit.dp
import androidx.wear.compose.foundation.lazy.ScalingLazyColumn
import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState
import androidx.wear.compose.material3.ButtonDefaults
import androidx.wear.compose.material3.EdgeButton
import androidx.wear.compose.material3.EdgeButtonSize
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.RadioButton
import androidx.wear.compose.material3.ScreenScaffold
import androidx.wear.compose.material3.ScreenScaffoldDefaults
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.samples.icons.CheckIcon

val state = rememberScalingLazyListState()
val horizontalPadding = LocalConfiguration.current.screenWidthDp.dp * 0.052f
val verticalPadding = LocalConfiguration.current.screenHeightDp.dp * 0.16f
val colors =
    listOf(
        "Filled" to ButtonDefaults.buttonColors(),
        "Filled Variant" to ButtonDefaults.filledVariantButtonColors(),
        "Filled Tonal" to ButtonDefaults.filledTonalButtonColors(),
        "Outlined" to ButtonDefaults.outlinedButtonColors(),
        "Disabled" to ButtonDefaults.buttonColors()
    )
var selectedColor by remember { mutableIntStateOf(0) }
val types = listOf("Icon only" to 0, "Text only" to 1)
var selectedType by remember { mutableIntStateOf(0) }

ScreenScaffold(
    scrollState = state,
    edgeButton = {
        EdgeButton(
            onClick = {},
            buttonSize = EdgeButtonSize.Medium,
            colors = colors[selectedColor].second,
            border =
                if (colors[selectedColor].first == "Outlined")
                    ButtonDefaults.outlinedButtonBorder(true)
                else null,
            enabled = colors[selectedColor].first != "Disabled"
        ) {
            if (selectedType == 0) {
                CheckIcon()
            } else {
                Text("Ok")
            }
        }
    }
) {
    ScalingLazyColumn(
        state = state,
        modifier = Modifier.fillMaxSize().selectableGroup(),
        autoCentering = null,
        contentPadding =
            ScreenScaffoldDefaults.contentPaddingWithEdgeButton(
                edgeButtonSize = EdgeButtonSize.Medium,
                start = horizontalPadding,
                end = horizontalPadding,
                top = verticalPadding,
            ),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        item { Text("Color") }
        items(colors.size) { ix ->
            RadioButton(
                label = { Text(colors[ix].first) },
                selected = selectedColor == ix,
                onSelect = { selectedColor = ix },
                modifier = Modifier.fillMaxWidth()
            )
        }
        item { Text("Type") }
        items(types.size) { ix ->
            RadioButton(
                label = { Text(types[ix].first) },
                selected = selectedType == ix,
                onSelect = { selectedType = ix },
                modifier = Modifier.fillMaxWidth()
            )
        }
    }
}
Parameters
onClick: () -> Unit

Will be called when the user clicks the button

modifier: Modifier = Modifier

Modifier to be applied to the button. When animating the button to appear/ disappear from the screen, a Modifier.height can be used to change the height of the component, but that won't change the space available for the content (though it may be scaled)

buttonSize: EdgeButtonSize = EdgeButtonSize.Small

Defines the size of the button. See EdgeButtonSize.

enabled: Boolean = true

Controls the enabled state of the button. When false, this button will not be clickable

colors: ButtonColors = ButtonDefaults.buttonColors()

ButtonColors that will be used to resolve the background and content color for this button in different states. See ButtonDefaults.buttonColors.

border: BorderStroke? = null

Optional BorderStroke that will be used to resolve the border for this button in different states.

interactionSource: MutableInteractionSource? = null

an optional hoisted MutableInteractionSource for observing and emitting Interactions for this button. You can use this to change the button's appearance or preview the button in different states. Note that if null is provided, interactions will still happen internally.

content: @Composable RowScope.() -> Unit

Slot for composable body content displayed on the Button. Either an Icon or Text.

FailureConfirmation

@Composable
fun FailureConfirmation(
    show: Boolean,
    onDismissRequest: () -> Unit,
    modifier: Modifier = Modifier,
    curvedText: (CurvedScope.() -> Unit)? = ConfirmationDefaults.failureText(),
    colors: ConfirmationColors = ConfirmationDefaults.failureColors(),
    properties: DialogProperties = DialogProperties(),
    durationMillis: Long = ConfirmationDefaults.ConfirmationDurationMillis,
    content: @Composable BoxScope.() -> Unit = ConfirmationDefaults.FailureIcon
): Unit

Shows a Confirmation dialog with a failure icon and an optional short curved text. This confirmation indicates an unsuccessful operation or action.

The confirmation will show a message to the user for durationMillis. After a specified timeout, the onDismissRequest callback will be invoked, where it's up to the caller to handle the dismissal. To hide the confirmation, show parameter should be set to false.

Example of a FailureConfirmation usage:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.material3.Confirmation
import androidx.wear.compose.material3.FailureConfirmation
import androidx.wear.compose.material3.FilledTonalButton
import androidx.wear.compose.material3.Text

var showConfirmation by remember { mutableStateOf(false) }

Box(Modifier.fillMaxSize()) {
    FilledTonalButton(
        modifier = Modifier.align(Alignment.Center),
        onClick = { showConfirmation = true },
        label = { Text("Show Confirmation") }
    )
}

FailureConfirmation(show = showConfirmation, onDismissRequest = { showConfirmation = false })
Parameters
show: Boolean

A boolean indicating whether the confirmation should be displayed.

onDismissRequest: () -> Unit

A lambda function to be called when the dialog is dismissed - either by swiping right or when the durationMillis has passed.

modifier: Modifier = Modifier

Modifier to be applied to the confirmation content.

curvedText: (CurvedScope.() -> Unit)? = ConfirmationDefaults.failureText()

A slot for displaying curved text content which will be shown along the bottom edge of the dialog. Defaults to a localized failure message.

colors: ConfirmationColors = ConfirmationDefaults.failureColors()

A ConfirmationColors object for customizing the colors used in this FailureConfirmation.

properties: DialogProperties = DialogProperties()

An optional DialogProperties object for configuring the dialog's behavior.

durationMillis: Long = ConfirmationDefaults.ConfirmationDurationMillis

The duration in milliseconds for which the dialog is displayed. Defaults to ConfirmationDefaults.ConfirmationDurationMillis.

content: @Composable BoxScope.() -> Unit = ConfirmationDefaults.FailureIcon

A slot for displaying an icon inside the confirmation dialog, which can be animated. Defaults to ConfirmationDefaults.FailureIcon.

@Composable
fun FilledIconButton(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    onLongClick: (() -> Unit)? = null,
    onLongClickLabel: String? = null,
    enabled: Boolean = true,
    shapes: IconButtonShapes = IconButtonDefaults.shapes(),
    colors: IconButtonColors = IconButtonDefaults.filledIconButtonColors(),
    border: BorderStroke? = null,
    interactionSource: MutableInteractionSource? = null,
    content: @Composable BoxScope.() -> Unit
): Unit

Wear Material FilledIconButton is a circular, icon-only button with a colored background and a contrasting content color. It offers a single slot to take an icon or image.

Set the size of the FilledIconButton with Modifier.touchTargetAwareSize to ensure that the recommended minimum touch target size is available.

The recommended IconButton sizes are IconButtonDefaults.DefaultButtonSize, IconButtonDefaults.LargeButtonSize, IconButtonDefaults.SmallButtonSize and IconButtonDefaults.ExtraSmallButtonSize.

Use IconButtonDefaults.iconSizeFor to determine the icon size for a given IconButton size, or refer to icon sizes IconButtonDefaults.SmallIconSize, IconButtonDefaults.DefaultIconSize, IconButtonDefaults.LargeIconSize directly.

FilledIconButton can be enabled or disabled. A disabled button will not respond to click events.

Example of FilledIconButton:

import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Favorite
import androidx.wear.compose.material3.FilledIconButton
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.IconButton

FilledIconButton(onClick = { /* Do something */ }) {
    Icon(imageVector = Icons.Filled.Favorite, contentDescription = "Favorite icon")
}
Parameters
onClick: () -> Unit

Will be called when the user clicks the button.

modifier: Modifier = Modifier

Modifier to be applied to the button.

onLongClick: (() -> Unit)? = null

Called when this button is long clicked (long-pressed). When this callback is set, onLongClickLabel should be set as well.

onLongClickLabel: String? = null

Semantic / accessibility label for the onLongClick action.

enabled: Boolean = true

Controls the enabled state of the button. When false, this button will not be clickable.

shapes: IconButtonShapes = IconButtonDefaults.shapes()

Defines the shape for this button. Defaults to a static shape based on IconButtonDefaults.shape, but animated versions are available through IconButtonDefaults.animatedShapes.

colors: IconButtonColors = IconButtonDefaults.filledIconButtonColors()

IconButtonColors that will be used to resolve the container and content color for this icon button in different states.

border: BorderStroke? = null

Optional BorderStroke for the icon button border.

interactionSource: MutableInteractionSource? = null

an optional hoisted MutableInteractionSource for observing and emitting Interactions for this button. You can use this to change the button's appearance or preview the button in different states. Note that if null is provided, interactions will still happen internally.

content: @Composable BoxScope.() -> Unit

The content displayed on the icon button, expected to be icon or image.

@Composable
fun FilledTonalButton(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    onLongClick: (() -> Unit)? = null,
    onLongClickLabel: String? = null,
    enabled: Boolean = true,
    shape: Shape = ButtonDefaults.shape,
    colors: ButtonColors = ButtonDefaults.filledTonalButtonColors(),
    border: BorderStroke? = null,
    contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
    interactionSource: MutableInteractionSource? = null,
    content: @Composable RowScope.() -> Unit
): Unit

Base level Wear Material3 FilledTonalButton that offers a single slot to take any content. Used as the container for more opinionated FilledTonalButton components that take specific content such as icons and labels.

The FilledTonalButton is Stadium-shaped by default and has a max height designed to take no more than two lines of text of Typography.labelMedium style. With localisation and/or large font sizes, the text can extend to a maximum of 3 lines in which case, the FilledTonalButton height adjusts to accommodate the contents. The FilledTonalButton can have an icon or image horizontally parallel to the two lines of text.

FilledTonalButton takes the ButtonDefaults.filledTonalButtonColors color scheme by default, with muted background, contrasting content color and no border. This is a medium-emphasis button for important actions that don't distract from other onscreen elements, such as final or unblocking actions in a flow with less emphasis than Button.

Other recommended buttons with ButtonColors for different levels of emphasis are: Button which defaults to ButtonDefaults.buttonColors, OutlinedButton which defaults to ButtonDefaults.outlinedButtonColors and ChildButton which defaults to ButtonDefaults.childButtonColors. Buttons can also take an image background using ButtonDefaults.imageBackgroundButtonColors.

FilledTonalButton can be enabled or disabled. A disabled button will not respond to click events.

FilledTonalButton scales itself appropriately when used within the scope of a TransformingLazyColumn.

Example of a FilledTonalButton:

import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.FilledTonalButton
import androidx.wear.compose.material3.Text

FilledTonalButton(
    onClick = { /* Do something */ },
    label = { Text("Filled Tonal Button") },
    modifier = modifier,
)
Parameters
onClick: () -> Unit

Will be called when the user clicks the button

modifier: Modifier = Modifier

Modifier to be applied to the button

onLongClick: (() -> Unit)? = null

Called when this button is long clicked (long-pressed). When this callback is set, onLongClickLabel should be set as well.

onLongClickLabel: String? = null

Semantic / accessibility label for the onLongClick action.

enabled: Boolean = true

Controls the enabled state of the button. When false, this button will not be clickable

shape: Shape = ButtonDefaults.shape

Defines the button's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material3 Theme

colors: ButtonColors = ButtonDefaults.filledTonalButtonColors()

ButtonColors that will be used to resolve the background and content color for this button in different states. See ButtonDefaults.filledTonalButtonColors.

border: BorderStroke? = null

Optional BorderStroke that will be used to resolve the border for this button in different states.

contentPadding: PaddingValues = ButtonDefaults.ContentPadding

The spacing values to apply internally between the container and the content

interactionSource: MutableInteractionSource? = null

an optional hoisted MutableInteractionSource for observing and emitting Interactions for this button. You can use this to change the button's appearance or preview the button in different states. Note that if null is provided, interactions will still happen internally.

content: @Composable RowScope.() -> Unit

Slot for composable body content displayed on the Button

@Composable
fun FilledTonalButton(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    onLongClick: (() -> Unit)? = null,
    onLongClickLabel: String? = null,
    secondaryLabel: (@Composable RowScope.() -> Unit)? = null,
    icon: (@Composable BoxScope.() -> Unit)? = null,
    enabled: Boolean = true,
    shape: Shape = ButtonDefaults.shape,
    colors: ButtonColors = ButtonDefaults.filledTonalButtonColors(),
    border: BorderStroke? = null,
    contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
    interactionSource: MutableInteractionSource? = null,
    label: @Composable RowScope.() -> Unit
): Unit

Wear Material3 FilledTonalButton that offers three slots and a specific layout for an icon, label and secondaryLabel. The icon and secondaryLabel are optional. The items are laid out with the icon, if provided, at the start of a row, with a column next containing the two label slots.

The FilledTonalButton is stadium-shaped by default and its standard height is designed to take 2 lines of text of Typography.labelMedium style - either a two-line label or both a single line label and a secondary label. With localisation and/or large font sizes, the FilledTonalButton height adjusts to accommodate the contents. The label and secondary label should be consistently aligned.

If a icon is provided then the labels should be "start" aligned, e.g. left aligned in ltr so that the text starts next to the icon.

If a icon is provided then the labels should be "start" aligned, e.g. left aligned in ltr so that the text starts next to the icon.

FilledTonalButton takes the ButtonDefaults.filledTonalButtonColors color scheme by default, with muted background, contrasting content color and no border. This is a medium-emphasis button for important actions that don't distract from other onscreen elements, such as final or unblocking actions in a flow with less emphasis than Button.

Other recommended buttons with ButtonColors for different levels of emphasis are: Button which defaults to ButtonDefaults.buttonColors, OutlinedButton which defaults to ButtonDefaults.outlinedButtonColors and ChildButton which defaults to ButtonDefaults.childButtonColors. Buttons can also take an image background using ButtonDefaults.imageBackgroundButtonColors.

FilledTonalButton can be enabled or disabled. A disabled button will not respond to click events.

FilledTonalButton scales itself appropriately when used within the scope of a TransformingLazyColumn.

Example of a FilledTonalButton with an icon and secondary label:

import androidx.compose.foundation.layout.size
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.ButtonDefaults
import androidx.wear.compose.material3.FilledTonalButton
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.Text

FilledTonalButton(
    onClick = { /* Do something */ },
    label = { Text("Filled Tonal Button") },
    secondaryLabel = { Text("Secondary label") },
    icon = {
        Icon(
            painter = painterResource(R.drawable.ic_favorite_rounded),
            contentDescription = "Favorite icon",
            modifier = Modifier.size(ButtonDefaults.IconSize)
        )
    },
    modifier = modifier,
)
Parameters
onClick: () -> Unit

Will be called when the user clicks the button

modifier: Modifier = Modifier

Modifier to be applied to the button

onLongClick: (() -> Unit)? = null

Called when this button is long clicked (long-pressed). When this callback is set, onLongClickLabel should be set as well.

onLongClickLabel: String? = null

Semantic / accessibility label for the onLongClick action.

secondaryLabel: (@Composable RowScope.() -> Unit)? = null

A slot for providing the button's secondary label. The contents are expected to be text which is "start" aligned if there is an icon preset and "start" or "center" aligned if not. label and secondaryLabel contents should be consistently aligned.

icon: (@Composable BoxScope.() -> Unit)? = null

A slot for providing the button's icon. The contents are expected to be a horizontally and vertically aligned icon of size ButtonDefaults.IconSize or ButtonDefaults.LargeIconSize.

enabled: Boolean = true

Controls the enabled state of the button. When false, this button will not be clickable

shape: Shape = ButtonDefaults.shape

Defines the button's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material3 Theme

colors: ButtonColors = ButtonDefaults.filledTonalButtonColors()

ButtonColors that will be used to resolve the background and content color for this button in different states. See ButtonDefaults.filledTonalButtonColors.

border: BorderStroke? = null

Optional BorderStroke that will be used to resolve the button border in different states.

contentPadding: PaddingValues = ButtonDefaults.ContentPadding

The spacing values to apply internally between the container and the content

interactionSource: MutableInteractionSource? = null

an optional hoisted MutableInteractionSource for observing and emitting Interactions for this button. You can use this to change the button's appearance or preview the button in different states. Note that if null is provided, interactions will still happen internally.

label: @Composable RowScope.() -> Unit

A slot for providing the button's main label. The contents are expected to be text which is "start" aligned if there is an icon preset and "start" or "center" aligned if not.

FilledTonalIconButton

@Composable
fun FilledTonalIconButton(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    onLongClick: (() -> Unit)? = null,
    onLongClickLabel: String? = null,
    enabled: Boolean = true,
    shapes: IconButtonShapes = IconButtonDefaults.shapes(),
    colors: IconButtonColors = IconButtonDefaults.filledTonalIconButtonColors(),
    border: BorderStroke? = null,
    interactionSource: MutableInteractionSource? = null,
    content: @Composable BoxScope.() -> Unit
): Unit

Wear Material FilledTonalIconButton is a circular, icon-only button with a muted, colored background and a contrasting icon color. It offers a single slot to take an icon or image.

Set the size of the FilledTonalIconButton with Modifier.touchTargetAwareSize to ensure that the recommended minimum touch target size is available.

The recommended icon button sizes are IconButtonDefaults.DefaultButtonSize, IconButtonDefaults.LargeButtonSize, IconButtonDefaults.SmallButtonSize and IconButtonDefaults.ExtraSmallButtonSize.

Use IconButtonDefaults.iconSizeFor to determine the icon size for a given IconButtonDefaults size, or refer to icon sizes IconButtonDefaults.SmallIconSize, IconButtonDefaults.DefaultIconSize, IconButtonDefaults.LargeButtonSize directly.

FilledTonalIconButton can be enabled or disabled. A disabled button will not respond to click events.

Example of FilledTonalIconButton:

import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Favorite
import androidx.wear.compose.material3.FilledTonalIconButton
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.IconButton

FilledTonalIconButton(onClick = { /* Do something */ }) {
    Icon(imageVector = Icons.Filled.Favorite, contentDescription = "Favorite icon")
}
Parameters
onClick: () -> Unit

Will be called when the user clicks the button.

modifier: Modifier = Modifier

Modifier to be applied to the button.

onLongClick: (() -> Unit)? = null

Called when this button is long clicked (long-pressed). When this callback is set, onLongClickLabel should be set as well.

onLongClickLabel: String? = null

Semantic / accessibility label for the onLongClick action.

enabled: Boolean = true

Controls the enabled state of the button. When false, this button will not be clickable.

shapes: IconButtonShapes = IconButtonDefaults.shapes()

Defines the shape for this button. Defaults to a static shape based on IconButtonDefaults.shape, but animated versions are available through IconButtonDefaults.animatedShapes.

colors: IconButtonColors = IconButtonDefaults.filledTonalIconButtonColors()

IconButtonColors that will be used to resolve the background and icon color for this button in different states.

border: BorderStroke? = null

Optional BorderStroke for the icon button border.

interactionSource: MutableInteractionSource? = null

an optional hoisted MutableInteractionSource for observing and emitting Interactions for this button. You can use this to change the button's appearance or preview the button in different states. Note that if null is provided, interactions will still happen internally.

content: @Composable BoxScope.() -> Unit

The content displayed on the icon button, expected to be icon or image.

HorizontalPageIndicator

@Composable
fun HorizontalPageIndicator(
    pagerState: PagerState,
    modifier: Modifier = Modifier,
    selectedColor: Color = PageIndicatorDefaults.selectedColor,
    unselectedColor: Color = PageIndicatorDefaults.unselectedColor,
    backgroundColor: Color = PageIndicatorDefaults.backgroundColor
): Unit

Horizontal page indicator for use with HorizontalPager, representing the currently active page and the approximate number of pages. Pages are indicated as a Circle shape. The indicator shows up to six pages individually - if there are more than six pages, HorizontalPageIndicator shows a smaller indicator to the left and/or right to indicate that more pages are available.

This is a full screen component and will occupy the whole screen. However it's not actionable, so it's not expected to interfere with anything on the screen.

Here's how different positions 0..10 might be visually represented: "X" is selected item, "O" and "o" full and half size items respectively.

O X O O O o - 2nd position out of 10. There are no more items on the left but more on the right.

o O O O X o - current page could be 6, 7 or 8 out of 10, as there are more potential pages on the left and on the right.

o O O O X O - current page is 9 out of 10, as there no more items on the right

HorizontalPageIndicator can be linear or curved, depending on the screen shape of the device - for circular screens it will be curved, whilst for square screens it will be linear.

Example usage with HorizontalPager:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.foundation.pager.rememberPagerState
import androidx.wear.compose.material3.HorizontalPageIndicator
import androidx.wear.compose.material3.HorizontalPagerScaffold
import androidx.wear.compose.material3.Text

val pageCount = 9
val pagerState = rememberPagerState { pageCount }

Box {
    HorizontalPagerScaffold(
        pagerState = pagerState,
        pageIndicator = { HorizontalPageIndicator(pagerState = pagerState) }
    ) { page ->
        Box(modifier = Modifier.fillMaxSize()) {
            Text(modifier = Modifier.align(Alignment.Center), text = "Page #$page")
        }
    }
}
Parameters
pagerState: PagerState

State of the HorizontalPager used to control this indicator

modifier: Modifier = Modifier

Modifier to be applied to the HorizontalPageIndicator

selectedColor: Color = PageIndicatorDefaults.selectedColor

The color which will be used for a selected indicator item.

unselectedColor: Color = PageIndicatorDefaults.unselectedColor

The color which will be used for an unselected indicator item.

backgroundColor: Color = PageIndicatorDefaults.backgroundColor

The color which will be used for an indicator background.

HorizontalPagerScaffold

@Composable
fun HorizontalPagerScaffold(
    pagerState: PagerState,
    modifier: Modifier = Modifier,
    pageIndicator: (@Composable BoxScope.() -> Unit)? = { HorizontalPageIndicator(pagerState) },
    pageIndicatorAnimationSpec: AnimationSpec<Float>? = null,
    rotaryScrollableBehavior: RotaryScrollableBehavior? = null,
    content: @Composable PagerScope.(page: Int) -> Unit
): Unit

HorizontalPagerScaffold is one of the Wear Material3 scaffold components.

The scaffold components AppScaffold and HorizontalPagerScaffold lay out the structure of a Pager and coordinate transitions of the HorizontalPageIndicator and TimeText 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.

Example of using AppScaffold and HorizontalPagerScaffold:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.foundation.pager.rememberPagerState
import androidx.wear.compose.material3.AppScaffold
import androidx.wear.compose.material3.HorizontalPagerScaffold
import androidx.wear.compose.material3.ScreenScaffold
import androidx.wear.compose.material3.Text

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

    HorizontalPagerScaffold(pagerState = pagerState) { page ->
        ScreenScaffold {
            Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
                Text("Page $page")
            }
        }
    }
}
Parameters
pagerState: PagerState

The state of the pager controlling the page content.

modifier: Modifier = Modifier

The modifier to be applied to the scaffold.

pageIndicator: (@Composable BoxScope.() -> Unit)? = { HorizontalPageIndicator(pagerState) }

A composable function that defines the page indicator to be displayed. By default, it uses a HorizontalPageIndicator.

pageIndicatorAnimationSpec: AnimationSpec<Float>? = null
  • An optional parameter to set whether the page indicator should fade out when paging has finished. This is useful for when the underlying page content conflicts with the page indicator. By default this is null, so the page indicator will be visible at all times, setting this to PagerScaffoldDefaults.FadeOutAnimation ensures the indicator only shows during paging, and fades out when the Pager is idle.

rotaryScrollableBehavior: RotaryScrollableBehavior? = null

Parameter for changing rotary behavior. By default rotary support is disabled for HorizontalPagerScaffold. It can be enabled by passing RotaryScrollableDefaults.snapBehavior with pagerState parameter.

content: @Composable PagerScope.(page: Int) -> Unit

A composable function that takes the current page index as a parameter and defines the content to be displayed on that page.

@Composable
fun Icon(
    bitmap: ImageBitmap,
    contentDescription: String?,
    modifier: Modifier = Modifier,
    tint: Color = LocalContentColor.current
): Unit

Icon component that draws bitmap using tint, defaulting to LocalContentColor. For a clickable icon, see Button.

Parameters
bitmap: ImageBitmap

ImageBitmap to draw inside this Icon

contentDescription: String?

Text used by accessibility services to describe what this icon represents. This should always be provided unless this icon is used for decorative purposes, and does not represent a meaningful action that a user can take. This text should be localized, such as by using androidx.compose.ui.res.stringResource or similar

modifier: Modifier = Modifier

Optional Modifier for this Icon

tint: Color = LocalContentColor.current

Tint to be applied to bitmap. If Color.Unspecified is provided, then no tint is applied

@Composable
fun Icon(
    imageVector: ImageVector,
    contentDescription: String?,
    modifier: Modifier = Modifier,
    tint: Color = LocalContentColor.current
): Unit

Icon component that draws imageVector using tint, defaulting to LocalContentColor. For a clickable icon, see IconButton.

Parameters
imageVector: ImageVector

ImageVector to draw inside this Icon

contentDescription: String?

Text used by accessibility services to describe what this icon represents. This should always be provided unless this icon is used for decorative purposes, and does not represent a meaningful action that a user can take. This text should be localized, such as by using androidx.compose.ui.res.stringResource or similar

modifier: Modifier = Modifier

Optional Modifier for this Icon

tint: Color = LocalContentColor.current

Tint to be applied to imageVector. If Color.Unspecified is provided, then no tint is applied

@Composable
fun Icon(
    painter: Painter,
    contentDescription: String?,
    modifier: Modifier = Modifier,
    tint: Color = LocalContentColor.current
): Unit

Icon component that draws a painter using tint, defaulting to LocalContentColor. For a clickable icon, see Button.

Parameters
painter: Painter

Painter to draw inside this Icon

contentDescription: String?

Text used by accessibility services to describe what this icon represents. This should always be provided unless this icon is used for decorative purposes, and does not represent a meaningful action that a user can take. This text should be localized, such as by using androidx.compose.ui.res.stringResource or similar

modifier: Modifier = Modifier

Optional Modifier for this Icon

tint: Color = LocalContentColor.current

Tint to be applied to painter. If Color.Unspecified is provided, then no tint is applied

@Composable
fun IconButton(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    onLongClick: (() -> Unit)? = null,
    onLongClickLabel: String? = null,
    enabled: Boolean = true,
    shapes: IconButtonShapes = IconButtonDefaults.shapes(),
    colors: IconButtonColors = IconButtonDefaults.iconButtonColors(),
    border: BorderStroke? = null,
    interactionSource: MutableInteractionSource? = null,
    content: @Composable BoxScope.() -> Unit
): Unit

Wear Material IconButton is a circular, icon-only button with transparent background and no border. It offers a single slot to take icon or image content.

Set the size of the IconButton with Modifier.touchTargetAwareSize to ensure that the recommended minimum touch target size is available.

The recommended IconButton sizes are IconButtonDefaults.DefaultButtonSize, IconButtonDefaults.LargeButtonSize, IconButtonDefaults.SmallButtonSize and IconButtonDefaults.ExtraSmallButtonSize.

Use IconButtonDefaults.iconSizeFor to determine the icon size for a given IconButtonDefaults size, or refer to icon sizes IconButtonDefaults.SmallIconSize, IconButtonDefaults.DefaultIconSize, IconButtonDefaults.LargeButtonSize directly.

IconButton can be enabled or disabled. A disabled button will not respond to click events.

Example of an IconButton:

import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Favorite
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.IconButton

IconButton(onClick = { /* Do something */ }) {
    Icon(imageVector = Icons.Filled.Favorite, contentDescription = "Favorite icon")
}

Example of an IconButton with onLongClick:

import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Favorite
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.IconButton

IconButton(
    onClick = { /* Do something for onClick*/ },
    onLongClick = onLongClick,
    onLongClickLabel = "Long click"
) {
    Icon(imageVector = Icons.Filled.Favorite, contentDescription = "Favorite icon")
}

Example of an IconButton with shape animation of rounded corners on press:

import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Favorite
import androidx.wear.compose.material3.FilledIconButton
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.IconButton
import androidx.wear.compose.material3.IconButtonDefaults

FilledIconButton(
    onClick = { /* Do something */ },
    shapes = IconButtonDefaults.animatedShapes(),
    colors = colors
) {
    Icon(imageVector = Icons.Filled.Favorite, contentDescription = "Favorite icon")
}

Example of an IconButton with image content:

import androidx.compose.foundation.Image
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.layout.ContentScale
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.IconButton
import androidx.wear.compose.material3.IconButtonDefaults

IconButton(
    onClick = { /* Do something */ },
    shapes = shapes,
) {
    Image(
        painter = painter,
        contentDescription = null,
        contentScale = ContentScale.Crop,
        modifier =
            if (enabled) Modifier else Modifier.alpha(IconButtonDefaults.disabledImageOpacity)
    )
}
Parameters
onClick: () -> Unit

Will be called when the user clicks the button.

modifier: Modifier = Modifier

Modifier to be applied to the button.

onLongClick: (() -> Unit)? = null

Called when this button is long clicked (long-pressed). When this callback is set, onLongClickLabel should be set as well.

onLongClickLabel: String? = null

Semantic / accessibility label for the onLongClick action.

enabled: Boolean = true

Controls the enabled state of the button. When false, this button will not be clickable.

shapes: IconButtonShapes = IconButtonDefaults.shapes()

Defines the shape for this button. Defaults to a static shape based on IconButtonDefaults.shape, but animated versions are available through IconButtonDefaults.animatedShapes.

colors: IconButtonColors = IconButtonDefaults.iconButtonColors()

IconButtonColors that will be used to resolve the background and icon color for this button in different states.

border: BorderStroke? = null

Optional BorderStroke for the icon button border.

interactionSource: MutableInteractionSource? = null

an optional hoisted MutableInteractionSource for observing and emitting Interactions for this button. You can use this to change the button's appearance or preview the button in different states. Note that if null is provided, interactions will still happen internally.

content: @Composable BoxScope.() -> Unit

The content displayed on the icon button, expected to be icon or image.

@Composable
fun IconToggleButton(
    checked: Boolean,
    onCheckedChange: (Boolean) -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    colors: IconToggleButtonColors = IconToggleButtonDefaults.iconToggleButtonColors(),
    interactionSource: MutableInteractionSource? = null,
    shapes: IconToggleButtonShapes = IconToggleButtonDefaults.shapes(),
    border: BorderStroke? = null,
    content: @Composable BoxScope.() -> Unit
): Unit

Wear Material IconToggleButton is a filled icon toggle button which switches between primary colors and tonal colors depending on checked value, and offers a single slot for icon or image.

Set the size of the IconToggleButton with Modifier.touchTargetAwareSize to ensure that the background padding will correctly reach the edge of the minimum touch target. The recommended icon toggle button sizes are IconToggleButtonDefaults.DefaultButtonSize, IconToggleButtonDefaults.SmallButtonSize, IconToggleButtonDefaults.LargeButtonSize and IconToggleButtonDefaults.ExtraLargeButtonSize.

Use IconToggleButtonDefaults.iconSizeFor to determine the icon size for a given IconToggleButton size, or refer to icon sizes, IconToggleButtonDefaults.DefaultIconSize, IconToggleButtonDefaults.LargeIconSize, IconToggleButtonDefaults.ExtraLargeIconSize directly.

IconToggleButton can be enabled or disabled. A disabled button will not respond to click events. When enabled, the checked and unchecked events are propagated by onCheckedChange.

A simple icon toggle button using the default colors, animated when pressed.

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.width
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.IconToggleButton
import androidx.wear.compose.material3.IconToggleButtonDefaults

var firstChecked by remember { mutableStateOf(true) }
var secondChecked by remember { mutableStateOf(false) }

Row(
    modifier = Modifier.fillMaxSize(),
    horizontalArrangement = Arrangement.Center,
    verticalAlignment = Alignment.CenterVertically
) {
    IconToggleButton(
        checked = firstChecked,
        onCheckedChange = { firstChecked = !firstChecked },
        shapes = IconToggleButtonDefaults.animatedShapes(),
    ) {
        Icon(imageVector = Icons.Filled.Favorite, contentDescription = "Favorite icon")
    }

    Spacer(modifier = Modifier.width(5.dp))

    IconToggleButton(
        checked = secondChecked,
        onCheckedChange = { secondChecked = !secondChecked },
        shapes = IconToggleButtonDefaults.animatedShapes(),
    ) {
        Icon(imageVector = Icons.Filled.Favorite, contentDescription = "Favorite icon")
    }
}

A simple icon toggle button using the default colors, animated when pressed, with different shapes and icons for the checked and unchecked states.

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.width
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.IconToggleButton
import androidx.wear.compose.material3.IconToggleButtonDefaults
import androidx.wear.compose.material3.samples.icons.WifiOffIcon
import androidx.wear.compose.material3.samples.icons.WifiOnIcon

var firstChecked by remember { mutableStateOf(true) }
var secondChecked by remember { mutableStateOf(false) }

Row(
    modifier = Modifier.fillMaxSize(),
    horizontalArrangement = Arrangement.Center,
    verticalAlignment = Alignment.CenterVertically
) {
    IconToggleButton(
        checked = firstChecked,
        onCheckedChange = { firstChecked = !firstChecked },
        shapes = IconToggleButtonDefaults.variantAnimatedShapes(),
    ) {
        if (firstChecked) {
            WifiOnIcon()
        } else {
            WifiOffIcon()
        }
    }

    Spacer(modifier = Modifier.width(5.dp))

    IconToggleButton(
        checked = secondChecked,
        onCheckedChange = { secondChecked = !secondChecked },
        shapes = IconToggleButtonDefaults.variantAnimatedShapes(),
    ) {
        if (secondChecked) {
            WifiOnIcon()
        } else {
            WifiOffIcon()
        }
    }
}
Parameters
checked: Boolean

Boolean flag indicating whether this toggle button is currently checked.

onCheckedChange: (Boolean) -> Unit

Callback to be invoked when this toggle button is clicked.

modifier: Modifier = Modifier

Modifier to be applied to the toggle button.

enabled: Boolean = true

Controls the enabled state of the toggle button. When false, this toggle button will not be clickable.

colors: IconToggleButtonColors = IconToggleButtonDefaults.iconToggleButtonColors()

IconToggleButtonColors that will be used to resolve the container and content color for this toggle button.

interactionSource: MutableInteractionSource? = null

an optional hoisted MutableInteractionSource for observing and emitting Interactions for this button. You can use this to change the button's appearance or preview the button in different states. Note that if null is provided, interactions will still happen internally.

shapes: IconToggleButtonShapes = IconToggleButtonDefaults.shapes()

Defines the shape for this toggle button. Defaults to a static shape based on IconToggleButtonDefaults.shape, but animated versions are available through IconToggleButtonDefaults.animatedShapes and IconToggleButtonDefaults.variantAnimatedShapes.

border: BorderStroke? = null

Optional BorderStroke for the IconToggleButton.

content: @Composable BoxScope.() -> Unit

The content to be drawn inside the toggle button.

@Composable
fun LevelIndicator(
    value: () -> Float,
    modifier: Modifier = Modifier,
    valueRange: ClosedFloatingPointRange<Float> = 0f..1f,
    enabled: Boolean = true,
    colors: LevelIndicatorColors = LevelIndicatorDefaults.colors(),
    strokeWidth: Dp = LevelIndicatorDefaults.StrokeWidth,
    sweepAngle: Float = LevelIndicatorDefaults.SweepAngle,
    reverseDirection: Boolean = false
): Unit

Creates a LevelIndicator for screens that that control a setting such as volume with either rotating side button, rotating bezel or a Stepper.

Example of LevelIndicator with a Stepper:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.material3.LevelIndicator
import androidx.wear.compose.material3.Stepper
import androidx.wear.compose.material3.StepperDefaults
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.samples.icons.VolumeDownIcon
import androidx.wear.compose.material3.samples.icons.VolumeUpIcon

var value by remember { mutableFloatStateOf(2f) }
val valueRange = 0f..4f
Box(modifier = Modifier.fillMaxSize()) {
    Stepper(
        value = value,
        onValueChange = { value = it },
        valueRange = valueRange,
        steps = 7,
        decreaseIcon = { VolumeDownIcon(StepperDefaults.IconSize) },
        increaseIcon = { VolumeUpIcon(StepperDefaults.IconSize) },
    ) {
        Text(String.format("Value: %.1f".format(value)))
    }
    LevelIndicator(
        value = { value },
        valueRange = valueRange,
        modifier = Modifier.align(Alignment.CenterStart)
    )
}
Parameters
value: () -> Float

Value of the indicator in the valueRange.

modifier: Modifier = Modifier

Modifier to be applied to the component

valueRange: ClosedFloatingPointRange<Float> = 0f..1f

range of values that value can take

enabled: Boolean = true

Controls the enabled state of LevelIndicator - when false, disabled colors will be used.

colors: LevelIndicatorColors = LevelIndicatorDefaults.colors()

LevelIndicatorColors that will be used to resolve the indicator and track colors for this LevelIndicator in different states

strokeWidth: Dp = LevelIndicatorDefaults.StrokeWidth

The stroke width for the indicator and track strokes

sweepAngle: Float = LevelIndicatorDefaults.SweepAngle

The angle covered by the curved LevelIndicator

reverseDirection: Boolean = false

Reverses direction of PositionIndicator if true

@Composable
fun LevelIndicator(
    value: () -> Int,
    valueProgression: IntProgression,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    colors: LevelIndicatorColors = LevelIndicatorDefaults.colors(),
    strokeWidth: Dp = LevelIndicatorDefaults.StrokeWidth,
    sweepAngle: Float = LevelIndicatorDefaults.SweepAngle,
    reverseDirection: Boolean = false
): Unit

Creates a LevelIndicator for screens that that control a setting such as volume with either rotating side button, rotating bezel or a Stepper.

Example of LevelIndicator with a Stepper working on an IntProgression:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.material3.LevelIndicator
import androidx.wear.compose.material3.Stepper
import androidx.wear.compose.material3.StepperDefaults
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.samples.icons.VolumeDownIcon
import androidx.wear.compose.material3.samples.icons.VolumeUpIcon

var value by remember { mutableIntStateOf(3) }
val valueProgression = 0..10
Box(modifier = Modifier.fillMaxSize()) {
    Stepper(
        value = value,
        onValueChange = { value = it },
        valueProgression = valueProgression,
        decreaseIcon = { VolumeDownIcon(StepperDefaults.IconSize) },
        increaseIcon = { VolumeUpIcon(StepperDefaults.IconSize) },
    ) {
        Text(String.format("Value: %d".format(value)))
    }
    LevelIndicator(
        value = { value },
        valueProgression = valueProgression,
        modifier = Modifier.align(Alignment.CenterStart)
    )
}
Parameters
value: () -> Int

Current value of the Stepper. If outside of valueProgression provided, value will be coerced to this range.

valueProgression: IntProgression

Progression of values that LevelIndicator value can take. Consists of rangeStart, rangeEnd and step. Range will be equally divided by step size

modifier: Modifier = Modifier

Modifier to be applied to the component

enabled: Boolean = true

Controls the enabled state of LevelIndicator - when false, disabled colors will be used.

colors: LevelIndicatorColors = LevelIndicatorDefaults.colors()

LevelIndicatorColors that will be used to resolve the indicator and track colors for this LevelIndicator in different states

strokeWidth: Dp = LevelIndicatorDefaults.StrokeWidth

The stroke width for the indicator and track strokes

sweepAngle: Float = LevelIndicatorDefaults.SweepAngle

The angle covered by the curved LevelIndicator

reverseDirection: Boolean = false

Reverses direction of PositionIndicator if true

LinearProgressIndicator

@Composable
fun LinearProgressIndicator(
    progress: () -> Float,
    modifier: Modifier = Modifier,
    colors: ProgressIndicatorColors = ProgressIndicatorDefaults.colors(),
    strokeWidth: Dp = LinearProgressIndicatorDefaults.StrokeWidthLarge,
    enabled: Boolean = true
): Unit

Material Design linear progress indicator.

The LinearProgressIndicator displays progress as a horizontal bar, consisting of two visual components:

  • Track: The background line representing the total range of progress.

  • Indicator: A colored line that fills the track, indicating the current progress value.

The indicator also includes a small dot at the end of the progress line. This dot serves as an accessibility feature to show the range of the indicator.

Progress updates will be animated. Small progress values that are larger than zero will be rounded up to at least the stroke width.

LinearProgressIndicator sample:

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.semantics.ProgressBarRangeInfo
import androidx.compose.ui.semantics.progressBarRangeInfo
import androidx.compose.ui.semantics.semantics
import androidx.wear.compose.material3.LinearProgressIndicator
import androidx.wear.compose.material3.MaterialTheme

Box(
    modifier = Modifier.background(MaterialTheme.colorScheme.background).fillMaxSize(),
    contentAlignment = Alignment.Center
) {
    LinearProgressIndicator(
        progress = progress,
        enabled = enabled,
        modifier =
            Modifier.semantics(mergeDescendants = true) {
                progressBarRangeInfo = ProgressBarRangeInfo(progress(), 0f..1f)
            }
    )
}
Parameters
progress: () -> Float

The progress of this progress indicator where 0.0 represents no progress and 1.0 represents completion. Values outside of this range are coerced into the range 0..1. Progress value changes will be animated.

modifier: Modifier = Modifier

Modifier to be applied to the LinearProgressIndicator.

colors: ProgressIndicatorColors = ProgressIndicatorDefaults.colors()

ProgressIndicatorColors that will be used to resolve the indicator and track colors for this progress indicator in different states.

strokeWidth: Dp = LinearProgressIndicatorDefaults.StrokeWidthLarge

The stroke width for the progress indicator. The minimum value is LinearProgressIndicatorDefaults.StrokeWidthSmall to ensure that the dot drawn at the end of the range can be distinguished.

enabled: Boolean = true

controls the enabled state. Although this component is not clickable, it can be contained within a clickable component. When enabled is false, this component will appear visually disabled.

LinearProgressIndicatorContent

@Composable
fun LinearProgressIndicatorContent(
    progress: () -> Float,
    modifier: Modifier = Modifier,
    colors: ProgressIndicatorColors = ProgressIndicatorDefaults.colors(),
    strokeWidth: Dp = LinearProgressIndicatorDefaults.StrokeWidthLarge,
    enabled: Boolean = true
): Unit

Linear progress indicator content with no progress animations.

Parameters
progress: () -> Float

The progress of this progress indicator where 0.0 represents no progress and 1.0 represents completion. Values outside of this range are coerced into the range 0..1.

modifier: Modifier = Modifier

Modifier to be applied to the LinearProgressIndicator.

colors: ProgressIndicatorColors = ProgressIndicatorDefaults.colors()

ProgressIndicatorColors that will be used to resolve the indicator and track colors for this progress indicator in different states.

strokeWidth: Dp = LinearProgressIndicatorDefaults.StrokeWidthLarge

The stroke width for the progress indicator. The minimum value is LinearProgressIndicatorDefaults.StrokeWidthSmall to ensure that the dot drawn at the end of the range can be distinguished.

enabled: Boolean = true

controls the enabled state. Although this component is not clickable, it can be contained within a clickable component. When enabled is false, this component will appear visually disabled.

@Composable
fun ListHeader(
    modifier: Modifier = Modifier,
    backgroundColor: Color = Color.Transparent,
    contentColor: Color = ListHeaderDefaults.ContentColor,
    contentPadding: PaddingValues = ListHeaderDefaults.ContentPadding,
    content: @Composable RowScope.() -> Unit
): Unit

A slot based composable for creating a list header item. ListHeaders are typically expected to be a few words of text on a single line. The contents will be start and end padded.

ListHeader scales itself appropriately when used within the scope of a TransformingLazyColumn.

Example of a ListHeader:

import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.wear.compose.foundation.lazy.ScalingLazyColumn
import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.ButtonDefaults
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.ListHeader
import androidx.wear.compose.material3.ListSubHeader
import androidx.wear.compose.material3.ScreenScaffold
import androidx.wear.compose.material3.Text

val scrollState = rememberScalingLazyListState()
val horizontalPadding = LocalConfiguration.current.screenWidthDp.dp * 0.052f

ScreenScaffold(scrollState = scrollState) {
    ScalingLazyColumn(
        state = scrollState,
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        contentPadding = PaddingValues(horizontal = horizontalPadding)
    ) {
        item { ListHeader { Text("Settings") } }
        item {
            ListSubHeader(
                icon = {
                    Icon(
                        painter = painterResource(R.drawable.ic_connectivity),
                        contentDescription = "Connectivity",
                    )
                },
                label = { Text("Connectivity") }
            )
        }
        item {
            Button(
                modifier = Modifier.fillMaxWidth(),
                onClick = {},
                icon = {
                    Icon(
                        painter = painterResource(R.drawable.ic_bluetooth),
                        contentDescription = "Bluetooth",
                        modifier = Modifier.size(ButtonDefaults.IconSize)
                    )
                },
            ) {
                Text("Bluetooth")
            }
        }
        item {
            Button(
                modifier = Modifier.fillMaxWidth(),
                onClick = {},
                icon = {
                    Icon(
                        painter = painterResource(R.drawable.ic_wifi),
                        contentDescription = "Wifi",
                        modifier = Modifier.size(ButtonDefaults.IconSize)
                    )
                },
            ) {
                Text("Wifi")
            }
        }
        item { ListSubHeader { Text("Display") } }
        item {
            Button(modifier = Modifier.fillMaxWidth(), onClick = {}) {
                Text("Change Watchface")
            }
        }
        item { Button(modifier = Modifier.fillMaxWidth(), onClick = {}) { Text("Brightness") } }
    }
}
Parameters
modifier: Modifier = Modifier

The modifier for the ListHeader.

backgroundColor: Color = Color.Transparent

The background color to apply - typically Color.Transparent

contentColor: Color = ListHeaderDefaults.ContentColor

The color to apply to content.

contentPadding: PaddingValues = ListHeaderDefaults.ContentPadding

The spacing values to apply internally between the container and the content.

content: @Composable RowScope.() -> Unit

Slot for ListHeader content, expected to be a single line of text.

@Composable
fun ListSubHeader(
    modifier: Modifier = Modifier,
    backgroundColor: Color = Color.Transparent,
    contentColor: Color = ListHeaderDefaults.subHeaderContentColor,
    contentPadding: PaddingValues = ListHeaderDefaults.SubHeaderContentPadding,
    icon: (@Composable BoxScope.() -> Unit)? = null,
    label: @Composable RowScope.() -> Unit
): Unit

A two slot based composable for creating a list sub-header item. ListSubHeaders offer slots for an icon and for a text label. The contents will be start and end padded.

ListSubHeader scales itself appropriately when used within the scope of a TransformingLazyColumn.

Example with use of ListSubHeader:

import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.wear.compose.foundation.lazy.ScalingLazyColumn
import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.ButtonDefaults
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.ListHeader
import androidx.wear.compose.material3.ListSubHeader
import androidx.wear.compose.material3.ScreenScaffold
import androidx.wear.compose.material3.Text

val scrollState = rememberScalingLazyListState()
val horizontalPadding = LocalConfiguration.current.screenWidthDp.dp * 0.052f

ScreenScaffold(scrollState = scrollState) {
    ScalingLazyColumn(
        state = scrollState,
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        contentPadding = PaddingValues(horizontal = horizontalPadding)
    ) {
        item { ListHeader { Text("Settings") } }
        item {
            ListSubHeader(
                icon = {
                    Icon(
                        painter = painterResource(R.drawable.ic_connectivity),
                        contentDescription = "Connectivity",
                    )
                },
                label = { Text("Connectivity") }
            )
        }
        item {
            Button(
                modifier = Modifier.fillMaxWidth(),
                onClick = {},
                icon = {
                    Icon(
                        painter = painterResource(R.drawable.ic_bluetooth),
                        contentDescription = "Bluetooth",
                        modifier = Modifier.size(ButtonDefaults.IconSize)
                    )
                },
            ) {
                Text("Bluetooth")
            }
        }
        item {
            Button(
                modifier = Modifier.fillMaxWidth(),
                onClick = {},
                icon = {
                    Icon(
                        painter = painterResource(R.drawable.ic_wifi),
                        contentDescription = "Wifi",
                        modifier = Modifier.size(ButtonDefaults.IconSize)
                    )
                },
            ) {
                Text("Wifi")
            }
        }
        item { ListSubHeader { Text("Display") } }
        item {
            Button(modifier = Modifier.fillMaxWidth(), onClick = {}) {
                Text("Change Watchface")
            }
        }
        item { Button(modifier = Modifier.fillMaxWidth(), onClick = {}) { Text("Brightness") } }
    }
}
Parameters
modifier: Modifier = Modifier

The modifier for the ListSubHeader.

backgroundColor: Color = Color.Transparent

The background color to apply - typically Color.Transparent

contentColor: Color = ListHeaderDefaults.subHeaderContentColor

The color to apply to content.

contentPadding: PaddingValues = ListHeaderDefaults.SubHeaderContentPadding

The spacing values to apply internally between the container and the content.

icon: (@Composable BoxScope.() -> Unit)? = null

A slot for providing icon to the ListSubHeader.

label: @Composable RowScope.() -> Unit

A slot for providing label to the ListSubHeader.

@Composable
fun MaterialTheme(
    colorScheme: ColorScheme = MaterialTheme.colorScheme,
    typography: Typography = MaterialTheme.typography,
    shapes: Shapes = MaterialTheme.shapes,
    motionScheme: MotionScheme = MaterialTheme.motionScheme,
    content: @Composable () -> Unit
): Unit

MaterialTheme defines the styling principles from the Wear Material3 design specification which extends the Material design specification.

Wear Material components from package/sub-packages in androidx.wear.compose.material3 use values provided here when retrieving default values.

All values may be set by providing this component with the colors, typography, and shapes attributes. Use this to configure the overall theme of elements within this MaterialTheme.

Any values that are not set will inherit the current value from the theme, falling back to the defaults if there is no parent MaterialTheme. This allows using a MaterialTheme at the top of your application, and then separate MaterialTheme(s) for different screens / parts of your UI, overriding only the parts of the theme definition that need to change.

For more information, see the Theming guide.

Parameters
colorScheme: ColorScheme = MaterialTheme.colorScheme

A complete definition of the Wear Material Color theme for this hierarchy

typography: Typography = MaterialTheme.typography

A set of text styles to be used as this hierarchy's typography system

shapes: Shapes = MaterialTheme.shapes

A set of shapes to be used by the components in this hierarchy

motionScheme: MotionScheme = MaterialTheme.motionScheme

a set of motion specs used to animate content for this hierarchy.

content: @Composable () -> Unit

Slot for composable content displayed with this theme

@Composable
fun OpenOnPhoneDialog(
    show: Boolean,
    onDismissRequest: () -> Unit,
    modifier: Modifier = Modifier,
    curvedText: (CurvedScope.() -> Unit)? = OpenOnPhoneDialogDefaults.curvedText(),
    colors: OpenOnPhoneDialogColors = OpenOnPhoneDialogDefaults.colors(),
    properties: DialogProperties = DialogProperties(),
    durationMillis: Long = OpenOnPhoneDialogDefaults.DurationMillis,
    content: @Composable BoxScope.() -> Unit = OpenOnPhoneDialogDefaults.OpenOnPhoneIcon
): Unit

A full-screen dialog that displays an animated icon with a curved text at the bottom.

The dialog will be showing a message to the user for durationMillis. After a specified timeout, the onDismissRequest callback will be invoked, where it's up to the caller to handle the dismissal. To hide the dialog, show parameter should be set to false.

This dialog is typically used to indicate that an action has been initiated and will continue on the user's phone. Once this dialog is displayed, it's developer responsibility to establish the connection between the watch and the phone.

Example of an OpenOnPhoneDialog usage:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.material3.FilledTonalButton
import androidx.wear.compose.material3.OpenOnPhoneDialog
import androidx.wear.compose.material3.Text

var showConfirmation by remember { mutableStateOf(false) }

Box(Modifier.fillMaxSize()) {
    FilledTonalButton(
        modifier = Modifier.align(Alignment.Center),
        onClick = { showConfirmation = true },
        label = { Text("Open on phone") }
    )
}

OpenOnPhoneDialog(
    show = showConfirmation,
    onDismissRequest = { showConfirmation = false },
)
Parameters
show: Boolean

A boolean indicating whether the dialog should be displayed.

onDismissRequest: () -> Unit

A lambda function to be called when the dialog is dismissed - either by swiping right or when the durationMillis has passed.

modifier: Modifier = Modifier

Modifier to be applied to the dialog content.

curvedText: (CurvedScope.() -> Unit)? = OpenOnPhoneDialogDefaults.curvedText()

A slot for displaying curved text content which will be shown along the bottom edge of the dialog. Defaults to a localized open on phone message.

colors: OpenOnPhoneDialogColors = OpenOnPhoneDialogDefaults.colors()

OpenOnPhoneDialogColors that will be used to resolve the colors used for this OpenOnPhoneDialog.

properties: DialogProperties = DialogProperties()

An optional DialogProperties object for configuring the dialog's behavior.

durationMillis: Long = OpenOnPhoneDialogDefaults.DurationMillis

The duration in milliseconds for which the dialog is displayed. Defaults to OpenOnPhoneDialogDefaults.DurationMillis.

content: @Composable BoxScope.() -> Unit = OpenOnPhoneDialogDefaults.OpenOnPhoneIcon

A slot for displaying an icon inside the open on phone dialog, which can be animated. Defaults to OpenOnPhoneDialogDefaults.OpenOnPhoneIcon.

@Composable
fun OutlinedButton(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    onLongClick: (() -> Unit)? = null,
    onLongClickLabel: String? = null,
    enabled: Boolean = true,
    shape: Shape = ButtonDefaults.shape,
    colors: ButtonColors = ButtonDefaults.outlinedButtonColors(),
    border: BorderStroke? = ButtonDefaults.outlinedButtonBorder(enabled),
    contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
    interactionSource: MutableInteractionSource? = null,
    content: @Composable RowScope.() -> Unit
): Unit

Base level Wear Material3 OutlinedButton that offers a single slot to take any content. Used as the container for more opinionated OutlinedButton components that take specific content such as icons and labels.

The OutlinedButton is Stadium-shaped by default and has a max height designed to take no more than two lines of text of Typography.labelMedium style. With localisation and/or large font sizes, the text can extend to a maximum of 3 lines in which case, the OutlinedButton height adjusts to accommodate the contents. The OutlinedButton can have an icon or image horizontally parallel to the two lines of text.

OutlinedButton takes the ButtonDefaults.outlinedButtonColors color scheme by default, with a transparent background and a thin border. This is a medium-emphasis button for important, non-primary actions that need attention.

Other recommended buttons with ButtonColors for different levels of emphasis are: Button which defaults to ButtonDefaults.buttonColors, FilledTonalButton which defaults to ButtonDefaults.filledTonalButtonColors, ChildButton which defaults to ButtonDefaults.childButtonColors. Buttons can also take an image background using ButtonDefaults.imageBackgroundButtonColors.

OutlinedButton can be enabled or disabled. A disabled button will not respond to click events.

OutlinedButton scales itself appropriately when used within the scope of a TransformingLazyColumn.

Example of an OutlinedButton:

import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.OutlinedButton
import androidx.wear.compose.material3.Text

OutlinedButton(
    onClick = { /* Do something */ },
    label = { Text("Outlined Button") },
    modifier = modifier,
)
Parameters
onClick: () -> Unit

Will be called when the user clicks the button

modifier: Modifier = Modifier

Modifier to be applied to the button

onLongClick: (() -> Unit)? = null

Called when this button is long clicked (long-pressed). When this callback is set, onLongClickLabel should be set as well.

onLongClickLabel: String? = null

Semantic / accessibility label for the onLongClick action.

enabled: Boolean = true

Controls the enabled state of the button. When false, this button will not be clickable

shape: Shape = ButtonDefaults.shape

Defines the button's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material3 Theme

colors: ButtonColors = ButtonDefaults.outlinedButtonColors()

ButtonColors that will be used to resolve the background and content color for this button in different states. See ButtonDefaults.outlinedButtonColors.

border: BorderStroke? = ButtonDefaults.outlinedButtonBorder(enabled)

Optional BorderStroke that will be used to resolve the border for this button in different states. See ButtonDefaults.outlinedButtonBorder.

contentPadding: PaddingValues = ButtonDefaults.ContentPadding

The spacing values to apply internally between the container and the content

interactionSource: MutableInteractionSource? = null

an optional hoisted MutableInteractionSource for observing and emitting Interactions for this button. You can use this to change the button's appearance or preview the button in different states. Note that if null is provided, interactions will still happen internally.

content: @Composable RowScope.() -> Unit

Slot for composable body content displayed on the OutlinedButton

@Composable
fun OutlinedButton(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    onLongClick: (() -> Unit)? = null,
    onLongClickLabel: String? = null,
    secondaryLabel: (@Composable RowScope.() -> Unit)? = null,
    icon: (@Composable BoxScope.() -> Unit)? = null,
    enabled: Boolean = true,
    shape: Shape = ButtonDefaults.shape,
    colors: ButtonColors = ButtonDefaults.outlinedButtonColors(),
    border: BorderStroke? = ButtonDefaults.outlinedButtonBorder(enabled),
    contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
    interactionSource: MutableInteractionSource? = null,
    label: @Composable RowScope.() -> Unit
): Unit

Wear Material3 OutlinedButton that offers three slots and a specific layout for an icon, label and secondaryLabel. The icon and secondaryLabel are optional. The items are laid out with the icon, if provided, at the start of a row, with a column next containing the two label slots.

The OutlinedButton is stadium-shaped by default and its standard height is designed to take 2 lines of text of Typography.labelMedium style - either a two-line label or both a single line label and a secondary label. With localisation and/or large font sizes, the OutlinedButton height adjusts to accommodate the contents. The label and secondary label should be consistently aligned.

If a icon is provided then the labels should be "start" aligned, e.g. left aligned in ltr so that the text starts next to the icon.

OutlinedButton takes the ButtonDefaults.outlinedButtonColors color scheme by default, with a transparent background and a thin border. This is a medium-emphasis button for important, non-primary actions that need attention.

Other recommended buttons with ButtonColors for different levels of emphasis are: Button which defaults to ButtonDefaults.buttonColors, FilledTonalButton which defaults to ButtonDefaults.filledTonalButtonColors, ChildButton which defaults to ButtonDefaults.childButtonColors. Buttons can also take an image background using ButtonDefaults.imageBackgroundButtonColors.

OutlinedButton can be enabled or disabled. A disabled button will not respond to click events.

OutlinedButton scales itself appropriately when used within the scope of a TransformingLazyColumn.

Example of an OutlinedButton with an icon and secondary label:

import androidx.compose.foundation.layout.size
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.ButtonDefaults
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.OutlinedButton
import androidx.wear.compose.material3.Text

OutlinedButton(
    onClick = { /* Do something */ },
    label = { Text("Outlined Button") },
    secondaryLabel = { Text("Secondary label") },
    icon = {
        Icon(
            painter = painterResource(R.drawable.ic_favorite_rounded),
            contentDescription = "Favorite icon",
            modifier = Modifier.size(ButtonDefaults.IconSize)
        )
    },
    modifier = modifier,
)
Parameters
onClick: () -> Unit

Will be called when the user clicks the button

modifier: Modifier = Modifier

Modifier to be applied to the button

onLongClick: (() -> Unit)? = null

Called when this button is long clicked (long-pressed). When this callback is set, onLongClickLabel should be set as well.

onLongClickLabel: String? = null

Semantic / accessibility label for the onLongClick action.

secondaryLabel: (@Composable RowScope.() -> Unit)? = null

A slot for providing the button's secondary label. The contents are expected to be text which is "start" aligned if there is an icon preset and "start" or "center" aligned if not. label and secondaryLabel contents should be consistently aligned.

icon: (@Composable BoxScope.() -> Unit)? = null

A slot for providing the button's icon. The contents are expected to be a horizontally and vertically aligned icon of size ButtonDefaults.IconSize or ButtonDefaults.LargeIconSize.

enabled: Boolean = true

Controls the enabled state of the button. When false, this button will not be clickable

shape: Shape = ButtonDefaults.shape

Defines the button's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material3 Theme

colors: ButtonColors = ButtonDefaults.outlinedButtonColors()

ButtonColors that will be used to resolve the background and content color for this button in different states. See ButtonDefaults.outlinedButtonColors.

border: BorderStroke? = ButtonDefaults.outlinedButtonBorder(enabled)

Optional BorderStroke that will be used to resolve the button border in different states. See ButtonDefaults.outlinedButtonBorder.

contentPadding: PaddingValues = ButtonDefaults.ContentPadding

The spacing values to apply internally between the container and the content

interactionSource: MutableInteractionSource? = null

an optional hoisted MutableInteractionSource for observing and emitting Interactions for this button. You can use this to change the button's appearance or preview the button in different states. Note that if null is provided, interactions will still happen internally.

label: @Composable RowScope.() -> Unit

A slot for providing the button's main label. The contents are expected to be text which is "start" aligned if there is an icon preset and "start" or "center" aligned if not.

@Composable
fun OutlinedCard(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    onLongClick: (() -> Unit)? = null,
    onLongClickLabel: String? = null,
    enabled: Boolean = true,
    shape: Shape = CardDefaults.shape,
    colors: CardColors = CardDefaults.outlinedCardColors(),
    border: BorderStroke = CardDefaults.outlinedCardBorder(),
    contentPadding: PaddingValues = CardDefaults.ContentPadding,
    interactionSource: MutableInteractionSource? = null,
    content: @Composable ColumnScope.() -> Unit
): Unit

Outlined Wear Material 3 Card that offers a single slot to take any content.

Outlined Card components that take specific content such as icons, images, titles, subtitles and labels. Outlined Cards have a visual boundary around the container. This can emphasise the content of this card.

The Card is Rectangle shaped with rounded corners by default.

Cards can be enabled or disabled. A disabled card will not respond to click events.

OutlinedCard scales itself appropriately when used within the scope of a TransformingLazyColumn.

Example of an OutlinedCard:

import androidx.wear.compose.material3.Card
import androidx.wear.compose.material3.OutlinedCard
import androidx.wear.compose.material3.Text

OutlinedCard(
    onClick = { /* Do something */ },
) {
    Text("Outlined card")
}

For more information, see the Cards Wear OS Material design guide.

Parameters
onClick: () -> Unit

Will be called when the user clicks the card

modifier: Modifier = Modifier

Modifier to be applied to the card

onLongClick: (() -> Unit)? = null

Called when this card is long clicked (long-pressed). When this callback is set, onLongClickLabel should be set as well.

onLongClickLabel: String? = null

Semantic / accessibility label for the onLongClick action.

enabled: Boolean = true

Controls the enabled state of the card. When false, this card will not be clickable and there will be no ripple effect on click. Wear cards do not have any specific elevation or alpha differences when not enabled - they are simply not clickable.

shape: Shape = CardDefaults.shape

Defines the card's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material Theme

colors: CardColors = CardDefaults.outlinedCardColors()

CardColors that will be used to resolve the colors used for this card in different states. See CardDefaults.cardColors.

border: BorderStroke = CardDefaults.outlinedCardBorder()

A BorderStroke object which is used for the outline drawing.

contentPadding: PaddingValues = CardDefaults.ContentPadding

The spacing values to apply internally between the container and the content

interactionSource: MutableInteractionSource? = null

an optional hoisted MutableInteractionSource for observing and emitting Interactions for this card. You can use this to change the card's appearance or preview the card in different states. Note that if null is provided, interactions will still happen internally.

content: @Composable ColumnScope.() -> Unit

The main slot for a content of this card

OutlinedIconButton

@Composable
fun OutlinedIconButton(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    onLongClick: (() -> Unit)? = null,
    onLongClickLabel: String? = null,
    enabled: Boolean = true,
    shapes: IconButtonShapes = IconButtonDefaults.shapes(),
    colors: IconButtonColors = IconButtonDefaults.outlinedIconButtonColors(),
    border: BorderStroke? = ButtonDefaults.outlinedButtonBorder(enabled),
    interactionSource: MutableInteractionSource? = null,
    content: @Composable BoxScope.() -> Unit
): Unit

Wear Material OutlinedIconButton is a circular, icon-only button with a transparent background, contrasting icon color and border. It offers a single slot to take an icon or image.

Set the size of the OutlinedIconButton with Modifier.touchTargetAwareSize to ensure that the recommended minimum touch target size is available.

The recommended icon button sizes are IconButtonDefaults.DefaultButtonSize, IconButtonDefaults.LargeButtonSize, IconButtonDefaults.SmallButtonSize and IconButtonDefaults.ExtraSmallButtonSize.

Use IconButtonDefaults.iconSizeFor to determine the icon size for a given IconButtonDefaults size, or refer to icon sizes IconButtonDefaults.SmallIconSize, IconButtonDefaults.DefaultIconSize, IconButtonDefaults.LargeButtonSize directly.

OutlinedIconButton can be enabled or disabled. A disabled button will not respond to click events.

An OutlinedIconButton has a transparent background and a thin border by default with content taking the theme primary color.

Example of OutlinedIconButton:

import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Favorite
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.IconButton
import androidx.wear.compose.material3.OutlinedIconButton

OutlinedIconButton(onClick = { /* Do something */ }) {
    Icon(imageVector = Icons.Filled.Favorite, contentDescription = "Favorite icon")
}
Parameters
onClick: () -> Unit

Will be called when the user clicks the button.

modifier: Modifier = Modifier

Modifier to be applied to the button.

onLongClick: (() -> Unit)? = null

Called when this button is long clicked (long-pressed). When this callback is set, onLongClickLabel should be set as well.

onLongClickLabel: String? = null

Semantic / accessibility label for the onLongClick action.

enabled: Boolean = true

Controls the enabled state of the button. When false, this button will not be clickable.

shapes: IconButtonShapes = IconButtonDefaults.shapes()

Defines the shape for this button. Defaults to a static shape based on IconButtonDefaults.shape, but animated versions are available through IconButtonDefaults.animatedShapes.

colors: IconButtonColors = IconButtonDefaults.outlinedIconButtonColors()

IconButtonColors that will be used to resolve the background and icon color for this button in different states. See IconButtonDefaults.outlinedIconButtonColors.

border: BorderStroke? = ButtonDefaults.outlinedButtonBorder(enabled)

Optional BorderStroke for the icon button border - ButtonDefaults.outlinedButtonBorder by default.

interactionSource: MutableInteractionSource? = null

an optional hoisted MutableInteractionSource for observing and emitting Interactions for this button. You can use this to change the button's appearance or preview the button in different states. Note that if null is provided, interactions will still happen internally.

content: @Composable BoxScope.() -> Unit

The content displayed on the icon button, expected to be icon or image.

@Composable
fun Picker(
    state: PickerState,
    contentDescription: String?,
    modifier: Modifier = Modifier,
    readOnly: Boolean = false,
    readOnlyLabel: (@Composable BoxScope.() -> Unit)? = null,
    onSelected: () -> Unit = {},
    spacing: Dp = 0.dp,
    gradientRatio: @FloatRange(from = 0.0, to = 0.5) Float = PickerDefaults.GradientRatio,
    gradientColor: Color = MaterialTheme.colorScheme.background,
    userScrollEnabled: Boolean = true,
    rotaryScrollableBehavior: RotaryScrollableBehavior? = PickerDefaults.rotarySnapBehavior(state),
    option: @Composable PickerScope.(index: Int) -> Unit
): Unit

A scrollable list of items to pick from. By default, items will be repeated "infinitely" in both directions, unless PickerState#repeatItems is specified as false.

Picker supports rotary input by default. Rotary input allows users to scroll the content of the Picker - by using a crown or a rotating bezel on their Wear OS device. It can be modified or turned off using the rotaryScrollableBehavior parameter.

Example of a simple picker to select one of five options:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.wear.compose.material3.Picker
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.rememberPickerState

val items = listOf("One", "Two", "Three", "Four", "Five")
val state = rememberPickerState(items.size)
val contentDescription by remember { derivedStateOf { "${state.selectedOptionIndex + 1}" } }
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
    Text(
        modifier = Modifier.align(Alignment.TopCenter).padding(top = 10.dp),
        text = "Selected: ${items[state.selectedOptionIndex]}"
    )
    Picker(
        modifier = Modifier.size(100.dp, 100.dp),
        state = state,
        contentDescription = contentDescription,
    ) {
        Text(items[it])
    }
}

Example of a sample picker group with an hour and minute picker (24 hour format):

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.wear.compose.material3.PickerGroup
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.rememberPickerState

var selectedPickerIndex by remember { mutableIntStateOf(0) }
val pickerStateHour = rememberPickerState(initialNumberOfOptions = 24)
val pickerStateMinute = rememberPickerState(initialNumberOfOptions = 60)
Column(
    modifier = Modifier.fillMaxWidth(),
    verticalArrangement = Arrangement.Center,
    horizontalAlignment = Alignment.CenterHorizontally
) {
    Spacer(modifier = Modifier.size(30.dp))
    Text(text = if (selectedPickerIndex == 0) "Hours" else "Minutes")
    Spacer(modifier = Modifier.size(10.dp))
    PickerGroup(
        selectedPickerIndex = selectedPickerIndex,
        onPickerSelected = { selectedPickerIndex = it },
        autoCenter = false
    ) {
        pickerGroupItem(
            pickerState = pickerStateHour,
            option = { optionIndex, _ -> Text(text = "%02d".format(optionIndex)) },
            modifier = Modifier.size(80.dp, 100.dp)
        )
        pickerGroupItem(
            pickerState = pickerStateMinute,
            option = { optionIndex, _ -> Text(text = "%02d".format(optionIndex)) },
            modifier = Modifier.size(80.dp, 100.dp)
        )
    }
}
Parameters
state: PickerState

The state of the component

contentDescription: String?

Text used by accessibility services to describe what the selected option represents. This text should be localized, such as by using androidx.compose.ui.res.stringResource or similar. Typically, the content description is inferred via derivedStateOf to avoid unnecessary recompositions, like this: val description by remember { derivedStateOf { /* expression using state.selectedOption */ } }

modifier: Modifier = Modifier

Modifier to be applied to the Picker.

readOnly: Boolean = false

Determines whether the Picker should display other available options for this field, inviting the user to scroll to change the value. When readOnly = true, only displays the currently selected option (and optionally a label). This is intended to be used for screens that display multiple Pickers, only one of which has the focus at a time.

readOnlyLabel: (@Composable BoxScope.() -> Unit)? = null

A slot for providing a label, displayed above the selected option when the Picker is read-only. The label is overlaid with the currently selected option within a Box, so it is recommended that the label is given Alignment.TopCenter.

onSelected: () -> Unit = {}

Action triggered when the Picker is selected by clicking. Used by accessibility semantics, which facilitates implementation of multi-picker screens.

spacing: Dp = 0.dp

The amount of spacing in Dp between items. Can be negative, which can be useful for Text if it has plenty of whitespace.

gradientRatio: @FloatRange(from = 0.0, to = 0.5) Float = PickerDefaults.GradientRatio

The size relative to the Picker height that the top and bottom gradients take. These gradients blur the picker content on the top and bottom. The default is 0.33, so the top 1/3 and the bottom 1/3 of the picker are taken by gradients. Should be between 0.0 and 0.5. Use 0.0 to disable the gradient.

gradientColor: Color = MaterialTheme.colorScheme.background

Should be the color outside of the Picker, so there is continuity.

userScrollEnabled: Boolean = true

Determines whether the picker should be scrollable or not. When userScrollEnabled = true, picker is scrollable. This is different from readOnly as it changes the scrolling behaviour.

rotaryScrollableBehavior: RotaryScrollableBehavior? = PickerDefaults.rotarySnapBehavior(state)

Parameter for changing rotary behavior. We recommend to use PickerDefaults.rotarySnapBehavior for Pickers, but passing null turns off the rotary handling if it is not required.

option: @Composable PickerScope.(index: Int) -> Unit

A block which describes the content. Inside this block you can reference PickerScope.selectedOptionIndex to determine which option is selected. When read-only mode is in use on a screen, it is recommended that this content is given Alignment.Center in order to align with the centrally selected Picker value.

@Composable
fun PickerGroup(
    selectedPickerIndex: Int,
    onPickerSelected: (selectedIndex: Int) -> Unit,
    modifier: Modifier = Modifier,
    autoCenter: Boolean = true,
    separator: (@Composable (Int) -> Unit)? = null,
    propagateMinConstraints: Boolean = false,
    content: PickerGroupScope.() -> Unit
): Unit

A group of Pickers to build components where multiple pickers are required to be combined together. At most one Picker can be selected at a time. When touch exploration services are enabled, the focus moves to the picker which is clicked. To handle clicks in a different manner, use the onPickerSelected lambda to control the focus of talkback and actual focus.

It is recommended to ensure that a Picker in non read only mode should have user scroll enabled when touch exploration services are running.

Example of a sample picker group with an hour and minute picker (24 hour format):

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.wear.compose.material3.PickerGroup
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.rememberPickerState

var selectedPickerIndex by remember { mutableIntStateOf(0) }
val pickerStateHour = rememberPickerState(initialNumberOfOptions = 24)
val pickerStateMinute = rememberPickerState(initialNumberOfOptions = 60)
Column(
    modifier = Modifier.fillMaxWidth(),
    verticalArrangement = Arrangement.Center,
    horizontalAlignment = Alignment.CenterHorizontally
) {
    Spacer(modifier = Modifier.size(30.dp))
    Text(text = if (selectedPickerIndex == 0) "Hours" else "Minutes")
    Spacer(modifier = Modifier.size(10.dp))
    PickerGroup(
        selectedPickerIndex = selectedPickerIndex,
        onPickerSelected = { selectedPickerIndex = it },
        autoCenter = false
    ) {
        pickerGroupItem(
            pickerState = pickerStateHour,
            option = { optionIndex, _ -> Text(text = "%02d".format(optionIndex)) },
            modifier = Modifier.size(80.dp, 100.dp)
        )
        pickerGroupItem(
            pickerState = pickerStateMinute,
            option = { optionIndex, _ -> Text(text = "%02d".format(optionIndex)) },
            modifier = Modifier.size(80.dp, 100.dp)
        )
    }
}

Example of an auto centering picker group where the total width exceeds screen's width:

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.wear.compose.material3.PickerGroup
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.rememberPickerState

var selectedPickerIndex by remember { mutableIntStateOf(0) }
val pickerStateHour = rememberPickerState(initialNumberOfOptions = 24)
val pickerStateMinute = rememberPickerState(initialNumberOfOptions = 60)
val pickerStateSeconds = rememberPickerState(initialNumberOfOptions = 60)
val pickerStateMilliSeconds = rememberPickerState(initialNumberOfOptions = 1000)
Column(
    modifier = Modifier.fillMaxWidth(),
    verticalArrangement = Arrangement.Center,
    horizontalAlignment = Alignment.CenterHorizontally
) {
    val headingText = mapOf(0 to "Hours", 1 to "Minutes", 2 to "Seconds", 3 to "Milli")
    Spacer(modifier = Modifier.size(30.dp))
    Text(text = headingText[selectedPickerIndex]!!)
    Spacer(modifier = Modifier.size(10.dp))
    PickerGroup(
        selectedPickerIndex = selectedPickerIndex,
        onPickerSelected = { selectedPickerIndex = it },
        autoCenter = true
    ) {
        pickerGroupItem(
            pickerState = pickerStateHour,
            option = { optionIndex, _ -> Text(text = "%02d".format(optionIndex)) },
            modifier = Modifier.size(80.dp, 100.dp)
        )
        pickerGroupItem(
            pickerState = pickerStateMinute,
            option = { optionIndex, _ -> Text(text = "%02d".format(optionIndex)) },
            modifier = Modifier.size(80.dp, 100.dp)
        )
        pickerGroupItem(
            pickerState = pickerStateSeconds,
            option = { optionIndex, _ -> Text(text = "%02d".format(optionIndex)) },
            modifier = Modifier.size(80.dp, 100.dp)
        )
        pickerGroupItem(
            pickerState = pickerStateMilliSeconds,
            option = { optionIndex, _ -> Text(text = "%03d".format(optionIndex)) },
            modifier = Modifier.size(80.dp, 100.dp)
        )
    }
}
Parameters
selectedPickerIndex: Int

The index of the Picker that is selected. The value is ignored when negative, which means that no Picker is selected.

onPickerSelected: (selectedIndex: Int) -> Unit

Action triggered when one of the Pickers is selected inside the group. Typically, selectedPickerIndex and onPickerSelected are used in tandem to apply a visual highlight to the currently selected Picker as a guide to the user.

modifier: Modifier = Modifier

Modifier to be applied to the PickerGroup.

autoCenter: Boolean = true

Indicates whether the selected Picker should be centered on the screen. It is recommended to set this as true when all the pickers cannot be fit into the screen. Or provide a mechanism to navigate to pickers which are not visible on screen. If false, the whole row containing pickers would be centered.

separator: (@Composable (Int) -> Unit)? = null

A composable block which describes the separator between different Pickers. The integer parameter to the composable depicts the index where it will be kept. For example, 0 would represent the separator between the first and second picker.

propagateMinConstraints: Boolean = false

Whether the incoming min constraints should be passed to content.

content: PickerGroupScope.() -> Unit

The content of the PickerGroup as a container of Pickers.

@Composable
fun ProvideTextStyle(value: TextStyle, content: @Composable () -> Unit): Unit

This function is used to set the current value of LocalTextStyle, merging the given style with the current style values for any missing attributes. Any Text components included in this component's content will be styled with this style unless styled explicitly.

See also
LocalTextStyle
@Composable
fun RadioButton(
    selected: Boolean,
    onSelect: () -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    shape: Shape = RadioButtonDefaults.radioButtonShape,
    colors: RadioButtonColors = RadioButtonDefaults.radioButtonColors(),
    contentPadding: PaddingValues = RadioButtonDefaults.ContentPadding,
    interactionSource: MutableInteractionSource? = null,
    icon: (@Composable BoxScope.() -> Unit)? = null,
    secondaryLabel: (@Composable RowScope.() -> Unit)? = null,
    label: @Composable RowScope.() -> Unit
): Unit

The Wear Material RadioButton offers slots and a specific layout for an icon, a label and a secondaryLabel. The icon and secondaryLabel are optional. The items are laid out in a row with the optional icon at the start, a column containing the two label slots in the middle and the selection control at the end.

The RadioButton is Stadium shaped. The label should take no more than 3 lines of text. The secondary label should take no more than 2 lines of text. With localisation and/or large font sizes, the RadioButton height adjusts to accommodate the contents. The label and secondary label are start aligned by default.

Note that Modifier.selectableGroup() must be present on the parent control (such as Column) to ensure correct accessibility behavior.

Samples: Example of a RadioButton:

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.selection.selectableGroup
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.RadioButton
import androidx.wear.compose.material3.Text

Column(modifier = Modifier.selectableGroup()) {
    var selectedButton by remember { mutableStateOf(0) }
    // RadioButton uses the Radio selection control by default.
    RadioButton(
        label = { Text("Radio button", maxLines = 3, overflow = TextOverflow.Ellipsis) },
        secondaryLabel = {
            Text("With secondary label", maxLines = 2, overflow = TextOverflow.Ellipsis)
        },
        selected = selectedButton == 0,
        onSelect = { selectedButton = 0 },
        icon = { Icon(Icons.Filled.Favorite, contentDescription = "Favorite icon") },
        enabled = true,
    )
    Spacer(modifier = Modifier.height(4.dp))
    RadioButton(
        label = { Text("Radio button", maxLines = 3, overflow = TextOverflow.Ellipsis) },
        secondaryLabel = {
            Text("With secondary label", maxLines = 3, overflow = TextOverflow.Ellipsis)
        },
        selected = selectedButton == 1,
        onSelect = { selectedButton = 1 },
        icon = { Icon(Icons.Filled.Favorite, contentDescription = "Favorite icon") },
        enabled = true,
    )
}

RadioButton can be enabled or disabled. A disabled button will not respond to click events.

The recommended set of RadioButton colors can be obtained from RadioButtonDefaults, e.g. RadioButtonDefaults.radioButtonColors.

Parameters
selected: Boolean

Boolean flag indicating whether this button is currently selected.

onSelect: () -> Unit

Callback to be invoked when this button has been selected by clicking.

modifier: Modifier = Modifier

Modifier to be applied to the RadioButton.

enabled: Boolean = true

Controls the enabled state of the button. When false, this button will not be clickable.

shape: Shape = RadioButtonDefaults.radioButtonShape

Defines the button's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material Theme.

colors: RadioButtonColors = RadioButtonDefaults.radioButtonColors()

RadioButtonColors that will be used to resolve the background and content color for this button in different states.

contentPadding: PaddingValues = RadioButtonDefaults.ContentPadding

The spacing values to apply internally between the container and the content.

interactionSource: MutableInteractionSource? = null

an optional hoisted MutableInteractionSource for observing and emitting Interactions for this radio button. You can use this to change the radio button's appearance or preview the radio button in different states. Note that if null is provided, interactions will still happen internally.

icon: (@Composable BoxScope.() -> Unit)? = null

An optional slot for providing an icon to indicate the purpose of the button. The contents are expected to be center-aligned, both horizontally and vertically, and should be an icon of size 24.dp.

secondaryLabel: (@Composable RowScope.() -> Unit)? = null

A slot for providing the button's secondary label. The contents are expected to be text which is "start" aligned.

label: @Composable RowScope.() -> Unit

A slot for providing the button's main label. The contents are expected to be text which is "start" aligned.

@Composable
fun ScreenScaffold(
    modifier: Modifier = Modifier,
    timeText: (@Composable () -> Unit)? = null,
    scrollInfoProvider: ScrollInfoProvider? = null,
    scrollIndicator: (@Composable BoxScope.() -> Unit)? = null,
    content: @Composable BoxScope.() -> Unit
): Unit

ScreenScaffold is one of the Wear Material3 scaffold components.

The scaffold components AppScaffold and ScreenScaffold lay out the structure of a screen and coordinate transitions of the ScrollIndicator and TimeText components. AppScaffold should be at the top of the composition (because it provides ScaffoldState and layers TimeText on top of all other content) and ScreenScaffold should be part of AppScaffold's content. When used in conjunction with SwipeDismissableNavHost, AppScaffold remains at the top of the composition, whilst ScreenScaffold will be placed for each individual composable route.

ScreenScaffold displays the ScrollIndicator at the center-end of the screen by default and coordinates showing/hiding TimeText and ScrollIndicator according to scrollInfoProvider.

Example of using AppScaffold and ScreenScaffold:

import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.Modifier
import androidx.wear.compose.foundation.lazy.ScalingLazyColumn
import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState
import androidx.wear.compose.material3.AppScaffold
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.ScreenScaffold
import androidx.wear.compose.material3.Text

// Declare just one [AppScaffold] per app such as in the activity.
// [AppScaffold] allows static screen elements (i.e. [TimeText]) to remain visible
// during in-app transitions such as swipe-to-dismiss.
AppScaffold {
    // Define the navigation hierarchy within the AppScaffold,
    // such as using SwipeDismissableNavHost.
    // For this sample, we will define a single screen inline.
    val listState = rememberScalingLazyListState()

    // By default, ScreenScaffold will handle transitions showing/hiding ScrollIndicator
    // and showing/hiding/scrolling away TimeText.
    ScreenScaffold(scrollState = listState) {
        ScalingLazyColumn(state = listState, modifier = Modifier.fillMaxSize()) {
            items(10) {
                Button(
                    onClick = {},
                    label = { Text("Item ${it + 1}") },
                )
            }
        }
    }
}
Parameters
modifier: Modifier = Modifier

The modifier for the screen scaffold.

timeText: (@Composable () -> Unit)? = null

Time text (both time and potentially status message) for this screen, if different to the time text at the AppScaffold level. When null, the time text from the AppScaffold is displayed for this screen.

scrollInfoProvider: ScrollInfoProvider? = null

Provider for scroll information used to scroll away screen elements such as TimeText and coordinate showing/hiding the ScrollIndicator.

scrollIndicator: (@Composable BoxScope.() -> Unit)? = null

The ScrollIndicator to display on this screen, which is expected to be aligned to Center-End. It is recommended to use the Material3 ScrollIndicator which is provided by default. No scroll indicator is displayed if null is passed.

content: @Composable BoxScope.() -> Unit

The body content for this screen.

@Composable
fun ScreenScaffold(
    scrollState: ScrollState,
    modifier: Modifier = Modifier,
    timeText: (@Composable () -> Unit)? = null,
    scrollIndicator: (@Composable BoxScope.() -> Unit)? = { ScrollIndicator(scrollState, modifier = Modifier.align(Alignment.CenterEnd)) },
    content: @Composable BoxScope.() -> Unit
): Unit

ScreenScaffold is one of the Wear Material3 scaffold components.

The scaffold components AppScaffold and ScreenScaffold lay out the structure of a screen and coordinate transitions of the ScrollIndicator and TimeText components. AppScaffold should be at the top of the composition (because it provides ScaffoldState and layers TimeText on top of all other content) and ScreenScaffold should be part of AppScaffold's content. When used in conjunction with SwipeDismissableNavHost, AppScaffold remains at the top of the composition, whilst ScreenScaffold will be placed for each individual composable route.

ScreenScaffold displays the ScrollIndicator at the center-end of the screen by default and coordinates showing/hiding TimeText and ScrollIndicator according to scrollState. Note that this version doesn't support a bottom button slot, for that use the overload that takes LazyListState or the one that takes a ScalingLazyListState.

Example of using AppScaffold and ScreenScaffold:

import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.Modifier
import androidx.wear.compose.foundation.lazy.ScalingLazyColumn
import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState
import androidx.wear.compose.material3.AppScaffold
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.ScreenScaffold
import androidx.wear.compose.material3.Text

// Declare just one [AppScaffold] per app such as in the activity.
// [AppScaffold] allows static screen elements (i.e. [TimeText]) to remain visible
// during in-app transitions such as swipe-to-dismiss.
AppScaffold {
    // Define the navigation hierarchy within the AppScaffold,
    // such as using SwipeDismissableNavHost.
    // For this sample, we will define a single screen inline.
    val listState = rememberScalingLazyListState()

    // By default, ScreenScaffold will handle transitions showing/hiding ScrollIndicator
    // and showing/hiding/scrolling away TimeText.
    ScreenScaffold(scrollState = listState) {
        ScalingLazyColumn(state = listState, modifier = Modifier.fillMaxSize()) {
            items(10) {
                Button(
                    onClick = {},
                    label = { Text("Item ${it + 1}") },
                )
            }
        }
    }
}
Parameters
scrollState: ScrollState

The scroll state for a Column, used to drive screen transitions such as TimeText scroll away and showing/hiding ScrollIndicator.

modifier: Modifier = Modifier

The modifier for the screen scaffold.

timeText: (@Composable () -> Unit)? = null

Time text (both time and potentially status message) for this screen, if different to the time text at the AppScaffold level. When null, the time text from the AppScaffold is displayed for this screen.

scrollIndicator: (@Composable BoxScope.() -> Unit)? = { ScrollIndicator(scrollState, modifier = Modifier.align(Alignment.CenterEnd)) }

The ScrollIndicator to display on this screen, which is expected to be aligned to Center-End. It is recommended to use the Material3 ScrollIndicator which is provided by default. No scroll indicator is displayed if null is passed.

content: @Composable BoxScope.() -> Unit

The body content for this screen.

@Composable
fun ScreenScaffold(
    edgeButton: @Composable BoxScope.() -> Unit,
    scrollInfoProvider: ScrollInfoProvider,
    modifier: Modifier = Modifier,
    timeText: (@Composable () -> Unit)? = null,
    scrollIndicator: (@Composable BoxScope.() -> Unit)? = null,
    content: @Composable BoxScope.() -> Unit
): Unit

ScreenScaffold is one of the Wear Material3 scaffold components.

The scaffold components AppScaffold and ScreenScaffold lay out the structure of a screen and coordinate transitions of the ScrollIndicator and TimeText components. AppScaffold should be at the top of the composition (because it provides ScaffoldState and layers TimeText on top of all other content) and ScreenScaffold should be part of AppScaffold's content. When used in conjunction with SwipeDismissableNavHost, AppScaffold remains at the top of the composition, whilst ScreenScaffold will be placed for each individual composable route.

ScreenScaffold displays the ScrollIndicator at the center-end of the screen by default and coordinates showing/hiding TimeText, ScrollIndicator and the bottom button according to a scrollInfoProvider.

This version of ScreenScaffold has a special slot for a button at the bottom, that grows and shrinks to take the available space after the scrollable content. In this overload, both edgeButton and scrollInfoProvider must be specified.

Example of using AppScaffold and ScreenScaffold:

import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.Modifier
import androidx.wear.compose.foundation.lazy.ScalingLazyColumn
import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState
import androidx.wear.compose.material3.AppScaffold
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.ScreenScaffold
import androidx.wear.compose.material3.Text

// Declare just one [AppScaffold] per app such as in the activity.
// [AppScaffold] allows static screen elements (i.e. [TimeText]) to remain visible
// during in-app transitions such as swipe-to-dismiss.
AppScaffold {
    // Define the navigation hierarchy within the AppScaffold,
    // such as using SwipeDismissableNavHost.
    // For this sample, we will define a single screen inline.
    val listState = rememberScalingLazyListState()

    // By default, ScreenScaffold will handle transitions showing/hiding ScrollIndicator
    // and showing/hiding/scrolling away TimeText.
    ScreenScaffold(scrollState = listState) {
        ScalingLazyColumn(state = listState, modifier = Modifier.fillMaxSize()) {
            items(10) {
                Button(
                    onClick = {},
                    label = { Text("Item ${it + 1}") },
                )
            }
        }
    }
}
Parameters
edgeButton: @Composable BoxScope.() -> Unit

slot for a EdgeButton that takes the available space below a scrolling list. It will scale up and fade in when the user scrolls to the end of the list, and scale down and fade out as the user scrolls up.

scrollInfoProvider: ScrollInfoProvider

Provider for scroll information used to scroll away screen elements such as TimeText and coordinate showing/hiding the ScrollIndicator, this needs to be a ScrollInfoProvider.

modifier: Modifier = Modifier

The modifier for the screen scaffold.

timeText: (@Composable () -> Unit)? = null

Time text (both time and potentially status message) for this screen, if different to the time text at the AppScaffold level. When null, the time text from the AppScaffold is displayed for this screen.

scrollIndicator: (@Composable BoxScope.() -> Unit)? = null

The ScrollIndicator to display on this screen, which is expected to be aligned to Center-End. It is recommended to use the Material3 ScrollIndicator which is provided by default. No scroll indicator is displayed if null is passed.

content: @Composable BoxScope.() -> Unit

The body content for this screen.

@Composable
fun ScreenScaffold(
    scrollState: LazyListState,
    modifier: Modifier = Modifier,
    timeText: (@Composable () -> Unit)? = null,
    scrollIndicator: (@Composable BoxScope.() -> Unit)? = { ScrollIndicator(scrollState, modifier = Modifier.align(Alignment.CenterEnd)) },
    edgeButton: (@Composable BoxScope.() -> Unit)? = null,
    content: @Composable BoxScope.() -> Unit
): Unit

ScreenScaffold is one of the Wear Material3 scaffold components.

The scaffold components AppScaffold and ScreenScaffold lay out the structure of a screen and coordinate transitions of the ScrollIndicator and TimeText components. AppScaffold should be at the top of the composition (because it provides ScaffoldState and layers TimeText on top of all other content) and ScreenScaffold should be part of AppScaffold's content. When used in conjunction with SwipeDismissableNavHost, AppScaffold remains at the top of the composition, whilst ScreenScaffold will be placed for each individual composable route.

ScreenScaffold displays the ScrollIndicator at the center-end of the screen by default and coordinates showing/hiding TimeText and ScrollIndicator according to scrollState.

This version of ScreenScaffold has a special slot for a button at the bottom, that grows and shrinks to take the available space after the scrollable content.

Example of using AppScaffold and ScreenScaffold:

import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.Modifier
import androidx.wear.compose.foundation.lazy.ScalingLazyColumn
import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState
import androidx.wear.compose.material3.AppScaffold
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.ScreenScaffold
import androidx.wear.compose.material3.Text

// Declare just one [AppScaffold] per app such as in the activity.
// [AppScaffold] allows static screen elements (i.e. [TimeText]) to remain visible
// during in-app transitions such as swipe-to-dismiss.
AppScaffold {
    // Define the navigation hierarchy within the AppScaffold,
    // such as using SwipeDismissableNavHost.
    // For this sample, we will define a single screen inline.
    val listState = rememberScalingLazyListState()

    // By default, ScreenScaffold will handle transitions showing/hiding ScrollIndicator
    // and showing/hiding/scrolling away TimeText.
    ScreenScaffold(scrollState = listState) {
        ScalingLazyColumn(state = listState, modifier = Modifier.fillMaxSize()) {
            items(10) {
                Button(
                    onClick = {},
                    label = { Text("Item ${it + 1}") },
                )
            }
        }
    }
}
Parameters
scrollState: LazyListState

The scroll state for androidx.compose.foundation.lazy.LazyColumn, used to drive screen transitions such as TimeText scroll away and showing/hiding ScrollIndicator.

modifier: Modifier = Modifier

The modifier for the screen scaffold.

timeText: (@Composable () -> Unit)? = null

Time text (both time and potentially status message) for this screen, if different to the time text at the AppScaffold level. When null, the time text from the AppScaffold is displayed for this screen.

scrollIndicator: (@Composable BoxScope.() -> Unit)? = { ScrollIndicator(scrollState, modifier = Modifier.align(Alignment.CenterEnd)) }

The ScrollIndicator to display on this screen, which is expected to be aligned to Center-End. It is recommended to use the Material3 ScrollIndicator which is provided by default. No scroll indicator is displayed if null is passed.

edgeButton: (@Composable BoxScope.() -> Unit)? = null

Optional slot for a EdgeButton that takes the available space below a scrolling list. It will scale up and fade in when the user scrolls to the end of the list, and scale down and fade out as the user scrolls up.

content: @Composable BoxScope.() -> Unit

The body content for this screen.

@Composable
fun ScreenScaffold(
    scrollState: ScalingLazyListState,
    modifier: Modifier = Modifier,
    timeText: (@Composable () -> Unit)? = null,
    scrollIndicator: (@Composable BoxScope.() -> Unit)? = { ScrollIndicator(scrollState, modifier = Modifier.align(Alignment.CenterEnd)) },
    edgeButton: (@Composable BoxScope.() -> Unit)? = null,
    content: @Composable BoxScope.() -> Unit
): Unit

ScreenScaffold is one of the Wear Material3 scaffold components.

The scaffold components AppScaffold and ScreenScaffold lay out the structure of a screen and coordinate transitions of the ScrollIndicator and TimeText components. AppScaffold should be at the top of the composition (because it provides ScaffoldState and layers TimeText on top of all other content) and ScreenScaffold should be part of AppScaffold's content. When used in conjunction with SwipeDismissableNavHost, AppScaffold remains at the top of the composition, whilst ScreenScaffold will be placed for each individual composable route.

ScreenScaffold displays the ScrollIndicator at the center-end of the screen by default and coordinates showing/hiding TimeText and ScrollIndicator according to scrollState.

This version of ScreenScaffold has a special slot for a button at the bottom, that grows and shrinks to take the available space after the scrollable content.

Example of using AppScaffold and ScreenScaffold:

import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.Modifier
import androidx.wear.compose.foundation.lazy.ScalingLazyColumn
import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState
import androidx.wear.compose.material3.AppScaffold
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.ScreenScaffold
import androidx.wear.compose.material3.Text

// Declare just one [AppScaffold] per app such as in the activity.
// [AppScaffold] allows static screen elements (i.e. [TimeText]) to remain visible
// during in-app transitions such as swipe-to-dismiss.
AppScaffold {
    // Define the navigation hierarchy within the AppScaffold,
    // such as using SwipeDismissableNavHost.
    // For this sample, we will define a single screen inline.
    val listState = rememberScalingLazyListState()

    // By default, ScreenScaffold will handle transitions showing/hiding ScrollIndicator
    // and showing/hiding/scrolling away TimeText.
    ScreenScaffold(scrollState = listState) {
        ScalingLazyColumn(state = listState, modifier = Modifier.fillMaxSize()) {
            items(10) {
                Button(
                    onClick = {},
                    label = { Text("Item ${it + 1}") },
                )
            }
        }
    }
}
Parameters
scrollState: ScalingLazyListState

The scroll state for ScalingLazyColumn, used to drive screen transitions such as TimeText scroll away and showing/hiding ScrollIndicator.

modifier: Modifier = Modifier

The modifier for the screen scaffold.

timeText: (@Composable () -> Unit)? = null

Time text (both time and potentially status message) for this screen, if different to the time text at the AppScaffold level. When null, the time text from the AppScaffold is displayed for this screen.

scrollIndicator: (@Composable BoxScope.() -> Unit)? = { ScrollIndicator(scrollState, modifier = Modifier.align(Alignment.CenterEnd)) }

The ScrollIndicator to display on this screen, which is expected to be aligned to Center-End. It is recommended to use the Material3 ScrollIndicator which is provided by default. No scroll indicator is displayed if null is passed.

edgeButton: (@Composable BoxScope.() -> Unit)? = null

Optional slot for a EdgeButton that takes the available space below a scrolling list. It will scale up and fade in when the user scrolls to the end of the list, and scale down and fade out as the user scrolls up.

content: @Composable BoxScope.() -> Unit

The body content for this screen.

@Composable
fun ScreenScaffold(
    scrollState: TransformingLazyColumnState,
    modifier: Modifier = Modifier,
    timeText: (@Composable () -> Unit)? = null,
    scrollIndicator: (@Composable BoxScope.() -> Unit)? = { ScrollIndicator(scrollState, modifier = Modifier.align(Alignment.CenterEnd)) },
    edgeButton: (@Composable BoxScope.() -> Unit)? = null,
    content: @Composable BoxScope.() -> Unit
): Unit

ScreenScaffold is one of the Wear Material3 scaffold components.

The scaffold components AppScaffold and ScreenScaffold lay out the structure of a screen and coordinate transitions of the ScrollIndicator and TimeText components. AppScaffold should be at the top of the composition (because it provides ScaffoldState and layers TimeText on top of all other content) and ScreenScaffold should be part of AppScaffold's content. When used in conjunction with SwipeDismissableNavHost, AppScaffold remains at the top of the composition, whilst ScreenScaffold will be placed for each individual composable route.

ScreenScaffold displays the ScrollIndicator at the center-end of the screen by default and coordinates showing/hiding TimeText and ScrollIndicator according to scrollState.

This version of ScreenScaffold has a special slot for a button at the bottom, that grows and shrinks to take the available space after the scrollable content.

Example of using AppScaffold and ScreenScaffold:

import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.Modifier
import androidx.wear.compose.foundation.lazy.ScalingLazyColumn
import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState
import androidx.wear.compose.material3.AppScaffold
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.ScreenScaffold
import androidx.wear.compose.material3.Text

// Declare just one [AppScaffold] per app such as in the activity.
// [AppScaffold] allows static screen elements (i.e. [TimeText]) to remain visible
// during in-app transitions such as swipe-to-dismiss.
AppScaffold {
    // Define the navigation hierarchy within the AppScaffold,
    // such as using SwipeDismissableNavHost.
    // For this sample, we will define a single screen inline.
    val listState = rememberScalingLazyListState()

    // By default, ScreenScaffold will handle transitions showing/hiding ScrollIndicator
    // and showing/hiding/scrolling away TimeText.
    ScreenScaffold(scrollState = listState) {
        ScalingLazyColumn(state = listState, modifier = Modifier.fillMaxSize()) {
            items(10) {
                Button(
                    onClick = {},
                    label = { Text("Item ${it + 1}") },
                )
            }
        }
    }
}

Example of using ScreenScaffold with a EdgeButton:

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.selection.selectableGroup
import androidx.compose.material.icons.filled.Check
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.unit.dp
import androidx.wear.compose.foundation.lazy.ScalingLazyColumn
import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState
import androidx.wear.compose.material3.ButtonDefaults
import androidx.wear.compose.material3.EdgeButton
import androidx.wear.compose.material3.EdgeButtonSize
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.RadioButton
import androidx.wear.compose.material3.ScreenScaffold
import androidx.wear.compose.material3.ScreenScaffoldDefaults
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.samples.icons.CheckIcon

val state = rememberScalingLazyListState()
val horizontalPadding = LocalConfiguration.current.screenWidthDp.dp * 0.052f
val verticalPadding = LocalConfiguration.current.screenHeightDp.dp * 0.16f
val colors =
    listOf(
        "Filled" to ButtonDefaults.buttonColors(),
        "Filled Variant" to ButtonDefaults.filledVariantButtonColors(),
        "Filled Tonal" to ButtonDefaults.filledTonalButtonColors(),
        "Outlined" to ButtonDefaults.outlinedButtonColors(),
        "Disabled" to ButtonDefaults.buttonColors()
    )
var selectedColor by remember { mutableIntStateOf(0) }
val types = listOf("Icon only" to 0, "Text only" to 1)
var selectedType by remember { mutableIntStateOf(0) }

ScreenScaffold(
    scrollState = state,
    edgeButton = {
        EdgeButton(
            onClick = {},
            buttonSize = EdgeButtonSize.Medium,
            colors = colors[selectedColor].second,
            border =
                if (colors[selectedColor].first == "Outlined")
                    ButtonDefaults.outlinedButtonBorder(true)
                else null,
            enabled = colors[selectedColor].first != "Disabled"
        ) {
            if (selectedType == 0) {
                CheckIcon()
            } else {
                Text("Ok")
            }
        }
    }
) {
    ScalingLazyColumn(
        state = state,
        modifier = Modifier.fillMaxSize().selectableGroup(),
        autoCentering = null,
        contentPadding =
            ScreenScaffoldDefaults.contentPaddingWithEdgeButton(
                edgeButtonSize = EdgeButtonSize.Medium,
                start = horizontalPadding,
                end = horizontalPadding,
                top = verticalPadding,
            ),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        item { Text("Color") }
        items(colors.size) { ix ->
            RadioButton(
                label = { Text(colors[ix].first) },
                selected = selectedColor == ix,
                onSelect = { selectedColor = ix },
                modifier = Modifier.fillMaxWidth()
            )
        }
        item { Text("Type") }
        items(types.size) { ix ->
            RadioButton(
                label = { Text(types[ix].first) },
                selected = selectedType == ix,
                onSelect = { selectedType = ix },
                modifier = Modifier.fillMaxWidth()
            )
        }
    }
}
Parameters
scrollState: TransformingLazyColumnState

The scroll state for TransformingLazyColumn, used to drive screen transitions such as TimeText scroll away and showing/hiding ScrollIndicator.

modifier: Modifier = Modifier

The modifier for the screen scaffold.

timeText: (@Composable () -> Unit)? = null

Time text (both time and potentially status message) for this screen, if different to the time text at the AppScaffold level. When null, the time text from the AppScaffold is displayed for this screen.

scrollIndicator: (@Composable BoxScope.() -> Unit)? = { ScrollIndicator(scrollState, modifier = Modifier.align(Alignment.CenterEnd)) }

The ScrollIndicator to display on this screen, which is expected to be aligned to Center-End. It is recommended to use the Material3 ScrollIndicator which is provided by default. No scroll indicator is displayed if null is passed.

edgeButton: (@Composable BoxScope.() -> Unit)? = null

Optional slot for a EdgeButton that takes the available space below a scrolling list. It will scale up and fade in when the user scrolls to the end of the list, and scale down and fade out as the user scrolls up.

content: @Composable BoxScope.() -> Unit

The body content for this screen.

@Composable
fun ScrollIndicator(
    state: LazyListState,
    modifier: Modifier = Modifier,
    reverseDirection: Boolean = false,
    positionAnimationSpec: AnimationSpec<Float> = ScrollIndicatorDefaults.PositionAnimationSpec
): Unit

A composable that displays a visual indicator of scrolling progress within a scrollable container.

Creates an ScrollIndicator based on the values in a LazyListState object that a LazyColumn uses.

To comply with Wear Material Design guidelines, this composable should be aligned to the center end of the screen using Alignment.CenterEnd. It will appear on the right in Ltr orientation and on the left in Rtl orientation.

It detects if the screen is round or square and draws itself as a curve or line.

For more information, see the Scroll indicators guide.

Example of a sample ScrollIndicator with LazyColumn:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.material3.ScrollIndicator
import androidx.wear.compose.material3.Text

val scrollState = rememberLazyListState()
Box {
    LazyColumn(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        state = scrollState
    ) {
        items(100) { Text(text = "Item $it") }
    }
    ScrollIndicator(modifier = Modifier.align(Alignment.CenterEnd), state = scrollState)
}
Parameters
state: LazyListState

the LazyListState to use as the basis for the ScrollIndicatorState.

modifier: Modifier = Modifier

The modifier to be applied to the component

reverseDirection: Boolean = false

Reverses direction of ScrollIndicator if true

positionAnimationSpec: AnimationSpec<Float> = ScrollIndicatorDefaults.PositionAnimationSpec

AnimationSpec for position animation. The Position animation is used for animating changes to the scroll size and position. To disable this animation snap AnimationSpec should be passed instead.

@Composable
fun ScrollIndicator(
    state: ScalingLazyListState,
    modifier: Modifier = Modifier,
    reverseDirection: Boolean = false,
    positionAnimationSpec: AnimationSpec<Float> = ScrollIndicatorDefaults.PositionAnimationSpec
): Unit

A composable that displays a visual indicator of scrolling progress within a scrollable container.

Creates an ScrollIndicator based on the values in a ScalingLazyListState object that a ScalingLazyColumn uses.

Typically used with the ScreenScaffold but can be used to decorate any full screen situation.

To comply with Wear Material Design guidelines, this composable should be aligned to the center end of the screen using Alignment.CenterEnd. It will appear on the right in Ltr orientation and on the left in Rtl orientation.

It detects if the screen is round or square and draws itself as a curve or line.

For more information, see the Scroll indicators guide.

Example of a sample ScrollIndicator with LazyColumn:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.foundation.lazy.ScalingLazyColumn
import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState
import androidx.wear.compose.material3.ScrollIndicator
import androidx.wear.compose.material3.Text

val scrollState = rememberScalingLazyListState()
Box {
    ScalingLazyColumn(modifier = Modifier.fillMaxSize(), state = scrollState) {
        items(100) { Text(text = "Item $it") }
    }
    ScrollIndicator(modifier = Modifier.align(Alignment.CenterEnd), state = scrollState)
}
Parameters
state: ScalingLazyListState

the ScalingLazyListState to use as the basis for the ScrollIndicatorState.

modifier: Modifier = Modifier

The modifier to be applied to the component

reverseDirection: Boolean = false

Reverses direction of ScrollIndicator if true

positionAnimationSpec: AnimationSpec<Float> = ScrollIndicatorDefaults.PositionAnimationSpec

AnimationSpec for position animation. The Position animation is used for animating changes to the scroll size and position. To disable this animation snap AnimationSpec should be passed instead.

@Composable
fun ScrollIndicator(
    state: ScrollState,
    modifier: Modifier = Modifier,
    reverseDirection: Boolean = false,
    positionAnimationSpec: AnimationSpec<Float> = ScrollIndicatorDefaults.PositionAnimationSpec
): Unit

A composable that displays a visual indicator of scrolling progress within a scrollable container.

Creates a ScrollIndicator based on the values in a ScrollState object. e.g. a Column implementing Modifier.verticalScroll provides a ScrollState.

To comply with Wear Material Design guidelines, this composable should be aligned to the center end of the screen using Alignment.CenterEnd, such as by setting modifier = Modifier.align(Alignment.CenterEnd). This way, the ScrollIndicator will appear on the right in Ltr orientation and on the left in Rtl orientation.

It detects if the screen is round or square and draws itself as a curve or line.

For more information, see the Scroll indicators guide.

Example of a sample ScrollIndicator with Column:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.material3.ScrollIndicator
import androidx.wear.compose.material3.Text

val scrollState = rememberScrollState()
Box {
    Column(
        modifier = Modifier.fillMaxSize().verticalScroll(scrollState),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        repeat(100) { Text(text = "Item $it") }
    }
    ScrollIndicator(modifier = Modifier.align(Alignment.CenterEnd), state = scrollState)
}
Parameters
state: ScrollState

The scrollState to use as the basis for the ScrollIndicatorState.

modifier: Modifier = Modifier

The modifier to be applied to the component - usually set to Modifier.align(Alignment.CenterEnd).

reverseDirection: Boolean = false

Reverses direction of ScrollIndicator if true

positionAnimationSpec: AnimationSpec<Float> = ScrollIndicatorDefaults.PositionAnimationSpec

AnimationSpec for position animation. The Position animation is used for animating changes to the scroll size and position. To disable this animation snap AnimationSpec should be passed instead.

@Composable
fun ScrollIndicator(
    state: TransformingLazyColumnState,
    modifier: Modifier = Modifier,
    reverseDirection: Boolean = false,
    positionAnimationSpec: AnimationSpec<Float> = ScrollIndicatorDefaults.PositionAnimationSpec
): Unit

SegmentedCircularProgressIndicator

@Composable
fun SegmentedCircularProgressIndicator(
    segmentCount: @IntRange(from = 1) Int,
    segmentValue: (segmentIndex: Int) -> Boolean,
    modifier: Modifier = Modifier,
    startAngle: Float = CircularProgressIndicatorDefaults.StartAngle,
    endAngle: Float = startAngle,
    colors: ProgressIndicatorColors = ProgressIndicatorDefaults.colors(),
    strokeWidth: Dp = CircularProgressIndicatorDefaults.largeStrokeWidth,
    gapSize: Dp = CircularProgressIndicatorDefaults.calculateRecommendedGapSize(strokeWidth),
    enabled: Boolean = true
): Unit

Material Design segmented circular progress indicator.

A segmented variant of CircularProgressIndicator that is divided into equally sized segments. This overload of SegmentedCircularProgressIndicator allows for each segment to be individually indicated as completed, such as for showing activity for intervals within a longer period

Example of SegmentedCircularProgressIndicator where the segments are turned on/off:

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.ui.Modifier
import androidx.wear.compose.material3.CircularProgressIndicator
import androidx.wear.compose.material3.CircularProgressIndicatorDefaults
import androidx.wear.compose.material3.MaterialTheme
import androidx.wear.compose.material3.ProgressIndicatorDefaults
import androidx.wear.compose.material3.SegmentedCircularProgressIndicator

Box(
    modifier =
        Modifier.background(MaterialTheme.colorScheme.background)
            .padding(CircularProgressIndicatorDefaults.FullScreenPadding)
            .fillMaxSize()
) {
    SegmentedCircularProgressIndicator(
        segmentCount = 5,
        segmentValue = { it % 2 != 0 },
    )
}

Example of smaller size SegmentedCircularProgressIndicator:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.wear.compose.material3.CircularProgressIndicator
import androidx.wear.compose.material3.SegmentedCircularProgressIndicator

Box(modifier = Modifier.fillMaxSize()) {
    SegmentedCircularProgressIndicator(
        segmentCount = 8,
        segmentValue = { it % 2 != 0 },
        modifier = Modifier.align(Alignment.Center).size(80.dp)
    )
}
Parameters
segmentCount: @IntRange(from = 1) Int

Number of equal segments that the progress indicator should be divided into. Has to be a number equal or greater to 1.

segmentValue: (segmentIndex: Int) -> Boolean

A function that for each segment between 1..segmentCount returns true if this segment should be displayed with the indicator color to show progress, and false if the segment should be displayed with the track color.

modifier: Modifier = Modifier

Modifier to be applied to the SegmentedCircularProgressIndicator.

startAngle: Float = CircularProgressIndicatorDefaults.StartAngle

The starting position of the progress arc, measured clockwise in degrees (0 to 360) from the 3 o'clock position. For example, 0 and 360 represent 3 o'clock, 90 and 180 represent 6 o'clock and 9 o'clock respectively. Default is 270 degrees CircularProgressIndicatorDefaults.StartAngle (top of the screen).

endAngle: Float = startAngle

The ending position of the progress arc, measured clockwise in degrees (0 to 360) from the 3 o'clock position. For example, 0 and 360 represent 3 o'clock, 90 and 180 represent 6 o'clock and 9 o'clock respectively. By default equal to startAngle.

colors: ProgressIndicatorColors = ProgressIndicatorDefaults.colors()

ProgressIndicatorColors that will be used to resolve the indicator and track color for this progress indicator in different states.

strokeWidth: Dp = CircularProgressIndicatorDefaults.largeStrokeWidth

The stroke width for the progress indicator.

gapSize: Dp = CircularProgressIndicatorDefaults.calculateRecommendedGapSize(strokeWidth)

The size of the gap between segments (in Dp).

enabled: Boolean = true

controls the enabled state. Although this component is not clickable, it can be contained within a clickable component. When enabled is false, this component will appear visually disabled.

SegmentedCircularProgressIndicator

@Composable
fun SegmentedCircularProgressIndicator(
    segmentCount: @IntRange(from = 1) Int,
    progress: () -> Float,
    modifier: Modifier = Modifier,
    allowProgressOverflow: Boolean = false,
    startAngle: Float = CircularProgressIndicatorDefaults.StartAngle,
    endAngle: Float = startAngle,
    colors: ProgressIndicatorColors = ProgressIndicatorDefaults.colors(),
    strokeWidth: Dp = CircularProgressIndicatorDefaults.largeStrokeWidth,
    gapSize: Dp = CircularProgressIndicatorDefaults.calculateRecommendedGapSize(strokeWidth),
    enabled: Boolean = true
): Unit

Material Design segmented circular progress indicator.

A segmented variant of CircularProgressIndicator that is divided into equally sized segments.

Example of SegmentedCircularProgressIndicator with progress value:

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.ui.Modifier
import androidx.wear.compose.material3.CircularProgressIndicator
import androidx.wear.compose.material3.CircularProgressIndicatorDefaults
import androidx.wear.compose.material3.MaterialTheme
import androidx.wear.compose.material3.ProgressIndicatorDefaults
import androidx.wear.compose.material3.SegmentedCircularProgressIndicator

Box(
    modifier =
        Modifier.background(MaterialTheme.colorScheme.background)
            .padding(CircularProgressIndicatorDefaults.FullScreenPadding)
            .fillMaxSize()
) {
    SegmentedCircularProgressIndicator(
        segmentCount = 5,
        progress = { 0.5f },
    )
}
Parameters
segmentCount: @IntRange(from = 1) Int

Number of equal segments that the progress indicator should be divided into. Has to be a number equal or greater to 1.

progress: () -> Float

The progress of this progress indicator where 0.0 represents no progress and 1.0 represents completion. Values smaller than 0.0 will be coerced to 0, while values larger than 1.0 will be wrapped around and shown as overflow with a different track color. The progress is applied to the entire SegmentedCircularProgressIndicator across all segments. Progress changes will be animated.

modifier: Modifier = Modifier

Modifier to be applied to the SegmentedCircularProgressIndicator.

allowProgressOverflow: Boolean = false

When progress overflow is allowed, values smaller than 0.0 will be coerced to 0, while values larger than 1.0 will be wrapped around and shown as overflow with a different track color ProgressIndicatorColors.overflowTrackBrush. For example values 1.2, 2.2 etc will be shown as 20% progress with the overflow color. When progress overflow is not allowed, progress values will be coerced into the range 0..1.

startAngle: Float = CircularProgressIndicatorDefaults.StartAngle

The starting position of the progress arc, measured clockwise in degrees (0 to 360) from the 3 o'clock position. For example, 0 and 360 represent 3 o'clock, 90 and 180 represent 6 o'clock and 9 o'clock respectively. Default is 270 degrees CircularProgressIndicatorDefaults.StartAngle (top of the screen).

endAngle: Float = startAngle

The ending position of the progress arc, measured clockwise in degrees (0 to 360) from the 3 o'clock position. For example, 0 and 360 represent 3 o'clock, 90 and 180 represent 6 o'clock and 9 o'clock respectively. By default equal to startAngle.

colors: ProgressIndicatorColors = ProgressIndicatorDefaults.colors()

ProgressIndicatorColors that will be used to resolve the indicator and track color for this progress indicator in different states.

strokeWidth: Dp = CircularProgressIndicatorDefaults.largeStrokeWidth

The stroke width for the progress indicator.

gapSize: Dp = CircularProgressIndicatorDefaults.calculateRecommendedGapSize(strokeWidth)

The size of the gap between segments (in Dp).

enabled: Boolean = true

controls the enabled state. Although this component is not clickable, it can be contained within a clickable component. When enabled is false, this component will appear visually disabled.

@Composable
fun Slider(
    value: Int,
    onValueChange: (Int) -> Unit,
    valueProgression: IntProgression,
    modifier: Modifier = Modifier,
    decreaseIcon: @Composable () -> Unit = { SliderDefaults.DecreaseIcon() },
    increaseIcon: @Composable () -> Unit = { SliderDefaults.IncreaseIcon() },
    enabled: Boolean = true,
    segmented: Boolean = valueProgression.stepsNumber() <= MaxSegmentSteps,
    shape: Shape = SliderDefaults.shape,
    colors: SliderColors = SliderDefaults.sliderColors()
): Unit

Slider allows users to make a selection from a range of values. The range of selections is shown as a bar between the minimum and maximum values of the range, from which users may select a single value. Slider is ideal for adjusting settings such as volume or brightness.

Value can be increased and decreased by clicking on the increase and decrease buttons, located accordingly to the start and end of the control. Buttons can have custom icons - decreaseIcon and increaseIcon.

The bar in the middle of control can have separators if segmented flag is set to true. A number of steps is calculated as the difference between max and min values of valueProgression divided by valueProgression.step - 1. For example, with a range of 100..120 and a step 5, number of by valueProgression.step - 1. For example, with a range of 100..120 and a step 5, number of steps will be (120-100)/ 5 - 1 = 3. Steps are 100(first), 105, 110, 115, 120(last)

If valueProgression range is not equally divisible by valueProgression.step, then valueProgression.last will be adjusted to the closest divisible value in the range. For example, 1..13 range and a step = 5, steps will be 1(first) , 6 , 11(last)

A continuous non-segmented slider sample:

import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.wear.compose.material3.Slider

var value by remember { mutableStateOf(4) }
Slider(
    value = value,
    onValueChange = { value = it },
    valueProgression = 0..10,
    segmented = false
)

A segmented slider sample:

import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.wear.compose.material3.Slider

var value by remember { mutableStateOf(2f) }
Slider(
    value = value,
    onValueChange = { value = it },
    valueRange = 1f..4f,
    steps = 7,
    segmented = true
)
Parameters
value: Int

Current value of the Slider. If outside of valueProgression provided, value will be coerced to this range.

onValueChange: (Int) -> Unit

Lambda in which value should be updated.

valueProgression: IntProgression

Progression of values that Slider value can take. Consists of rangeStart, rangeEnd and step. Range will be equally divided by step size.

modifier: Modifier = Modifier

Modifiers for the Slider layout.

decreaseIcon: @Composable () -> Unit = { SliderDefaults.DecreaseIcon() }

A slot for an icon which is placed on the decrease (start) button such as SliderDefaults.DecreaseIcon.

increaseIcon: @Composable () -> Unit = { SliderDefaults.IncreaseIcon() }

A slot for an icon which is placed on the increase (end) button such as SliderDefaults.IncreaseIcon.

enabled: Boolean = true

Controls the enabled state of the slider. When false, this slider will not be clickable.

segmented: Boolean = valueProgression.stepsNumber() <= MaxSegmentSteps

A boolean value which specifies whether a bar will be split into segments or not. Recommendation is while using this flag do not have more than MaxSegmentSteps steps as it might affect user experience. By default true if number of steps is <= MaxSegmentSteps.

shape: Shape = SliderDefaults.shape

Defines slider's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material3 Theme.

colors: SliderColors = SliderDefaults.sliderColors()

SliderColors that will be used to resolve the background and content color for this slider in different states.

@Composable
fun Slider(
    value: Float,
    onValueChange: (Float) -> Unit,
    steps: Int,
    modifier: Modifier = Modifier,
    decreaseIcon: @Composable () -> Unit = { SliderDefaults.DecreaseIcon() },
    increaseIcon: @Composable () -> Unit = { SliderDefaults.IncreaseIcon() },
    enabled: Boolean = true,
    valueRange: ClosedFloatingPointRange<Float> = 0f..(steps + 1).toFloat(),
    segmented: Boolean = steps <= MaxSegmentSteps,
    shape: Shape = SliderDefaults.shape,
    colors: SliderColors = SliderDefaults.sliderColors()
): Unit

Slider allows users to make a selection from a range of values. The range of selections is shown as a bar between the minimum and maximum values of the range, from which users may select a single value. Slider is ideal for adjusting settings such as volume or brightness.

Value can be increased and decreased by clicking on the increase and decrease buttons, located accordingly to the start and end of the control. Buttons can have custom icons - decreaseIcon and increaseIcon.

The bar in the middle of control can have separators if segmented flag is set to true. A single step value is calculated as the difference between min and max values of valueRange divided by steps + 1 value.

A continuous non-segmented slider sample:

import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.wear.compose.material3.Slider

var value by remember { mutableStateOf(4.5f) }
Slider(
    value = value,
    onValueChange = { value = it },
    valueRange = 3f..6f,
    steps = 5,
    segmented = false
)

A segmented slider sample:

import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.wear.compose.material3.Slider

var value by remember { mutableStateOf(2f) }
Slider(
    value = value,
    onValueChange = { value = it },
    valueRange = 1f..4f,
    steps = 7,
    segmented = true
)
Parameters
value: Float

Current value of the Slider. If outside of valueRange provided, value will be coerced to this range.

onValueChange: (Float) -> Unit

Lambda in which value should be updated.

steps: Int

Specifies the number of discrete values, excluding min and max values, evenly distributed across the whole value range. Must not be negative. If 0, slider will have only min and max values and no steps in between.

modifier: Modifier = Modifier

Modifiers for the Slider layout.

decreaseIcon: @Composable () -> Unit = { SliderDefaults.DecreaseIcon() }

A slot for an icon which is placed on the decrease (start) button such as SliderDefaults.DecreaseIcon.

increaseIcon: @Composable () -> Unit = { SliderDefaults.IncreaseIcon() }

A slot for an icon which is placed on the increase (end) button such as SliderDefaults.IncreaseIcon.

enabled: Boolean = true

Controls the enabled state of the slider. When false, this slider will not be clickable.

valueRange: ClosedFloatingPointRange<Float> = 0f..(steps + 1).toFloat()

Range of values that Slider value can take. Passed value will be coerced to this range.

segmented: Boolean = steps <= MaxSegmentSteps

A boolean value which specifies whether a bar will be split into segments or not. Recommendation is while using this flag do not have more than MaxSegmentSteps steps as it might affect user experience. By default true if number of steps is <= MaxSegmentSteps.

shape: Shape = SliderDefaults.shape

Defines slider's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material3 Theme.

colors: SliderColors = SliderDefaults.sliderColors()

SliderColors that will be used to resolve the background and content color for this slider in different states.

SplitCheckboxButton

@Composable
fun SplitCheckboxButton(
    checked: Boolean,
    onCheckedChange: (Boolean) -> Unit,
    toggleContentDescription: String?,
    onContainerClick: () -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    shape: Shape = CheckboxButtonDefaults.splitCheckboxButtonShape,
    colors: SplitCheckboxButtonColors = CheckboxButtonDefaults.splitCheckboxButtonColors(),
    toggleInteractionSource: MutableInteractionSource? = null,
    containerInteractionSource: MutableInteractionSource? = null,
    containerClickLabel: String? = null,
    contentPadding: PaddingValues = CheckboxButtonDefaults.ContentPadding,
    secondaryLabel: (@Composable RowScope.() -> Unit)? = null,
    label: @Composable RowScope.() -> Unit
): Unit

The Wear Material SplitCheckboxButton offers slots and a specific layout for a label and secondaryLabel. The secondaryLabel is optional. The items are laid out with a column containing the two label slots and a Checkbox at the end.

The SplitCheckboxButton is Stadium shaped. The label should take no more than 3 lines of text. The secondary label should take no more than 2 lines of text. With localisation and/or large font sizes, the SplitCheckboxButton height adjusts to accommodate the contents. The label and secondary label are start aligned by default.

A SplitCheckboxButton has two tappable areas, one tap area for the labels and another for the checkbox. The onContainerClick listener will be associated with the main body of the SplitCheckboxButton and the onCheckedChange listener associated with the checkbox area only.

Samples: Example of a SplitCheckboxButton:

import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.text.style.TextOverflow
import androidx.wear.compose.material3.CheckboxButton
import androidx.wear.compose.material3.SplitCheckboxButton
import androidx.wear.compose.material3.Text

var checked by remember { mutableStateOf(true) }
SplitCheckboxButton(
    label = { Text("Split Checkbox Button", maxLines = 3, overflow = TextOverflow.Ellipsis) },
    checked = checked,
    onCheckedChange = { checked = it },
    toggleContentDescription = "Split Checkbox Button Sample",
    onContainerClick = {
        /* Do something */
    },
    containerClickLabel = "click",
    enabled = true,
)

For a SplitCheckboxButton the background of the tappable background area behind the toggle control will have a visual effect applied to provide a "divider" between the two tappable areas.

The recommended set of colors can be obtained from CheckboxButtonDefaults, e.g. CheckboxButtonDefaults.splitCheckboxButtonColors.

SplitCheckboxButton can be enabled or disabled. A disabled button will not respond to click events.

Parameters
checked: Boolean

Boolean flag indicating whether this button is currently checked.

onCheckedChange: (Boolean) -> Unit

Callback to be invoked when this buttons checked status is changed.

toggleContentDescription: String?

The content description for the checkbox control part of the component.

onContainerClick: () -> Unit

Click listener called when the user clicks the main body of the button, the area behind the labels.

modifier: Modifier = Modifier

Modifier to be applied to the button.

enabled: Boolean = true

Controls the enabled state of the button. When false, this button will not be clickable.

shape: Shape = CheckboxButtonDefaults.splitCheckboxButtonShape

Defines the button's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material Theme.

colors: SplitCheckboxButtonColors = CheckboxButtonDefaults.splitCheckboxButtonColors()

SplitCheckboxButtonColors that will be used to resolve the background and content color for this button in different states.

toggleInteractionSource: MutableInteractionSource? = null

an optional hoisted MutableInteractionSource for observing and emitting Interactions for this button's "toggleable" tap area. You can use this to change the button's appearance or preview the button in different states. Note that if null is provided, interactions will still happen internally.

containerInteractionSource: MutableInteractionSource? = null

an optional hoisted MutableInteractionSource for observing and emitting Interactions for this button's main body "clickable" tap area. You can use this to change the button's appearance or preview the button in different states. Note that if null is provided, interactions will still happen internally.

containerClickLabel: String? = null

Optional click label on the main body of the button for accessibility.

contentPadding: PaddingValues = CheckboxButtonDefaults.ContentPadding

The spacing values to apply internally between the container and the content.

secondaryLabel: (@Composable RowScope.() -> Unit)? = null

A slot for providing the button's secondary label. The contents are expected to be "start" aligned.

label: @Composable RowScope.() -> Unit

A slot for providing the button's main label. The contents are expected to be text which is "start" aligned.

@Composable
fun SplitRadioButton(
    selected: Boolean,
    onSelectionClick: () -> Unit,
    selectionContentDescription: String?,
    onContainerClick: () -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    shape: Shape = RadioButtonDefaults.splitRadioButtonShape,
    colors: SplitRadioButtonColors = RadioButtonDefaults.splitRadioButtonColors(),
    selectionInteractionSource: MutableInteractionSource? = null,
    containerInteractionSource: MutableInteractionSource? = null,
    containerClickLabel: String? = null,
    contentPadding: PaddingValues = RadioButtonDefaults.ContentPadding,
    secondaryLabel: (@Composable RowScope.() -> Unit)? = null,
    label: @Composable RowScope.() -> Unit
): Unit

The Wear Material SplitRadioButton offers two slots and a specific layout for a label and secondaryLabel. The secondaryLabel is optional. The items are laid out with a column containing the two label slots and radio button control at the end.

The SplitRadioButton is Stadium shaped. The label should take no more than 3 lines of text. The secondary label should take no more than 2 lines of text. With localisation and/or large font sizes, the SplitRadioButton height adjusts to accommodate the contents. The label and secondary label are start aligned by default.

A SplitRadioButton has two tappable areas, one tap area for the labels and another for the selection control. The onContainerClick listener will be associated with the main body of the split radio button with the onSelectionClick listener associated with the selection control area only.

Samples: Example of a SplitRadioButton:

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.selection.selectableGroup
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.wear.compose.material3.RadioButton
import androidx.wear.compose.material3.SplitRadioButton
import androidx.wear.compose.material3.Text

Column(modifier = Modifier.selectableGroup()) {
    var selectedButton by remember { mutableStateOf(0) }
    // SplitRadioButton uses the Radio selection control by default.
    SplitRadioButton(
        label = { Text("First Button", maxLines = 3, overflow = TextOverflow.Ellipsis) },
        selected = selectedButton == 0,
        onSelectionClick = { selectedButton = 0 },
        selectionContentDescription = "First",
        onContainerClick = {
            /* Do something */
        },
        containerClickLabel = "click",
        enabled = true,
    )
    Spacer(modifier = Modifier.height(4.dp))
    SplitRadioButton(
        label = { Text("Second Button", maxLines = 3, overflow = TextOverflow.Ellipsis) },
        selected = selectedButton == 1,
        onSelectionClick = { selectedButton = 1 },
        selectionContentDescription = "Second",
        onContainerClick = {
            /* Do something */
        },
        containerClickLabel = "click",
        enabled = true,
    )
}

For a SplitRadioButton the background of the tappable background area behind the selection control will have a visual effect applied to provide a "divider" between the two tappable areas.

The recommended set of colors can be obtained from RadioButtonDefaults, e.g. RadioButtonDefaults.splitRadioButtonColors.

SplitRadioButton can be enabled or disabled. A disabled button will not respond to click events.

Parameters
selected: Boolean

Boolean flag indicating whether this button is currently selected.

onSelectionClick: () -> Unit

Callback to be invoked when this button has been selected.

selectionContentDescription: String?

The content description for the selection control part of the component

onContainerClick: () -> Unit

Click listener called when the user clicks the main body of the button, the area containing the labels.

modifier: Modifier = Modifier

Modifier to be applied to the button.

enabled: Boolean = true

Controls the enabled state of the button. When false, this button will not be clickable.

shape: Shape = RadioButtonDefaults.splitRadioButtonShape

Defines the button's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material Theme.

colors: SplitRadioButtonColors = RadioButtonDefaults.splitRadioButtonColors()

SplitRadioButtonColors that will be used to resolve the background and content color for this button in different states.

selectionInteractionSource: MutableInteractionSource? = null

an optional hoisted MutableInteractionSource for observing and emitting Interactions for this button's "selectable" tap area. You can use this to change the button's appearance or preview the button in different states. Note that if null is provided, interactions will still happen internally.

containerInteractionSource: MutableInteractionSource? = null

an optional hoisted MutableInteractionSource for observing and emitting Interactions for this button's "clickable" tap area. You can use this to change the button's appearance or preview the button in different states. Note that if null is provided, interactions will still happen internally.

containerClickLabel: String? = null

Optional click label on the main body of the button for accessibility.

contentPadding: PaddingValues = RadioButtonDefaults.ContentPadding

The spacing values to apply internally between the container and the content.

secondaryLabel: (@Composable RowScope.() -> Unit)? = null

A slot for providing the button's secondary label. The contents are expected to be "start" aligned.

label: @Composable RowScope.() -> Unit

A slot for providing the button's main label. The contents are expected to be text which is "start" aligned.

@Composable
fun SplitSwitchButton(
    checked: Boolean,
    onCheckedChange: (Boolean) -> Unit,
    toggleContentDescription: String?,
    onContainerClick: () -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    shape: Shape = SwitchButtonDefaults.splitSwitchButtonShape,
    colors: SplitSwitchButtonColors = SwitchButtonDefaults.splitSwitchButtonColors(),
    toggleInteractionSource: MutableInteractionSource? = null,
    containerInteractionSource: MutableInteractionSource? = null,
    containerClickLabel: String? = null,
    contentPadding: PaddingValues = SwitchButtonDefaults.ContentPadding,
    secondaryLabel: (@Composable RowScope.() -> Unit)? = null,
    label: @Composable RowScope.() -> Unit
): Unit

The Wear Material SplitSwitchButton offers slots and a specific layout for a label and secondary label. The secondaryLabel is optional. The items are laid out with a column containing the two label slots and a Switch at the end.

The SplitSwitchButton is Stadium shaped. The label should take no more than 3 lines of text. The secondary label should take no more than 2 lines of text. With localisation and/or large font sizes, the SplitSwitchButton height adjusts to accommodate the contents. The label and secondary label are start aligned by default.

A SplitSwitchButton has two tappable areas, one tap area for the labels and another for the switch. The onContainerClick listener will be associated with the main body of the SplitSwitchButton with the onCheckedChange listener associated with the switch area only.

Example of a SplitSwitchButton:

import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.text.style.TextOverflow
import androidx.wear.compose.material3.SplitSwitchButton
import androidx.wear.compose.material3.SwitchButton
import androidx.wear.compose.material3.Text

var checked by remember { mutableStateOf(true) }
SplitSwitchButton(
    label = { Text("Split Switch Button", maxLines = 3, overflow = TextOverflow.Ellipsis) },
    checked = checked,
    onCheckedChange = { checked = it },
    toggleContentDescription = "Split Switch Button Sample",
    onContainerClick = {
        /* Do something */
    },
    enabled = true,
)

For a SplitSwitchButton the background of the tappable background area behind the switch will have a visual effect applied to provide a "divider" between the two tappable areas.

The recommended set of colors can be obtained from SwitchButtonDefaults, e.g. SwitchButtonDefaults.splitSwitchButtonColors.

SplitSwitchButton can be enabled or disabled. A disabled button will not respond to click events.

Parameters
checked: Boolean

Boolean flag indicating whether this button is currently checked.

onCheckedChange: (Boolean) -> Unit

Callback to be invoked when this buttons checked status is changed.

toggleContentDescription: String?

The content description for the switch control part of the component.

onContainerClick: () -> Unit

Click listener called when the user clicks the main body of the button, the area behind the labels.

modifier: Modifier = Modifier

Modifier to be applied to the button.

enabled: Boolean = true

Controls the enabled state of the button. When false, this button will not be clickable.

shape: Shape = SwitchButtonDefaults.splitSwitchButtonShape

Defines the button's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material Theme.

colors: SplitSwitchButtonColors = SwitchButtonDefaults.splitSwitchButtonColors()

SplitSwitchButtonColors that will be used to resolve the background and content color for this button in different states.

toggleInteractionSource: MutableInteractionSource? = null

an optional hoisted MutableInteractionSource for observing and emitting Interactions for this button's "toggleable" tap area. You can use this to change the button's appearance or preview the button in different states. Note that if null is provided, interactions will still happen internally.

containerInteractionSource: MutableInteractionSource? = null

an optional hoisted MutableInteractionSource for observing and emitting Interactions for this button's main body "clickable" tap area. You can use this to change the button's appearance or preview the button in different states. Note that if null is provided, interactions will still happen internally.

containerClickLabel: String? = null

Optional click label on the main body of the button for accessibility.

contentPadding: PaddingValues = SwitchButtonDefaults.ContentPadding

The spacing values to apply internally between the container and the content.

secondaryLabel: (@Composable RowScope.() -> Unit)? = null

A slot for providing the button's secondary label. The contents are expected to be "start" aligned.

label: @Composable RowScope.() -> Unit

A slot for providing the button's main label. The contents are expected to be text which is "start" aligned.

@Composable
fun Stepper(
    value: Int,
    onValueChange: (Int) -> Unit,
    valueProgression: IntProgression,
    decreaseIcon: @Composable () -> Unit,
    increaseIcon: @Composable () -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    colors: StepperColors = StepperDefaults.colors(),
    content: @Composable BoxScope.() -> Unit
): Unit

Stepper allows users to make a selection from a range of values. It's a full-screen control with increase button on the top, decrease button on the bottom and a slot (expected to have either Text or Button) in the middle. Value can be increased and decreased by clicking on the increase and decrease buttons. Buttons can have custom icons - decreaseIcon and increaseIcon. Stepper itself doesn't show the current value but can be displayed via the content slot or LevelIndicator if required. To add range semantics on Stepper, use Modifier.rangeSemantics.

Example of a Stepper with integer values:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.material3.LevelIndicator
import androidx.wear.compose.material3.Stepper
import androidx.wear.compose.material3.StepperDefaults
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.samples.icons.VolumeDownIcon
import androidx.wear.compose.material3.samples.icons.VolumeUpIcon

var value by remember { mutableIntStateOf(3) }
val valueProgression = 0..10
Box(modifier = Modifier.fillMaxSize()) {
    Stepper(
        value = value,
        onValueChange = { value = it },
        valueProgression = valueProgression,
        decreaseIcon = { VolumeDownIcon(StepperDefaults.IconSize) },
        increaseIcon = { VolumeUpIcon(StepperDefaults.IconSize) },
    ) {
        Text(String.format("Value: %d".format(value)))
    }
    LevelIndicator(
        value = { value },
        valueProgression = valueProgression,
        modifier = Modifier.align(Alignment.CenterStart)
    )
}

A number of steps is calculated as the difference between max and min values of valueProgression divided by valueProgression.step - 1. For example, with a range of 100..120 and a step 5, number of steps will be (120-100)/ 5 - 1 = 3. Steps are 100(first), 105, 110, 115, 120(last)

If valueProgression range is not equally divisible by valueProgression.step, then valueProgression.last will be adjusted to the closest divisible value in the range. For example, 1..13 range and a step = 5, steps will be 1(first), 6, 11(last)

If value is not equal to any step value, then it will be coerced to the closest step value. However, the value itself will not be changed and onValueChange in this case will not be triggered.

Parameters
value: Int

Current value of the Stepper. If outside of valueProgression provided, value will be coerced to this range.

onValueChange: (Int) -> Unit

Lambda in which value should be updated.

valueProgression: IntProgression

Progression of values that Stepper value can take. Consists of rangeStart, rangeEnd and step. Range will be equally divided by step size.

decreaseIcon: @Composable () -> Unit

A slot for an icon which is placed on the decrease (bottom) button.

increaseIcon: @Composable () -> Unit

A slot for an icon which is placed on the increase (top) button.

modifier: Modifier = Modifier

Modifiers for the Stepper layout.

enabled: Boolean = true

Whether the Stepper is enabled.

colors: StepperColors = StepperDefaults.colors()

StepperColors that will be used to resolve the colors used for this Stepper. See StepperDefaults.colors.

content: @Composable BoxScope.() -> Unit

Content body for the Stepper.

@Composable
fun Stepper(
    value: Float,
    onValueChange: (Float) -> Unit,
    steps: Int,
    decreaseIcon: @Composable () -> Unit,
    increaseIcon: @Composable () -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    valueRange: ClosedFloatingPointRange<Float> = 0f..(steps + 1).toFloat(),
    colors: StepperColors = StepperDefaults.colors(),
    content: @Composable BoxScope.() -> Unit
): Unit

Stepper allows users to make a selection from a range of values. It's a full-screen control with increase button on the top, decrease button on the bottom and a slot (expected to have either Text or Button) in the middle. Value can be increased and decreased by clicking on the increase and decrease buttons. Buttons can have custom icons - decreaseIcon and increaseIcon. Step value is calculated as the difference between min and max values divided by steps+1. Stepper itself doesn't show the current value but can be displayed via the content slot or LevelIndicator if required. If value is not equal to any step value, then it will be coerced to the closest step value. However, the value itself will not be changed and onValueChange in this case will not be triggered. To add range semantics on Stepper, use Modifier.rangeSemantics.

Example of a simple Stepper with LevelIndicator:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.material3.LevelIndicator
import androidx.wear.compose.material3.Stepper
import androidx.wear.compose.material3.StepperDefaults
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.samples.icons.VolumeDownIcon
import androidx.wear.compose.material3.samples.icons.VolumeUpIcon

var value by remember { mutableFloatStateOf(2f) }
val valueRange = 0f..4f
Box(modifier = Modifier.fillMaxSize()) {
    Stepper(
        value = value,
        onValueChange = { value = it },
        valueRange = valueRange,
        steps = 7,
        decreaseIcon = { VolumeDownIcon(StepperDefaults.IconSize) },
        increaseIcon = { VolumeUpIcon(StepperDefaults.IconSize) },
    ) {
        Text(String.format("Value: %.1f".format(value)))
    }
    LevelIndicator(
        value = { value },
        valueRange = valueRange,
        modifier = Modifier.align(Alignment.CenterStart)
    )
}

Example of a Stepper with range semantics:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.material3.LevelIndicator
import androidx.wear.compose.material3.Stepper
import androidx.wear.compose.material3.StepperDefaults
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.rangeSemantics
import androidx.wear.compose.material3.samples.icons.VolumeDownIcon
import androidx.wear.compose.material3.samples.icons.VolumeUpIcon

var value by remember { mutableFloatStateOf(2f) }
val valueRange = 0f..4f
val onValueChange = { i: Float -> value = i }
val steps = 7
Box(modifier = Modifier.fillMaxSize()) {
    Stepper(
        value = value,
        onValueChange = onValueChange,
        valueRange = valueRange,
        modifier = Modifier.rangeSemantics(value, true, onValueChange, valueRange, steps),
        steps = steps,
        decreaseIcon = { VolumeDownIcon(StepperDefaults.IconSize) },
        increaseIcon = { VolumeUpIcon(StepperDefaults.IconSize) },
    ) {
        Text("Value: $value")
    }
    LevelIndicator(
        value = { value },
        valueRange = valueRange,
        modifier = Modifier.align(Alignment.CenterStart)
    )
}

Example of a Stepper with Custom icons and Button content:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.width
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.LevelIndicator
import androidx.wear.compose.material3.Stepper
import androidx.wear.compose.material3.StepperDefaults
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.samples.icons.HeadphoneIcon
import androidx.wear.compose.material3.samples.icons.VolumeDownIcon
import androidx.wear.compose.material3.samples.icons.VolumeUpIcon

var value by remember { mutableFloatStateOf(2f) }
val valueRange = 0f..4f
Box(modifier = Modifier.fillMaxSize()) {
    Stepper(
        value = value,
        onValueChange = { value = it },
        valueRange = valueRange,
        increaseIcon = { VolumeUpIcon(StepperDefaults.IconSize) },
        decreaseIcon = { VolumeDownIcon(StepperDefaults.IconSize) },
        steps = 7
    ) {
        Text(String.format("Value: %.1f".format(value)))
        Button(
            onClick = {},
            modifier = Modifier.width(150.dp),
            label = { Text(text = "This watch", modifier = Modifier.fillMaxWidth()) },
            secondaryLabel = { Text(text = "Headphones", modifier = Modifier.fillMaxWidth()) },
            icon = { HeadphoneIcon(24.dp) },
        )
    }
    LevelIndicator(
        value = { value },
        valueRange = valueRange,
        modifier = Modifier.align(Alignment.CenterStart)
    )
}
Parameters
value: Float

Current value of the Stepper. If outside of valueRange provided, value will be coerced to this range.

onValueChange: (Float) -> Unit

Lambda in which value should be updated.

steps: Int

Specifies the number of discrete values, excluding min and max values, evenly distributed across the whole value range. Must not be negative. If 0, stepper will have only min and max values and no steps in between.

decreaseIcon: @Composable () -> Unit

A slot for an icon which is placed on the decrease (bottom) button.

increaseIcon: @Composable () -> Unit

A slot for an icon which is placed on the increase (top) button.

modifier: Modifier = Modifier

Modifiers for the Stepper layout.

enabled: Boolean = true

Whether the Stepper is enabled.

valueRange: ClosedFloatingPointRange<Float> = 0f..(steps + 1).toFloat()

Range of values that Stepper value can take. Passed value will be coerced to this range.

colors: StepperColors = StepperDefaults.colors()

StepperColors that will be used to resolve the colors used for this Stepper. See StepperDefaults.colors.

content: @Composable BoxScope.() -> Unit

Content body for the Stepper.

SuccessConfirmation

@Composable
fun SuccessConfirmation(
    show: Boolean,
    onDismissRequest: () -> Unit,
    modifier: Modifier = Modifier,
    curvedText: (CurvedScope.() -> Unit)? = ConfirmationDefaults.successText(),
    colors: ConfirmationColors = ConfirmationDefaults.successColors(),
    properties: DialogProperties = DialogProperties(),
    durationMillis: Long = ConfirmationDefaults.ConfirmationDurationMillis,
    content: @Composable BoxScope.() -> Unit = ConfirmationDefaults.SuccessIcon
): Unit

Shows a Confirmation dialog with a success icon and optional short curved text. This confirmation indicates a successful operation or action.

The confirmation will show a message to the user for durationMillis. After a specified timeout, the onDismissRequest callback will be invoked, where it's up to the caller to handle the dismissal. To hide the confirmation, show parameter should be set to false.

Example of a SuccessConfirmation usage:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.material3.Confirmation
import androidx.wear.compose.material3.FilledTonalButton
import androidx.wear.compose.material3.SuccessConfirmation
import androidx.wear.compose.material3.Text

var showConfirmation by remember { mutableStateOf(false) }

Box(Modifier.fillMaxSize()) {
    FilledTonalButton(
        modifier = Modifier.align(Alignment.Center),
        onClick = { showConfirmation = true },
        label = { Text("Show Confirmation") }
    )
}

SuccessConfirmation(show = showConfirmation, onDismissRequest = { showConfirmation = false })
Parameters
show: Boolean

A boolean indicating whether the confirmation should be displayed.

onDismissRequest: () -> Unit

A lambda function to be called when the dialog is dismissed - either by swiping right or when the durationMillis has passed.

modifier: Modifier = Modifier

Modifier to be applied to the confirmation content.

curvedText: (CurvedScope.() -> Unit)? = ConfirmationDefaults.successText()

A slot for displaying curved text content which will be shown along the bottom edge of the dialog. Defaults to a localized success message.

colors: ConfirmationColors = ConfirmationDefaults.successColors()

A ConfirmationColors object for customizing the colors used in this SuccessConfirmation.

properties: DialogProperties = DialogProperties()

An optional DialogProperties object for configuring the dialog's behavior.

durationMillis: Long = ConfirmationDefaults.ConfirmationDurationMillis

The duration in milliseconds for which the dialog is displayed. Defaults to ConfirmationDefaults.ConfirmationDurationMillis.

content: @Composable BoxScope.() -> Unit = ConfirmationDefaults.SuccessIcon

A slot for displaying an icon inside the confirmation dialog, which can be animated. Defaults to an animated ConfirmationDefaults.SuccessIcon.

@Composable
fun SwipeToDismissBox(
    state: SwipeToDismissBoxState,
    modifier: Modifier = Modifier,
    backgroundScrimColor: Color = MaterialTheme.colorScheme.background,
    contentScrimColor: Color = MaterialTheme.colorScheme.background,
    backgroundKey: Any = SwipeToDismissKeys.Background,
    contentKey: Any = SwipeToDismissKeys.Content,
    userSwipeEnabled: Boolean = true,
    content: @Composable BoxScope.(isBackground: Boolean) -> Unit
): Unit

Wear Material 3 SwipeToDismissBox that handles the swipe-to-dismiss gesture. Takes a single slot for the background (only displayed during the swipe gesture) and the foreground content.

Example of a SwipeToDismissBox with stateful composables:

import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.saveable.rememberSaveableStateHolder
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.wear.compose.foundation.SwipeToDismissValue
import androidx.wear.compose.foundation.rememberSwipeToDismissBoxState
import androidx.wear.compose.material3.CheckboxButton
import androidx.wear.compose.material3.MaterialTheme
import androidx.wear.compose.material3.SwipeToDismissBox
import androidx.wear.compose.material3.Text

// State for managing a 2-level navigation hierarchy between
// MainScreen and ItemScreen composables.
// Alternatively, use SwipeDismissableNavHost from wear.compose.navigation.
var showMainScreen by remember { mutableStateOf(true) }
val saveableStateHolder = rememberSaveableStateHolder()

// Swipe gesture dismisses ItemScreen to return to MainScreen.
val state = rememberSwipeToDismissBoxState()
LaunchedEffect(state.currentValue) {
    if (state.currentValue == SwipeToDismissValue.Dismissed) {
        state.snapTo(SwipeToDismissValue.Default)
        showMainScreen = !showMainScreen
    }
}

// Hierarchy is ListScreen -> ItemScreen, so we show ListScreen as the background behind
// the ItemScreen, otherwise there's no background to show.
SwipeToDismissBox(
    state = state,
    userSwipeEnabled = !showMainScreen,
    backgroundKey = if (!showMainScreen) "MainKey" else "Background",
    contentKey = if (showMainScreen) "MainKey" else "ItemKey",
) { isBackground ->
    if (isBackground || showMainScreen) {
        // Best practice would be to use State Hoisting and leave this composable stateless.
        // Here, we want to support MainScreen being shown from different destinations
        // (either in the foreground or in the background during swiping) - that can be achieved
        // using SaveableStateHolder and rememberSaveable as shown below.
        saveableStateHolder.SaveableStateProvider(
            key = "MainKey",
            content = {
                // Composable that maintains its own state
                // and can be shown in foreground or background.
                val checked = rememberSaveable { mutableStateOf(true) }
                Column(
                    modifier =
                        Modifier.fillMaxSize().padding(horizontal = 8.dp, vertical = 8.dp),
                    verticalArrangement =
                        Arrangement.spacedBy(4.dp, Alignment.CenterVertically),
                ) {
                    Row(
                        modifier =
                            Modifier.height(40.dp)
                                .background(
                                    color = MaterialTheme.colorScheme.surfaceContainer,
                                    shape = CircleShape
                                )
                                .padding(horizontal = 12.dp),
                        verticalAlignment = Alignment.CenterVertically,
                    ) {
                        Box(modifier = Modifier.clickable { showMainScreen = false }) {
                            Text("Item details")
                        }
                        CheckboxButton(
                            label = { Text("Checkbox", maxLines = 1) },
                            checked = checked.value,
                            onCheckedChange = { checked.value = it },
                        )
                    }
                }
            }
        )
    } else {
        Column(
            modifier = Modifier.fillMaxSize().background(MaterialTheme.colorScheme.primary),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.Center,
        ) {
            Text("Show details here...", color = MaterialTheme.colorScheme.onPrimary)
            Text("Swipe right to dismiss", color = MaterialTheme.colorScheme.onPrimary)
        }
    }
}

Example of using Modifier.edgeSwipeToDismiss with SwipeToDismissBox:

import androidx.compose.foundation.background
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.rememberScrollState
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.foundation.edgeSwipeToDismiss
import androidx.wear.compose.foundation.rememberSwipeToDismissBoxState
import androidx.wear.compose.material3.MaterialTheme
import androidx.wear.compose.material3.SwipeToDismissBox
import androidx.wear.compose.material3.Text

val state = rememberSwipeToDismissBoxState()

// When using Modifier.edgeSwipeToDismiss, it is required that the element on which the
// modifier applies exists within a SwipeToDismissBox which shares the same state.
SwipeToDismissBox(state = state, onDismissed = navigateBack) { isBackground ->
    val horizontalScrollState = rememberScrollState(0)
    if (isBackground) {
        Box(
            modifier =
                Modifier.fillMaxSize().background(MaterialTheme.colorScheme.secondaryContainer)
        )
    } else {
        Box(modifier = Modifier.fillMaxSize()) {
            Text(
                modifier =
                    Modifier.align(Alignment.Center)
                        .edgeSwipeToDismiss(state)
                        .horizontalScroll(horizontalScrollState),
                text =
                    "This text can be scrolled horizontally - to dismiss, swipe " +
                        "right from the left edge of the screen (called Edge Swiping)",
            )
        }
    }
}

For more information, see the Swipe to dismiss guide.

Parameters
state: SwipeToDismissBoxState

State containing information about ongoing swipe or animation.

modifier: Modifier = Modifier

Modifier for this component.

backgroundScrimColor: Color = MaterialTheme.colorScheme.background

Color for background scrim.

contentScrimColor: Color = MaterialTheme.colorScheme.background

Color used for the scrim over the content composable during the swipe gesture.

backgroundKey: Any = SwipeToDismissKeys.Background

key which identifies the content currently composed in the content block when isBackground == true. Provide the backgroundKey if your background content will be displayed as a foreground after the swipe animation ends (as is common when SwipeToDismissBox is used for the navigation). This allows remembered state to be correctly moved between background and foreground.

contentKey: Any = SwipeToDismissKeys.Content

key which identifies the content currently composed in the content block when isBackground == false. See backgroundKey.

userSwipeEnabled: Boolean = true

Whether the swipe gesture is enabled. (e.g. when there is no background screen, set userSwipeEnabled = false)

content: @Composable BoxScope.(isBackground: Boolean) -> Unit

Slot for content, with the isBackground parameter enabling content to be displayed behind the foreground content - the background is normally hidden, is shown behind a scrim during the swipe gesture, and is shown without scrim once the finger passes the swipe-to-dismiss threshold.

@Composable
fun SwipeToDismissBox(
    onDismissed: () -> Unit,
    modifier: Modifier = Modifier,
    state: SwipeToDismissBoxState = rememberSwipeToDismissBoxState(),
    backgroundScrimColor: Color = MaterialTheme.colorScheme.background,
    contentScrimColor: Color = MaterialTheme.colorScheme.background,
    backgroundKey: Any = SwipeToDismissKeys.Background,
    contentKey: Any = SwipeToDismissKeys.Content,
    userSwipeEnabled: Boolean = true,
    content: @Composable BoxScope.(isBackground: Boolean) -> Unit
): Unit

Wear Material 3 SwipeToDismissBox that handles the swipe-to-dismiss gesture. This overload takes an onDismissed parameter which is used to execute a command when the swipe to dismiss has completed, such as navigating to another screen.

Example of a simple SwipeToDismissBox:

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.material3.MaterialTheme
import androidx.wear.compose.material3.SwipeToDismissBox
import androidx.wear.compose.material3.Text

SwipeToDismissBox(onDismissed = navigateBack) { isBackground ->
    if (isBackground) {
        Box(
            modifier =
                Modifier.fillMaxSize().background(MaterialTheme.colorScheme.secondaryContainer)
        )
    } else {
        Column(
            modifier = Modifier.fillMaxSize().background(MaterialTheme.colorScheme.primary),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.Center,
        ) {
            Text("Swipe right to dismiss", color = MaterialTheme.colorScheme.onPrimary)
        }
    }
}

Example of using Modifier.edgeSwipeToDismiss with SwipeToDismissBox:

import androidx.compose.foundation.background
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.rememberScrollState
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.foundation.edgeSwipeToDismiss
import androidx.wear.compose.foundation.rememberSwipeToDismissBoxState
import androidx.wear.compose.material3.MaterialTheme
import androidx.wear.compose.material3.SwipeToDismissBox
import androidx.wear.compose.material3.Text

val state = rememberSwipeToDismissBoxState()

// When using Modifier.edgeSwipeToDismiss, it is required that the element on which the
// modifier applies exists within a SwipeToDismissBox which shares the same state.
SwipeToDismissBox(state = state, onDismissed = navigateBack) { isBackground ->
    val horizontalScrollState = rememberScrollState(0)
    if (isBackground) {
        Box(
            modifier =
                Modifier.fillMaxSize().background(MaterialTheme.colorScheme.secondaryContainer)
        )
    } else {
        Box(modifier = Modifier.fillMaxSize()) {
            Text(
                modifier =
                    Modifier.align(Alignment.Center)
                        .edgeSwipeToDismiss(state)
                        .horizontalScroll(horizontalScrollState),
                text =
                    "This text can be scrolled horizontally - to dismiss, swipe " +
                        "right from the left edge of the screen (called Edge Swiping)",
            )
        }
    }
}

For more information, see the Swipe to dismiss guide.

Parameters
onDismissed: () -> Unit

Executes when the swipe to dismiss has completed.

modifier: Modifier = Modifier

Modifier for this component.

state: SwipeToDismissBoxState = rememberSwipeToDismissBoxState()

State containing information about ongoing swipe or animation.

backgroundScrimColor: Color = MaterialTheme.colorScheme.background

Color for background scrim.

contentScrimColor: Color = MaterialTheme.colorScheme.background

Color used for the scrim over the content composable during the swipe gesture.

backgroundKey: Any = SwipeToDismissKeys.Background

key which identifies the content currently composed in the content block when isBackground == true. Provide the backgroundKey if your background content will be displayed as a foreground after the swipe animation ends (as is common when SwipeToDismissBox is used for the navigation). This allows remembered state to be correctly moved between background and foreground.

contentKey: Any = SwipeToDismissKeys.Content

key which identifies the content currently composed in the content block when isBackground == false. See backgroundKey.

userSwipeEnabled: Boolean = true

Whether the swipe gesture is enabled. (e.g. when there is no background screen, set userSwipeEnabled = false)

content: @Composable BoxScope.(isBackground: Boolean) -> Unit

Slot for content, with the isBackground parameter enabling content to be displayed behind the foreground content - the background is normally hidden, is shown behind a scrim during the swipe gesture, and is shown without scrim once the finger passes the swipe-to-dismiss threshold.

@Composable
fun SwipeToReveal(
    actions: SwipeToRevealScope.() -> Unit,
    modifier: Modifier = Modifier,
    revealState: RevealState = rememberRevealState(),
    actionButtonHeight: Dp = SwipeToRevealDefaults.SmallActionButtonHeight,
    content: @Composable () -> Unit
): Unit

SwipeToReveal Material composable. This adds the option to configure up to two additional actions on a Composable: a mandatory SwipeToRevealScope.primaryAction and an optional SwipeToRevealScope.secondaryAction. These actions are initially hidden and revealed only when the content is swiped. These additional actions can be triggered by clicking on them after they are revealed. SwipeToRevealScope.primaryAction will be triggered on full swipe of the content.

For actions like "Delete", consider adding SwipeToRevealScope.undoPrimaryAction (displayed when the SwipeToRevealScope.primaryAction is activated). Adding undo composables allow users to undo the action that they just performed.

SwipeToReveal composable adds the CustomAccessibilityActions using the labels from primary and secondary actions.

Example of SwipeToReveal with primary and secondary actions

import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Delete
import androidx.compose.material.icons.outlined.MoreVert
import androidx.compose.ui.Modifier
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.SwipeToReveal
import androidx.wear.compose.material3.SwipeToRevealDefaults
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.rememberRevealState

SwipeToReveal(
    // Use the double action anchor width when revealing two actions
    revealState =
        rememberRevealState(
            anchorWidth = SwipeToRevealDefaults.DoubleActionAnchorWidth,
        ),
    actions = {
        primaryAction(
            onClick = { /* This block is called when the primary action is executed. */ },
            icon = { Icon(Icons.Outlined.Delete, contentDescription = "Delete") },
            label = "Delete"
        )
        secondaryAction(
            onClick = { /* This block is called when the secondary action is executed. */ },
            icon = { Icon(Icons.Outlined.MoreVert, contentDescription = "Options") },
            label = "Options"
        )
        undoPrimaryAction(
            onClick = { /* This block is called when the undo primary action is executed. */ },
            label = "Undo Delete"
        )
    }
) {
    Button(modifier = Modifier.fillMaxWidth(), onClick = {}) {
        Text("This Button has two actions", modifier = Modifier.fillMaxSize())
    }
}

Example of SwipeToReveal with a Card composable, it reveals a taller button.

import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Delete
import androidx.compose.ui.Modifier
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.Card
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.SwipeToReveal
import androidx.wear.compose.material3.SwipeToRevealDefaults
import androidx.wear.compose.material3.Text

SwipeToReveal(
    actionButtonHeight = SwipeToRevealDefaults.LargeActionButtonHeight,
    actions = {
        primaryAction(
            onClick = { /* This block is called when the primary action is executed. */ },
            icon = { Icon(Icons.Outlined.Delete, contentDescription = "Delete") },
            label = "Delete"
        )
    }
) {
    Card(modifier = Modifier.fillMaxWidth(), onClick = {}) {
        Text(
            "This Card has one action, and the revealed button is taller",
            modifier = Modifier.fillMaxSize()
        )
    }
}

Example of SwipeToReveal that doesn't reveal the actions, instead it only executes them when fully swiped or bounces back to its initial state.

import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Delete
import androidx.compose.material.icons.outlined.Refresh
import androidx.compose.ui.Modifier
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.SwipeToReveal
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.rememberRevealState

SwipeToReveal(
    revealState = rememberRevealState(useAnchoredActions = false),
    actions = {
        primaryAction(
            onClick = { /* This block is called when the primary action is executed. */ },
            icon = { Icon(Icons.Outlined.Delete, contentDescription = "Delete") },
            label = "Delete"
        )
        undoPrimaryAction(
            onClick = { /* This block is called when the undo primary action is executed. */ },
            icon = { Icon(Icons.Outlined.Refresh, contentDescription = "Undo") },
            label = "Undo"
        )
    }
) {
    Button(modifier = Modifier.fillMaxWidth(), onClick = {}) {
        Text("Swipe to execute the primary action.", modifier = Modifier.fillMaxSize())
    }
}
Parameters
actions: SwipeToRevealScope.() -> Unit

Actions of the SwipeToReveal composable, such as SwipeToRevealScope.primaryAction. actions should always include exactly one SwipeToRevealScope.primaryAction. SwipeToRevealScope.secondaryAction, SwipeToRevealScope.undoPrimaryAction and SwipeToRevealScope.undoSecondaryAction are optional.

modifier: Modifier = Modifier

Modifier to be applied on the composable

revealState: RevealState = rememberRevealState()

RevealState of the SwipeToReveal

actionButtonHeight: Dp = SwipeToRevealDefaults.SmallActionButtonHeight

Desired height of the revealed action buttons. In case the content is a Button composable, it's suggested to use SwipeToRevealDefaults.SmallActionButtonHeight, and for a Card composable, it's suggested to use SwipeToRevealDefaults.LargeActionButtonHeight.

content: @Composable () -> Unit

The content that will be initially displayed over the other actions provided.

See also
SwipeToReveal
@Composable
fun SwitchButton(
    checked: Boolean,
    onCheckedChange: (Boolean) -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    shape: Shape = SwitchButtonDefaults.switchButtonShape,
    colors: SwitchButtonColors = SwitchButtonDefaults.switchButtonColors(),
    contentPadding: PaddingValues = SwitchButtonDefaults.ContentPadding,
    interactionSource: MutableInteractionSource? = null,
    icon: (@Composable BoxScope.() -> Unit)? = null,
    secondaryLabel: (@Composable RowScope.() -> Unit)? = null,
    label: @Composable RowScope.() -> Unit
): Unit

The Wear Material SwitchButton offers three slots and a specific layout for an icon, a label, and a secondaryLabel. The icon and secondaryLabel are optional. The items are laid out in a row with the optional icon at the start and a column containing the two label slots in the middle.

The SwitchButton is Stadium shaped. The label should take no more than 3 lines of text. The secondary label should take no more than 2 lines of text. With localisation and/or large font sizes, the SwitchButton height adjusts to accommodate the contents. The label and secondary label are start aligned by default.

Example of a SwitchButton:

import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.text.style.TextOverflow
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.SwitchButton
import androidx.wear.compose.material3.Text

var checked by remember { mutableStateOf(true) }
SwitchButton(
    label = { Text("Switch Button", maxLines = 3, overflow = TextOverflow.Ellipsis) },
    secondaryLabel = {
        Text("With secondary label", maxLines = 2, overflow = TextOverflow.Ellipsis)
    },
    checked = checked,
    onCheckedChange = { checked = it },
    icon = { Icon(Icons.Filled.Favorite, contentDescription = "Favorite icon") },
    enabled = true,
)

SwitchButton can be enabled or disabled. A disabled button will not respond to click events.

The recommended set of SwitchButton colors can be obtained from SwitchButtonDefaults, e.g. SwitchButtonDefaults.switchButtonColors.

Parameters
checked: Boolean

Boolean flag indicating whether this button is currently checked.

onCheckedChange: (Boolean) -> Unit

Callback to be invoked when this buttons checked status is changed.

modifier: Modifier = Modifier

Modifier to be applied to the SwitchButton.

enabled: Boolean = true

Controls the enabled state of the button. When false, this button will not be clickable.

shape: Shape = SwitchButtonDefaults.switchButtonShape

Defines the button's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material Theme.

colors: SwitchButtonColors = SwitchButtonDefaults.switchButtonColors()

SwitchButtonColors that will be used to resolve the background and content color for this button in different states.

contentPadding: PaddingValues = SwitchButtonDefaults.ContentPadding

The spacing values to apply internally between the container and the content.

interactionSource: MutableInteractionSource? = null

an optional hoisted MutableInteractionSource for observing and emitting Interactions for this button's "toggleable" tap area. You can use this to change the button's appearance or preview the button in different states. Note that if null is provided, interactions will still happen internally.

icon: (@Composable BoxScope.() -> Unit)? = null

An optional slot for providing an icon to indicate the purpose of the button. The contents are expected to be a horizontally and vertically center aligned icon of size 24.dp.

secondaryLabel: (@Composable RowScope.() -> Unit)? = null

A slot for providing the button's secondary label. The contents are expected to be text which is "start" aligned.

label: @Composable RowScope.() -> Unit

A slot for providing the button's main label. The contents are expected to be text which is "start" aligned and no more than 3 lines of text.

@Composable
fun Text(
    text: String,
    modifier: Modifier = Modifier,
    color: Color = Color.Unspecified,
    fontSize: TextUnit = TextUnit.Unspecified,
    fontStyle: FontStyle? = null,
    fontWeight: FontWeight? = null,
    fontFamily: FontFamily? = null,
    letterSpacing: TextUnit = TextUnit.Unspecified,
    textDecoration: TextDecoration? = null,
    textAlign: TextAlign? = LocalTextConfiguration.current.textAlign,
    lineHeight: TextUnit = TextUnit.Unspecified,
    overflow: TextOverflow = LocalTextConfiguration.current.overflow,
    softWrap: Boolean = true,
    maxLines: Int = LocalTextConfiguration.current.maxLines,
    minLines: Int = 1,
    onTextLayout: (TextLayoutResult) -> Unit = {},
    style: TextStyle = LocalTextStyle.current
): Unit

High level element that displays text and provides semantics / accessibility information.

The default style uses the LocalTextStyle provided by the MaterialTheme / components. If you are setting your own style, you may want to consider first retrieving LocalTextStyle, and using TextStyle.copy to keep any theme defined attributes, only modifying the specific attributes you want to override.

For ease of use, commonly used parameters from TextStyle are also present here. The order of precedence is as follows:

  • If a parameter is explicitly set here (i.e, it is not null or TextUnit.Unspecified), then this parameter will always be used.

  • If a parameter is not set, (null or TextUnit.Unspecified), then the corresponding value from style will be used instead.

Additionally, for color, if color is not set, and style does not have a color, then LocalContentColor will be used.

Parameters
text: String

The text to be displayed.

modifier: Modifier = Modifier

Modifier to apply to this layout node.

color: Color = Color.Unspecified

Color to apply to the text. If Color.Unspecified, and style has no color set, this will be LocalContentColor.

fontSize: TextUnit = TextUnit.Unspecified

The size of glyphs to use when painting the text. See TextStyle.fontSize.

fontStyle: FontStyle? = null

The typeface variant to use when drawing the letters (e.g., italic). See TextStyle.fontStyle.

fontWeight: FontWeight? = null

The typeface thickness to use when painting the text (e.g., FontWeight.Bold).

fontFamily: FontFamily? = null

The font family to be used when rendering the text. See TextStyle.fontFamily.

letterSpacing: TextUnit = TextUnit.Unspecified

The amount of space to add between each letter. See TextStyle.letterSpacing.

textDecoration: TextDecoration? = null

The decorations to paint on the text (e.g., an underline). See TextStyle.textDecoration.

textAlign: TextAlign? = LocalTextConfiguration.current.textAlign

The alignment of the text within the lines of the paragraph. See TextStyle.textAlign.

lineHeight: TextUnit = TextUnit.Unspecified

Line height for the Paragraph in TextUnit unit, e.g. SP or EM. See TextStyle.lineHeight.

overflow: TextOverflow = LocalTextConfiguration.current.overflow

How visual overflow should be handled.

softWrap: Boolean = true

Whether the text should break at soft line breaks. If false, the glyphs in the text will be positioned as if there was unlimited horizontal space. If softWrap is false, overflow and TextAlign may have unexpected effects.

maxLines: Int = LocalTextConfiguration.current.maxLines

An optional maximum number of lines for the text to span, wrapping if necessary. If the text exceeds the given number of lines, it will be truncated according to overflow and softWrap. If it is not null, then it must be greater than zero.

minLines: Int = 1

The minimum height in terms of minimum number of visible lines. It is required that 1 <= minLines<= maxLines.

onTextLayout: (TextLayoutResult) -> Unit = {}

Callback that is executed when a new text layout is calculated. A TextLayoutResult object that callback provides contains paragraph information, size of the text, baselines and other details. The callback can be used to add additional decoration or functionality to the text. For example, to draw selection around the text.

style: TextStyle = LocalTextStyle.current

Style configuration for the text such as color, font, line height etc.

@Composable
fun Text(
    text: AnnotatedString,
    modifier: Modifier = Modifier,
    color: Color = Color.Unspecified,
    fontSize: TextUnit = TextUnit.Unspecified,
    fontStyle: FontStyle? = null,
    fontWeight: FontWeight? = null,
    fontFamily: FontFamily? = null,
    letterSpacing: TextUnit = TextUnit.Unspecified,
    textDecoration: TextDecoration? = null,
    textAlign: TextAlign? = LocalTextConfiguration.current.textAlign,
    lineHeight: TextUnit = TextUnit.Unspecified,
    overflow: TextOverflow = LocalTextConfiguration.current.overflow,
    softWrap: Boolean = true,
    maxLines: Int = LocalTextConfiguration.current.maxLines,
    minLines: Int = 1,
    inlineContent: Map<StringInlineTextContent> = mapOf(),
    onTextLayout: (TextLayoutResult) -> Unit = {},
    style: TextStyle = LocalTextStyle.current
): Unit

High level element that displays text and provides semantics / accessibility information.

The default style uses the LocalTextStyle provided by the MaterialTheme / components. If you are setting your own style, you may want to consider first retrieving LocalTextStyle, and using TextStyle.copy to keep any theme defined attributes, only modifying the specific attributes you want to override.

For ease of use, commonly used parameters from TextStyle are also present here. The order of precedence is as follows:

  • If a parameter is explicitly set here (i.e, it is not null or TextUnit.Unspecified), then this parameter will always be used.

  • If a parameter is not set, (null or TextUnit.Unspecified), then the corresponding value from style will be used instead.

Additionally, for color, if color is not set, and style does not have a color, then LocalContentColor will be used.

Parameters
text: AnnotatedString

The text to be displayed, where AnnotatedString allows multiple styles to be used.

modifier: Modifier = Modifier

Modifier to apply to this layout node.

color: Color = Color.Unspecified

Color to apply to the text. If Color.Unspecified, and style has no color set, this will be LocalContentColor.

fontSize: TextUnit = TextUnit.Unspecified

The size of glyphs to use when painting the text. See TextStyle.fontSize.

fontStyle: FontStyle? = null

The typeface variant to use when drawing the letters (e.g., italic). See TextStyle.fontStyle.

fontWeight: FontWeight? = null

The typeface thickness to use when painting the text (e.g., FontWeight.Bold).

fontFamily: FontFamily? = null

The font family to be used when rendering the text. See TextStyle.fontFamily.

letterSpacing: TextUnit = TextUnit.Unspecified

The amount of space to add between each letter. See TextStyle.letterSpacing.

textDecoration: TextDecoration? = null

The decorations to paint on the text (e.g., an underline). See TextStyle.textDecoration.

textAlign: TextAlign? = LocalTextConfiguration.current.textAlign

The alignment of the text within the lines of the paragraph. See TextStyle.textAlign.

lineHeight: TextUnit = TextUnit.Unspecified

Line height for the Paragraph in TextUnit unit, e.g. SP or EM. See TextStyle.lineHeight.

overflow: TextOverflow = LocalTextConfiguration.current.overflow

How visual overflow should be handled.

softWrap: Boolean = true

Whether the text should break at soft line breaks. If false, the glyphs in the text will be positioned as if there was unlimited horizontal space. If softWrap is false, overflow and TextAlign may have unexpected effects.

maxLines: Int = LocalTextConfiguration.current.maxLines

An optional maximum number of lines for the text to span, wrapping if necessary. If the text exceeds the given number of lines, it will be truncated according to overflow and softWrap. If it is not null, then it must be greater than zero.

minLines: Int = 1

The minimum height in terms of minimum number of visible lines. It is required that 1 <= minLines<= maxLines.

inlineContent: Map<StringInlineTextContent> = mapOf()

A map store composables that replaces certain ranges of the text. It's used to insert composables into text layout. Check InlineTextContent for more information.

onTextLayout: (TextLayoutResult) -> Unit = {}

Callback that is executed when a new text layout is calculated. A TextLayoutResult object that callback provides contains paragraph information, size of the text, baselines and other details. The callback can be used to add additional decoration or functionality to the text. For example, to draw selection around the text.

style: TextStyle = LocalTextStyle.current

Style configuration for the text such as color, font, line height etc.

@Composable
fun TextButton(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    onLongClick: (() -> Unit)? = null,
    onLongClickLabel: String? = null,
    enabled: Boolean = true,
    shapes: TextButtonShapes = TextButtonDefaults.shapes(),
    colors: TextButtonColors = TextButtonDefaults.textButtonColors(),
    border: BorderStroke? = null,
    interactionSource: MutableInteractionSource? = null,
    content: @Composable BoxScope.() -> Unit
): Unit

Wear Material TextButton is a circular, text-only button with transparent background and no border. It offers a single slot for text.

Set the size of the TextButton with Modifier.touchTargetAwareSize to ensure that the recommended minimum touch target size is available. The recommended TextButton sizes are TextButtonDefaults.DefaultButtonSize, TextButtonDefaults.LargeButtonSize and TextButtonDefaults.SmallButtonSize. The recommended text styles for each corresponding button size are TextButtonDefaults.defaultButtonTextStyle, TextButtonDefaults.largeButtonTextStyle and TextButtonDefaults.smallButtonTextStyle.

The default TextButton has no border and a transparent background for low emphasis actions. For actions that require high emphasis, set colors to TextButtonDefaults.filledTextButtonColors. For a medium-emphasis, outlined TextButton, set border to ButtonDefaults.outlinedButtonBorder. For a middle ground between outlined and filled, set colors to TextButtonDefaults.filledTonalTextButtonColors.

TextButton can be enabled or disabled. A disabled button will not respond to click events.

Example of a TextButton:

import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.TextButton

TextButton(onClick = { /* Do something */ }) { Text(text = "ABC") }

Example of a large, filled tonal TextButton:

import androidx.compose.foundation.layout.size
import androidx.compose.ui.Modifier
import androidx.wear.compose.material3.ButtonDefaults
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.TextButton
import androidx.wear.compose.material3.TextButtonDefaults

TextButton(
    onClick = { /* Do something */ },
    colors = TextButtonDefaults.filledTonalTextButtonColors(),
    modifier = Modifier.size(TextButtonDefaults.LargeButtonSize)
) {
    Text(text = "ABC", style = TextButtonDefaults.largeButtonTextStyle)
}

Example of TextButton with onLongClick:

import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.TextButton

TextButton(
    onClick = { /* Do something for onClick*/ },
    onLongClick = onLongClick,
    onLongClickLabel = "Long click"
) {
    Text(text = "ABC")
}

Example of an TextButton with shape animation of rounded corners on press:

import androidx.wear.compose.material3.ButtonDefaults
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.TextButton
import androidx.wear.compose.material3.TextButtonDefaults

TextButton(
    onClick = { /* Do something */ },
    shapes = TextButtonDefaults.animatedShapes(),
) {
    Text(text = "ABC")
}
Parameters
onClick: () -> Unit

Will be called when the user clicks the button.

modifier: Modifier = Modifier

Modifier to be applied to the button.

onLongClick: (() -> Unit)? = null

Called when this button is long clicked (long-pressed). When this callback is set, onLongClickLabel should be set as well.

onLongClickLabel: String? = null

Semantic / accessibility label for the onLongClick action.

enabled: Boolean = true

Controls the enabled state of the button. When false, this button will not be clickable.

shapes: TextButtonShapes = TextButtonDefaults.shapes()

Defines the shape for this button. Defaults to a static shape based on TextButtonDefaults.shape, but animated versions are available through TextButtonDefaults.animatedShapes.

colors: TextButtonColors = TextButtonDefaults.textButtonColors()

TextButtonColors that will be used to resolve the background and content color for this button in different states.

border: BorderStroke? = null

Optional BorderStroke that will be used to resolve the text button border in different states. See ButtonDefaults.outlinedButtonBorder.

interactionSource: MutableInteractionSource? = null

an optional hoisted MutableInteractionSource for observing and emitting Interactions for this button. You can use this to change the button's appearance or preview the button in different states. Note that if null is provided, interactions will still happen internally.

content: @Composable BoxScope.() -> Unit

The content displayed on the text button, expected to be text or image.

@Composable
fun TextToggleButton(
    checked: Boolean,
    onCheckedChange: (Boolean) -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    colors: TextToggleButtonColors = TextToggleButtonDefaults.textToggleButtonColors(),
    interactionSource: MutableInteractionSource? = null,
    shapes: TextToggleButtonShapes = TextToggleButtonDefaults.shapes(),
    border: BorderStroke? = null,
    content: @Composable BoxScope.() -> Unit
): Unit

Wear Material TextToggleButton is a filled text toggle button which switches between primary colors and tonal colors depending on checked value, and offers a single slot for text.

Set the size of the TextToggleButton with Modifier.touchTargetAwareSize to ensure that the background padding will correctly reach the edge of the minimum touch target. The recommended TextToggleButton sizes are TextToggleButtonDefaults.DefaultButtonSize, TextToggleButtonDefaults.LargeButtonSize and TextToggleButtonDefaults.ExtraLargeButtonSize. The recommended text styles for each corresponding button size are TextToggleButtonDefaults.defaultButtonTextStyle, TextToggleButtonDefaults.largeButtonTextStyle and TextToggleButtonDefaults.extraLargeButtonTextStyle.

TextToggleButton can be enabled or disabled. A disabled button will not respond to click events. When enabled, the checked and unchecked events are propagated by onCheckedChange.

A simple text toggle button using the default colors, animated when pressed.

import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.TextToggleButton
import androidx.wear.compose.material3.TextToggleButtonDefaults

var checked by remember { mutableStateOf(true) }
TextToggleButton(
    checked = checked,
    onCheckedChange = { checked = !checked },
    shapes = TextToggleButtonDefaults.animatedShapes(),
) {
    Text(text = if (checked) "On" else "Off")
}

A simple text toggle button using the default colors, animated when pressed and with different shapes for the checked and unchecked states.

import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.TextToggleButton
import androidx.wear.compose.material3.TextToggleButtonDefaults

var checked by remember { mutableStateOf(true) }
TextToggleButton(
    checked = checked,
    onCheckedChange = { checked = !checked },
    shapes = TextToggleButtonDefaults.variantAnimatedShapes()
) {
    Text(text = if (checked) "On" else "Off")
}

Example of a large text toggle button:

import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.TextButtonDefaults
import androidx.wear.compose.material3.TextToggleButton
import androidx.wear.compose.material3.TextToggleButtonDefaults
import androidx.wear.compose.material3.touchTargetAwareSize

var checked by remember { mutableStateOf(true) }
TextToggleButton(
    checked = checked,
    onCheckedChange = { checked = !checked },
    modifier = Modifier.touchTargetAwareSize(TextButtonDefaults.LargeButtonSize),
) {
    Text(
        text = if (checked) "On" else "Off",
        style = TextToggleButtonDefaults.largeButtonTextStyle,
    )
}
Parameters
checked: Boolean

Boolean flag indicating whether this toggle button is currently checked.

onCheckedChange: (Boolean) -> Unit

Callback to be invoked when this toggle button is clicked.

modifier: Modifier = Modifier

Modifier to be applied to the toggle button.

enabled: Boolean = true

Controls the enabled state of the toggle button. When false, this toggle button will not be clickable.

colors: TextToggleButtonColors = TextToggleButtonDefaults.textToggleButtonColors()

TextToggleButtonColors that will be used to resolve the container and content color for this toggle button.

interactionSource: MutableInteractionSource? = null

an optional hoisted MutableInteractionSource for observing and emitting Interactions for this toggle button. You can use this to change the toggle button's appearance or preview the toggle button in different states. Note that if null is provided, interactions will still happen internally.

shapes: TextToggleButtonShapes = TextToggleButtonDefaults.shapes()

Defines the shape for this toggle button. Defaults to a static shape based on TextToggleButtonDefaults.shape, but animated versions are available through TextToggleButtonDefaults.animatedShapes and TextToggleButtonDefaults.variantAnimatedShapes.

border: BorderStroke? = null

Optional BorderStroke for the TextToggleButton.

content: @Composable BoxScope.() -> Unit

The text to be drawn inside the toggle button.

@RequiresApi(value = 26)
@Composable
fun TimePicker(
    initialTime: LocalTime,
    onTimePicked: (LocalTime) -> Unit,
    modifier: Modifier = Modifier,
    timePickerType: TimePickerType = TimePickerDefaults.timePickerType,
    colors: TimePickerColors = TimePickerDefaults.timePickerColors()
): Unit

A full screen TimePicker with configurable columns that allows users to select a time.

This component is designed to take most/all of the screen and utilizes large fonts.

Example of a TimePicker:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Edit
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalConfiguration
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.TimePicker

var showTimePicker by remember { mutableStateOf(true) }
var timePickerTime by remember { mutableStateOf(LocalTime.now()) }
val formatter =
    DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)
        .withLocale(LocalConfiguration.current.locales[0])
if (showTimePicker) {
    TimePicker(
        onTimePicked = {
            timePickerTime = it
            showTimePicker = false
        },
        initialTime = timePickerTime // Initialize with last picked time on reopen
    )
} else {
    Box(
        modifier = Modifier.fillMaxSize(),
        contentAlignment = Alignment.Center,
    ) {
        Button(
            onClick = { showTimePicker = true },
            label = { Text("Selected Time") },
            secondaryLabel = { Text(timePickerTime.format(formatter)) },
            icon = { Icon(imageVector = Icons.Filled.Edit, contentDescription = "Edit") },
        )
    }
}

Example of a TimePicker with seconds:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Edit
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.TimePicker
import androidx.wear.compose.material3.TimePickerType

var showTimePicker by remember { mutableStateOf(true) }
var timePickerTime by remember { mutableStateOf(LocalTime.now()) }
val formatter = DateTimeFormatter.ofPattern("HH:mm:ss")
if (showTimePicker) {
    TimePicker(
        onTimePicked = {
            timePickerTime = it
            showTimePicker = false
        },
        timePickerType = TimePickerType.HoursMinutesSeconds24H,
        initialTime = timePickerTime // Initialize with last picked time on reopen
    )
} else {
    Box(
        modifier = Modifier.fillMaxSize(),
        contentAlignment = Alignment.Center,
    ) {
        Button(
            onClick = { showTimePicker = true },
            label = { Text("Selected Time") },
            secondaryLabel = { Text(timePickerTime.format(formatter)) },
            icon = { Icon(imageVector = Icons.Filled.Edit, contentDescription = "Edit") },
        )
    }
}

Example of a 12 hour clock TimePicker:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Edit
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.TimePicker
import androidx.wear.compose.material3.TimePickerType

var showTimePicker by remember { mutableStateOf(true) }
var timePickerTime by remember { mutableStateOf(LocalTime.now()) }
val formatter = DateTimeFormatter.ofPattern("hh:mm a")
if (showTimePicker) {
    TimePicker(
        onTimePicked = {
            timePickerTime = it
            showTimePicker = false
        },
        timePickerType = TimePickerType.HoursMinutesAmPm12H,
        initialTime = timePickerTime // Initialize with last picked time on reopen
    )
} else {
    Box(
        modifier = Modifier.fillMaxSize(),
        contentAlignment = Alignment.Center,
    ) {
        Button(
            onClick = { showTimePicker = true },
            label = { Text("Selected Time") },
            secondaryLabel = { Text(timePickerTime.format(formatter)) },
            icon = { Icon(imageVector = Icons.Filled.Edit, contentDescription = "Edit") },
        )
    }
}
Parameters
initialTime: LocalTime

The initial time to be displayed in the TimePicker.

onTimePicked: (LocalTime) -> Unit

The callback that is called when the user confirms the time selection. It provides the selected time as LocalTime.

modifier: Modifier = Modifier

Modifier to be applied to the Box containing the UI elements.

timePickerType: TimePickerType = TimePickerDefaults.timePickerType

The different TimePickerType supported by this time picker. It indicates whether to show seconds or AM/PM selector as well as hours and minutes.

colors: TimePickerColors = TimePickerDefaults.timePickerColors()

TimePickerColors be applied to the TimePicker.

@Composable
fun TimeText(
    modifier: Modifier = Modifier,
    curvedModifier: CurvedModifier = CurvedModifier,
    maxSweepAngle: Float = TimeTextDefaults.MaxSweepAngle,
    timeSource: TimeSource = TimeTextDefaults.rememberTimeSource(timeFormat()),
    timeTextStyle: TextStyle = TimeTextDefaults.timeTextStyle(),
    contentColor: Color = MaterialTheme.colorScheme.primary,
    contentPadding: PaddingValues = TimeTextDefaults.ContentPadding,
    content: TimeTextScope.() -> Unit = { time() }
): Unit

Layout to show the current time and a label at the top of the screen. If device has a round screen, then the time will be curved along the top edge of the screen, if rectangular - then the text and the time will be straight.

Note that Wear Material UX guidance recommends that time text should not be larger than TimeTextDefaults.MaxSweepAngle of the screen edge on round devices, which is enforced by default. It is recommended that additional content, if any, is limited to short status messages before the TimeTextScope.time using the MaterialTheme.colorScheme.primary color.

For more information, see the Curved Text guide.

Different components of TimeText can be added through methods of TimeTextScope.

A simple TimeText which shows the current time:

import androidx.wear.compose.material3.TimeText

// TimeText displays the current time by default.
TimeText()

A TimeText with a short app status message shown:

import androidx.wear.compose.material3.MaterialTheme
import androidx.wear.compose.material3.TimeText
import androidx.wear.compose.material3.TimeTextDefaults

val primaryStyle =
    TimeTextDefaults.timeTextStyle(color = MaterialTheme.colorScheme.primaryContainer)
TimeText {
    text("ETA 12:48", style = primaryStyle)
    separator()
    time()
}
Parameters
modifier: Modifier = Modifier

The modifier to be applied to the component.

curvedModifier: CurvedModifier = CurvedModifier

The CurvedModifier used to restrict the arc in which TimeText is drawn.

maxSweepAngle: Float = TimeTextDefaults.MaxSweepAngle

The default maximum sweep angle in degrees.

timeSource: TimeSource = TimeTextDefaults.rememberTimeSource(timeFormat())

TimeSource which retrieves the current time and formats it.

timeTextStyle: TextStyle = TimeTextDefaults.timeTextStyle()

TextStyle for the time text itself.

contentColor: Color = MaterialTheme.colorScheme.primary

Color of content of displayed through TimeTextScope.text and TimeTextScope.composable.

contentPadding: PaddingValues = TimeTextDefaults.ContentPadding

The spacing values between the container and the content.

content: TimeTextScope.() -> Unit = { time() }

The content of the TimeText - displays the current time by default.

@Composable
fun TitleCard(
    onClick: () -> Unit,
    title: @Composable RowScope.() -> Unit,
    modifier: Modifier = Modifier,
    onLongClick: (() -> Unit)? = null,
    onLongClickLabel: String? = null,
    time: (@Composable () -> Unit)? = null,
    subtitle: (@Composable ColumnScope.() -> Unit)? = null,
    enabled: Boolean = true,
    shape: Shape = CardDefaults.shape,
    colors: CardColors = CardDefaults.cardColors(),
    border: BorderStroke? = null,
    contentPadding: PaddingValues = CardDefaults.ContentPadding,
    interactionSource: MutableInteractionSource? = null,
    content: (@Composable () -> Unit)? = null
): Unit

Opinionated Wear Material 3 Card that offers a specific layout to show interactive information about an application, e.g. a message. TitleCards are designed for use within an application.

The time, subtitle and content fields are optional, but it is expected that at least one of these is provided. The layout will vary according to which fields are supplied - see samples.

If the content is text it can be single or multiple line and is expected to be Top and Start aligned. When subtitle is used content shouldn't exceed 2 lines height. Overall the title, content and subtitle text should be no more than 5 rows of text combined.

If more than one composable is provided in the content slot it is the responsibility of the caller to determine how to layout the contents, e.g. provide either a row or a column.

TitleCard scales itself appropriately when used within the scope of a TransformingLazyColumn.

Example of a TitleCard with time, title and content:

import androidx.wear.compose.material3.Card
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.TitleCard

TitleCard(
    onClick = { /* Do something */ },
    title = { Text("Title card") },
    time = { Text("Now") },
) {
    Text("Card content")
}

Example of a TitleCard with a background image:

import androidx.compose.foundation.Image
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
import androidx.wear.compose.material3.Card
import androidx.wear.compose.material3.CardDefaults
import androidx.wear.compose.material3.MaterialTheme
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.TitleCard

TitleCard(
    onClick = { /* Do something */ },
    title = { Text("Card title") },
    time = { Text("Now") },
    colors =
        CardDefaults.imageCardColors(
            containerPainter =
                CardDefaults.imageWithScrimBackgroundPainter(
                    backgroundImagePainter = painterResource(id = R.drawable.backgroundimage)
                ),
            contentColor = MaterialTheme.colorScheme.onSurface,
            titleColor = MaterialTheme.colorScheme.onSurface
        ),
    contentPadding = CardDefaults.ImageContentPadding,
    modifier = Modifier.semantics { contentDescription = "Background image" }
) {
    Text("Card content")
}

Example of a TitleCard with time, title and subtitle:

import androidx.wear.compose.material3.Card
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.TitleCard

TitleCard(
    onClick = { /* Do something */ },
    time = { Text("Now") },
    title = { Text("Title card") },
    subtitle = { Text("Subtitle") }
)

Example of a TitleCard with images content:

import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.dp
import androidx.wear.compose.material3.Card
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.TitleCard

TitleCard(
    onClick = { /* Do something */ },
    title = { Text("Title card") },
    time = { Text("Now") },
    modifier = Modifier.semantics { contentDescription = "Background image" }
) {
    Spacer(Modifier.height(4.dp))
    Row(modifier = Modifier.fillMaxWidth()) {
        Image(
            modifier =
                Modifier.weight(2f)
                    .height(68.dp)
                    .align(Alignment.CenterVertically)
                    .clip(RoundedCornerShape(16.dp)),
            painter = painterResource(id = R.drawable.card_content_image),
            contentScale = ContentScale.Crop,
            contentDescription = null
        )
        Spacer(Modifier.width(4.dp))
        Image(
            modifier =
                Modifier.weight(1f)
                    .height(68.dp)
                    .align(Alignment.CenterVertically)
                    .clip(RoundedCornerShape(16.dp)),
            painter = painterResource(id = R.drawable.card_content_image),
            contentScale = ContentScale.Crop,
            contentDescription = null
        )
    }
}

Example of an outlined TitleCard:

import androidx.wear.compose.material3.Card
import androidx.wear.compose.material3.CardDefaults
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.TitleCard

TitleCard(
    onClick = { /* Do something */ },
    title = { Text("Title card") },
    time = { Text("Now") },
    colors = CardDefaults.outlinedCardColors(),
    border = CardDefaults.outlinedCardBorder(),
) {
    Text("Card content")
}

For more information, see the Cards guide.

Parameters
onClick: () -> Unit

Will be called when the user clicks the card

title: @Composable RowScope.() -> Unit

A slot for displaying the title of the card, expected to be one or two lines of text.

modifier: Modifier = Modifier

Modifier to be applied to the card

onLongClick: (() -> Unit)? = null

Called when this card is long clicked (long-pressed). When this callback is set, onLongClickLabel should be set as well.

onLongClickLabel: String? = null

Semantic / accessibility label for the onLongClick action.

time: (@Composable () -> Unit)? = null

An optional slot for displaying the time relevant to the contents of the card, expected to be a short piece of text. Depending on whether we have a content or not, can be placed at the end of the title line or above it.

subtitle: (@Composable ColumnScope.() -> Unit)? = null

An optional slot for displaying the subtitle of the card, expected to be one line of text.

enabled: Boolean = true

Controls the enabled state of the card. When false, this card will not be clickable and there will be no ripple effect on click. Wear cards do not have any specific elevation or alpha differences when not enabled - they are simply not clickable.

shape: Shape = CardDefaults.shape

Defines the card's shape. It is strongly recommended to use the default as this shape is a key characteristic of the Wear Material Theme

colors: CardColors = CardDefaults.cardColors()

CardColors that will be used to resolve the colors used for this card in different states. See CardDefaults.cardColors.

border: BorderStroke? = null

A BorderStroke object which is used for drawing outlines.

contentPadding: PaddingValues = CardDefaults.ContentPadding

The spacing values to apply internally between the container and the content

interactionSource: MutableInteractionSource? = null

an optional hoisted MutableInteractionSource for observing and emitting Interactions for this card. You can use this to change the card's appearance or preview the card in different states. Note that if null is provided, interactions will still happen internally.

content: (@Composable () -> Unit)? = null

The optional body content of the card. If not provided then title and subtitle are expected to be provided

VerticalPageIndicator

@Composable
fun VerticalPageIndicator(
    pagerState: PagerState,
    modifier: Modifier = Modifier,
    selectedColor: Color = PageIndicatorDefaults.selectedColor,
    unselectedColor: Color = PageIndicatorDefaults.unselectedColor,
    backgroundColor: Color = PageIndicatorDefaults.backgroundColor
): Unit

Vertical page indicator for use with VerticalPager, representing the currently active page and the approximate number of pages. Pages are indicated as a Circle shape. The indicator shows up to six pages individually - if there are more than six pages, VerticalPageIndicator shows a smaller indicator to the top and/or bottom to indicate that more pages are available.

This is a full screen component and will occupy the whole screen. However it's not actionable, so it's not expected to interfere with anything on the screen.

VerticalPageIndicator can be linear or curved, depending on the screen shape of the device - for circular screens it will be curved, whilst for square screens it will be linear.

Example usage with VerticalPager:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.foundation.pager.rememberPagerState
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.VerticalPageIndicator
import androidx.wear.compose.material3.VerticalPagerScaffold

val pageCount = 9
val pagerState = rememberPagerState { pageCount }

Box {
    VerticalPagerScaffold(
        pagerState = pagerState,
        pageIndicator = { VerticalPageIndicator(pagerState = pagerState) }
    ) { page ->
        Box(modifier = Modifier.fillMaxSize()) {
            Text(modifier = Modifier.align(Alignment.Center), text = "Page #$page")
        }
    }
}
Parameters
pagerState: PagerState

State of the VerticalPager used to control this indicator

modifier: Modifier = Modifier

Modifier to be applied to the VerticalPageIndicator

selectedColor: Color = PageIndicatorDefaults.selectedColor

The color which will be used for a selected indicator item.

unselectedColor: Color = PageIndicatorDefaults.unselectedColor

The color which will be used for an unselected indicator item.

backgroundColor: Color = PageIndicatorDefaults.backgroundColor

The color which will be used for an indicator background.

VerticalPagerScaffold

@Composable
fun VerticalPagerScaffold(
    pagerState: PagerState,
    modifier: Modifier = Modifier,
    pageIndicator: (@Composable BoxScope.() -> Unit)? = { VerticalPageIndicator(pagerState) },
    pageIndicatorAnimationSpec: AnimationSpec<Float>? = null,
    rotaryScrollableBehavior: RotaryScrollableBehavior? = RotaryScrollableDefaults.snapBehavior(pagerState),
    content: @Composable PagerScope.(page: Int) -> Unit
): Unit

VerticalPagerScaffold is one of the Wear Material3 scaffold components.

The scaffold components AppScaffold and VerticalPagerScaffold lay out the structure of a Pager and coordinate transitions of the VerticalPageIndicator and TimeText components.

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

VerticalPagerScaffold supports rotary input by default. Rotary input allows users to scroll through the pager's content - by using a crown or a rotating bezel on their Wear OS device. It can be modified or turned off using the rotaryScrollableBehavior parameter.

Example of using AppScaffold and VerticalPagerScaffold:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.foundation.pager.rememberPagerState
import androidx.wear.compose.material3.AppScaffold
import androidx.wear.compose.material3.ScreenScaffold
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.VerticalPagerScaffold

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

    VerticalPagerScaffold(pagerState = pagerState) { page ->
        ScreenScaffold {
            Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
                Text("Page $page")
            }
        }
    }
}
Parameters
pagerState: PagerState

The state of the pager controlling the page content.

modifier: Modifier = Modifier

The modifier to be applied to the scaffold.

pageIndicator: (@Composable BoxScope.() -> Unit)? = { VerticalPageIndicator(pagerState) }

A composable function that defines the page indicator to be displayed. By default, it uses a VerticalPageIndicator.

pageIndicatorAnimationSpec: AnimationSpec<Float>? = null
  • An optional parameter to set whether the page indicator should fade out when paging has finished. This is useful for when the underlying page content conflicts with the page indicator. By default this is null, so the page indicator will be visible at all times, setting this to PagerScaffoldDefaults.FadeOutAnimation ensures the indicator only shows during paging, and fades out when the Pager is idle.

rotaryScrollableBehavior: RotaryScrollableBehavior? = RotaryScrollableDefaults.snapBehavior(pagerState)

Parameter for changing rotary behavior. We recommend to use RotaryScrollableDefaults.snapBehavior with pagerState parameter. Passing null turns off the rotary handling if it is not required.

content: @Composable PagerScope.(page: Int) -> Unit

A composable function that takes the current page index as a parameter and defines the content to be displayed on that page.

@Composable
fun contentColorFor(backgroundColor: Color): Color

The Material color system contains pairs of colors that are typically used for the background and content color inside a component. For example, a Button typically uses primary for its background, and onPrimary for the color of its content (usually text or iconography).

This function tries to match the provided backgroundColor to a 'background' color in this ColorScheme, and then will return the corresponding color used for content. For example, when backgroundColor is ColorScheme.primary, this will return ColorScheme.onPrimary.

If backgroundColor does not match a background color in the theme, this will return the current value of LocalContentColor as a best-effort color.

Returns
Color

the matching content color for backgroundColor. If backgroundColor is not present in the theme's ColorScheme, then returns the current value of LocalContentColor.

See also
contentColorFor

dynamicColorScheme

fun dynamicColorScheme(context: Context): ColorScheme?

Creates a dynamic color scheme.

Use this function to create a color scheme based on the current watchface. If the user changes the watchface colors, this color scheme will change accordingly. This function checks whether the dynamic color scheme can be used and returns null otherwise. It is expected that callers will check the return value and fallback to their own default color scheme if it is null.

Parameters
context: Context

The context required to get system resource data.

rememberAnimatedTextFontRegistry

@Composable
@RequiresApi(value = 31)
fun rememberAnimatedTextFontRegistry(
    startFontVariationSettings: FontVariation.Settings,
    endFontVariationSettings: FontVariation.Settings,
    textStyle: TextStyle = LocalTextStyle.current,
    startFontSize: TextUnit = textStyle.fontSize,
    endFontSize: TextUnit = textStyle.fontSize
): AnimatedTextFontRegistry

Generates an AnimatedTextFontRegistry to use within composition.

Start and end of the animation is when the animatable is at 0f and 1f, respectively. This API supports overshooting, so a generated font can be extrapolated outside startFontVariationSettings and endFontVariationSettings range, developers need to make sure the given font supports possible font variation settings throughout the animation.

Parameters
startFontVariationSettings: FontVariation.Settings

Font variation settings at the start of the animation

endFontVariationSettings: FontVariation.Settings

Font variation settings at the end of the animation

textStyle: TextStyle = LocalTextStyle.current

Text style to be used for the animation

startFontSize: TextUnit = textStyle.fontSize

Font size at the start of the animation

endFontSize: TextUnit = textStyle.fontSize

Font size at the end of the animation

rememberPickerState

@Composable
fun rememberPickerState(
    initialNumberOfOptions: @IntRange(from = 1) Int,
    initiallySelectedIndex: @IntRange(from = 0) Int = 0,
    shouldRepeatOptions: Boolean = true
): PickerState

Creates a PickerState that is remembered across compositions.

Parameters
initialNumberOfOptions: @IntRange(from = 1) Int

the number of options.

initiallySelectedIndex: @IntRange(from = 0) Int = 0

the index of the option to show in the center at the start, zero-based.

shouldRepeatOptions: Boolean = true

if true (the default), the options will be repeated.

rememberPlaceholderState

@Composable
fun rememberPlaceholderState(isContentReady: () -> Boolean): PlaceholderState

Creates a PlaceholderState that is remembered across compositions. To animate the placeholder depending on the state, run PlaceholderState.animatePlaceholder.

A PlaceholderState should be created for each component that has placeholder data. The state is used to coordinate all of the different placeholder effects and animations.

Placeholder has a number of different effects designed to work together. Modifier.placeholder draws a placeholder shape on top of content that is waiting to load. There can be multiple placeholders in a component. Modifier.placeholderShimmer does a shimmer animation over the whole component that includes the placeholders. There should only be one placeholderShimmer for each component.

Background placeholder effects are used to mask the background of components like buttons and cards until all of the data has loaded. Use PlaceholderDefaults.placeholderButtonColors and PlaceholderDefaults.painterWithPlaceholderOverlayBackgroundBrush to draw the component background.

Once all of the components content is loaded, isContentReady is true the shimmer will stop and a wipe off animation will remove the placeholders to reveal the content.

Parameters
isContentReady: () -> Boolean

a lambda to determine whether all of the data/content has been loaded for a given component and is ready to be displayed.

@Composable
fun rememberRevealState(
    initialValue: RevealValue = RevealValue.Covered,
    anchorWidth: Dp = SwipeToRevealDefaults.SingleActionAnchorWidth,
    useAnchoredActions: Boolean = true,
    swipeDirection: SwipeDirection = SwipeDirection.RightToLeft
): RevealState

Creates a reveal state with Material3 specs.

Parameters
initialValue: RevealValue = RevealValue.Covered

The initial value of the RevealValue for the SwipeToReveal composable.

anchorWidth: Dp = SwipeToRevealDefaults.SingleActionAnchorWidth

Fraction of the screen revealed items should be displayed in. Ignored if useAnchoredActions is set to false, as the items won't be anchored to the screen. For a single action SwipeToReveal component, this should be SwipeToRevealDefaults.SingleActionAnchorWidth, and for a double action SwipeToReveal, SwipeToRevealDefaults.DoubleActionAnchorWidth to be able to display both action buttons.

useAnchoredActions: Boolean = true

Whether the actions should stay revealed, or bounce back to hidden when the user stops swiping. This is relevant for SwipeToReveal components with a single action. If the developer wants a swipe to clear behaviour, this should be set to false.

swipeDirection: SwipeDirection = SwipeDirection.RightToLeft

Direction of the swipe to reveal the actions.

fun ripple(
    bounded: Boolean = true,
    radius: Dp = Dp.Unspecified,
    color: Color = Color.Unspecified
): IndicationNodeFactory

Creates a Ripple using the provided values and values inferred from the theme.

A Ripple is a Material implementation of Indication that expresses different Interactions by drawing ripple animations and state layers.

A Ripple responds to PressInteraction.Press by starting a new ripple animation, and responds to other Interactions by showing a fixed state layer with varying alpha values depending on the Interaction.

MaterialTheme provides Ripples using androidx.compose.foundation.LocalIndication, so a Ripple will be used as the default Indication inside components such as androidx.compose.foundation.clickable and androidx.compose.foundation.indication, in addition to Material provided components that use a Ripple as well.

You can also explicitly create a Ripple and provide it to custom components in order to change the parameters from the default, such as to create an unbounded ripple with a fixed size.

To create a Ripple with a manually defined color that can change over time, see the other ripple overload with a ColorProducer parameter. This will avoid unnecessary recompositions when changing the color, and preserve existing ripple state when the color changes.

Parameters
bounded: Boolean = true

If true, ripples are clipped by the bounds of the target layout. Unbounded ripples always animate from the target layout center, bounded ripples animate from the touch position.

radius: Dp = Dp.Unspecified

the radius for the ripple. If Dp.Unspecified is provided then the size will be calculated based on the target layout size.

color: Color = Color.Unspecified

the color of the ripple. This color is usually the same color used by the text or iconography in the component. This color will then have alpha applied to calculate the final color used to draw the ripple. If Color.Unspecified is provided the color used will be LocalContentColor instead.

fun ripple(
    color: ColorProducer,
    bounded: Boolean = true,
    radius: Dp = Dp.Unspecified
): IndicationNodeFactory

Creates a Ripple using the provided values and values inferred from the theme.

A Ripple is a Material implementation of Indication that expresses different Interactions by drawing ripple animations and state layers.

A Ripple responds to PressInteraction.Press by starting a new ripple animation, and responds to other Interactions by showing a fixed state layer with varying alpha values depending on the Interaction.

MaterialTheme provides Ripples using androidx.compose.foundation.LocalIndication, so a Ripple will be used as the default Indication inside components such as androidx.compose.foundation.clickable and androidx.compose.foundation.indication, in addition to Material provided components that use a Ripple as well.

You can also explicitly create a Ripple and provide it to custom components in order to change the parameters from the default, such as to create an unbounded ripple with a fixed size.

To create a Ripple with a static color, see the ripple overload with a Color parameter. This overload is optimized for Ripples that have dynamic colors that change over time, to reduce unnecessary recompositions.

Parameters
color: ColorProducer

the color of the ripple. This color is usually the same color used by the text or iconography in the component. This color will then have alpha applied to calculate the final color used to draw the ripple. If you are creating this ColorProducer outside of composition (where it will be automatically remembered), make sure that its instance is stable (such as by remembering the object that holds it), or remember the returned ripple object to make sure that ripple nodes are not being created each recomposition.

bounded: Boolean = true

If true, ripples are clipped by the bounds of the target layout. Unbounded ripples always animate from the target layout center, bounded ripples animate from the touch position.

radius: Dp = Dp.Unspecified

the radius for the ripple. If Dp.Unspecified is provided then the size will be calculated based on the target layout size.

Extension functions

fun ColorScheme.contentColorFor(backgroundColor: Color): Color

The Material color system contains pairs of colors that are typically used for the background and content color inside a component. For example, a Button typically uses primary for its background, and onPrimary for the color of its content (usually text or iconography).

This function tries to match the provided backgroundColor to a 'background' color in this ColorScheme, and then will return the corresponding color used for content. For example, when backgroundColor is ColorScheme.primary, this will return ColorScheme.onPrimary.

If backgroundColor does not match a background color in the theme, this will return Color.Unspecified.

Returns
Color

the matching content color for backgroundColor. If backgroundColor is not present in the theme's ColorScheme, then returns Color.Unspecified.

See also
contentColorFor
fun CurvedScope.curvedText(
    text: String,
    modifier: CurvedModifier = CurvedModifier,
    maxSweepAngle: Float = CurvedTextDefaults.ScrollableContentMaxSweepAngle,
    background: Color = Color.Unspecified,
    color: Color = Color.Unspecified,
    fontSize: TextUnit = TextUnit.Unspecified,
    fontFamily: FontFamily? = null,
    fontWeight: FontWeight? = null,
    fontStyle: FontStyle? = null,
    fontSynthesis: FontSynthesis? = null,
    style: CurvedTextStyle? = null,
    angularDirection: CurvedDirection.Angular? = null,
    overflow: TextOverflow = TextOverflow.Clip
): Unit

CurvedText is a component allowing developers to easily write curved text following the curvature a circle (usually at the edge of a circular screen). CurvedText can be only created within the CurvedLayout to ensure the best experience, like being able to specify to positioning.

Note that Wear Material UX guidance recommends that curvedText should not exceed the sweep angle CurvedTextDefaults.ScrollableContentMaxSweepAngle on screens with scrollable content such as lists. This limit is enforced by default. For screens without scrollable content, CurvedTextDefaults.StaticContentMaxSweepAngle may be used instead.

The default style uses the LocalTextStyle provided by the MaterialTheme / components, converting it to a CurvedTextStyle. Note that not all parameters are used by curvedText.

If you are setting your own style, you may want to consider first retrieving LocalTextStyle, and using TextStyle.copy to keep any theme defined attributes, only modifying the specific attributes you want to override, then convert to CurvedTextStyle

For ease of use, commonly used parameters from CurvedTextStyle are also present here. The order of precedence is as follows:

  • If a parameter is explicitly set here (i.e, it is not null or TextUnit.Unspecified), then this parameter will always be used.

  • If a parameter is not set, (null or TextUnit.Unspecified), then the corresponding value from style will be used instead.

Additionally, for color, if color is not set, and style does not have a color, then LocalContentColor will be used.

For samples using curved text in a CurvedLayout see:

import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.StrokeCap.Companion.Round
import androidx.compose.ui.unit.dp
import androidx.wear.compose.foundation.CurvedLayout
import androidx.wear.compose.foundation.CurvedModifier
import androidx.wear.compose.foundation.angularSizeDp
import androidx.wear.compose.foundation.background
import androidx.wear.compose.foundation.curvedBox
import androidx.wear.compose.foundation.curvedRow
import androidx.wear.compose.material3.MaterialTheme
import androidx.wear.compose.material3.curvedText

val backgroundColor = MaterialTheme.colorScheme.onPrimary
val customColor = MaterialTheme.colorScheme.tertiaryDim
CurvedLayout {
    curvedRow(CurvedModifier.background(backgroundColor, Round)) {
        curvedText("Calling", color = customColor)
        curvedBox(CurvedModifier.angularSizeDp(5.dp)) {}
        curvedText("Camilia Garcia")
    }
}
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Warning
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.StrokeCap.Companion.Round
import androidx.wear.compose.foundation.CurvedDirection
import androidx.wear.compose.foundation.CurvedLayout
import androidx.wear.compose.foundation.CurvedModifier
import androidx.wear.compose.foundation.background
import androidx.wear.compose.foundation.curvedComposable
import androidx.wear.compose.foundation.curvedRow
import androidx.wear.compose.material3.ButtonDefaults
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.MaterialTheme
import androidx.wear.compose.material3.curvedText

val backgroundColor = MaterialTheme.colorScheme.onPrimary
CurvedLayout(anchor = 90f, angularDirection = CurvedDirection.Angular.Reversed) {
    curvedRow(CurvedModifier.background(backgroundColor, Round)) {
        curvedComposable {
            Icon(
                Icons.Filled.Warning,
                contentDescription = "Warning",
                modifier = Modifier.size(ButtonDefaults.IconSize)
            )
        }
        curvedText("Error - network lost")
    }
}

For more information, see the Curved Text guide.

Parameters
text: String

The text to display

modifier: CurvedModifier = CurvedModifier

The CurvedModifier to apply to this curved text.

maxSweepAngle: Float = CurvedTextDefaults.ScrollableContentMaxSweepAngle

The default maximum sweep angle in degrees. For screens without scrollable content, CurvedTextDefaults.StaticContentMaxSweepAngle may be used instead.

background: Color = Color.Unspecified

The background color for the text.

color: Color = Color.Unspecified

Color to apply to the text. If Color.Unspecified, and style has no color set, this will be LocalContentColor.

fontSize: TextUnit = TextUnit.Unspecified

The size of glyphs to use when painting the text. See TextStyle.fontSize.

fontFamily: FontFamily? = null

The font family to be used when rendering the text.

fontWeight: FontWeight? = null

The thickness of the glyphs, in a range of 1, 1000. see FontWeight

fontStyle: FontStyle? = null

The typeface variant to use when drawing the letters (e.g. italic).

fontSynthesis: FontSynthesis? = null

Whether to synthesize font weight and/or style when the requested weight or style cannot be found in the provided font family.

style: CurvedTextStyle? = null

Specifies the style to use.

angularDirection: CurvedDirection.Angular? = null

Specify if the text is laid out clockwise or anti-clockwise, and if those needs to be reversed in a Rtl layout. If not specified, it will be inherited from the enclosing curvedRow or CurvedLayout See CurvedDirection.Angular.

overflow: TextOverflow = TextOverflow.Clip

How visual overflow should be handled.

minimumInteractiveComponentSize

fun Modifier.minimumInteractiveComponentSize(): Modifier

Reserves at least 48.dp in size to disambiguate touch interactions if the element would measure smaller.

https://m3.material.io/foundations/accessible-design/accessibility-basics#28032e45-c598-450c-b355-f9fe737b1cd8

This uses the Material recommended minimum size of 48.dp x 48.dp, which may not the same as the system enforced minimum size.

This modifier is not needed for touch target expansion to happen. It only affects layout, to make sure there is adequate space for touch target expansion.

@Composable
fun Modifier.placeholder(
    placeholderState: PlaceholderState,
    shape: Shape = PlaceholderDefaults.Shape,
    color: Color = MaterialTheme.colorScheme.onSurface .copy(alpha = 0.1f) .compositeOver(MaterialTheme.colorScheme.surfaceContainer)
): Modifier

Draws a placeholder shape over the top of a composable and animates a wipe off effect to remove the placeholder. Typically used whilst content is 'loading' and then 'revealed'.

Example of a Button with icon and a label that put placeholders over individual content slots:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.style.TextOverflow
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.ButtonDefaults
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.PlaceholderDefaults
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.placeholder
import androidx.wear.compose.material3.placeholderShimmer
import androidx.wear.compose.material3.rememberPlaceholderState

var labelText by remember { mutableStateOf("") }
var imageVector: ImageVector? by remember { mutableStateOf(null) }
val buttonPlaceholderState = rememberPlaceholderState {
    labelText.isNotEmpty() && imageVector != null
}

Button(
    onClick = { /* Do something */ },
    enabled = true,
    label = {
        Text(
            text = labelText,
            maxLines = 2,
            overflow = TextOverflow.Ellipsis,
            modifier = Modifier.fillMaxWidth().placeholder(buttonPlaceholderState)
        )
    },
    icon = {
        Box(
            modifier =
                Modifier.size(ButtonDefaults.IconSize).placeholder(buttonPlaceholderState)
        ) {
            if (imageVector != null) {
                Icon(
                    imageVector = imageVector!!,
                    contentDescription = "Heart",
                    modifier =
                        Modifier.wrapContentSize(align = Alignment.Center)
                            .size(ButtonDefaults.IconSize)
                            .fillMaxSize(),
                )
            }
        }
    },
    colors =
        PlaceholderDefaults.placeholderButtonColors(
            originalButtonColors = ButtonDefaults.buttonColors(),
            placeholderState = buttonPlaceholderState
        ),
    modifier = Modifier.fillMaxWidth().placeholderShimmer(buttonPlaceholderState)
)
// Simulate content loading completing in stages
LaunchedEffect(Unit) {
    delay(2000)
    imageVector = Icons.Filled.Favorite
    delay(1000)
    labelText = "A label"
}
if (!buttonPlaceholderState.isHidden) {
    LaunchedEffect(buttonPlaceholderState) { buttonPlaceholderState.animatePlaceholder() }
}

Example of a Button with icon and a primary and secondary labels that draws another Button over the top of it when waiting for placeholder data to load:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.ButtonDefaults
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.PlaceholderDefaults
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.placeholder
import androidx.wear.compose.material3.placeholderShimmer
import androidx.wear.compose.material3.rememberPlaceholderState

var labelText by remember { mutableStateOf("") }
var secondaryLabelText by remember { mutableStateOf("") }
var imageVector: ImageVector? by remember { mutableStateOf(null) }

val buttonPlaceholderState = rememberPlaceholderState {
    labelText.isNotEmpty() && secondaryLabelText.isNotEmpty() && imageVector != null
}
Box {
    if (buttonPlaceholderState.isHidden || buttonPlaceholderState.isWipingOff) {
        Button(
            onClick = { /* Do something */ },
            enabled = true,
            label = {
                Text(
                    text = labelText,
                    maxLines = 1,
                    overflow = TextOverflow.Ellipsis,
                    modifier = Modifier.fillMaxWidth()
                )
            },
            secondaryLabel = {
                Text(
                    text = secondaryLabelText,
                    maxLines = 1,
                    overflow = TextOverflow.Ellipsis,
                    modifier = Modifier.fillMaxWidth()
                )
            },
            icon = {
                if (imageVector != null) {
                    Icon(
                        imageVector = imageVector!!,
                        contentDescription = "Heart",
                        modifier =
                            Modifier.wrapContentSize(align = Alignment.Center)
                                .size(ButtonDefaults.IconSize)
                                .fillMaxSize(),
                    )
                }
            },
            colors = ButtonDefaults.filledTonalButtonColors(),
            modifier = Modifier.fillMaxWidth()
        )
    }
    if (!buttonPlaceholderState.isHidden) {
        Button(
            onClick = { /* Do something */ },
            enabled = true,
            label = {
                Box(
                    modifier =
                        Modifier.fillMaxWidth()
                            .height(16.dp)
                            .padding(top = 1.dp, bottom = 1.dp)
                            .placeholder(placeholderState = buttonPlaceholderState)
                )
            },
            secondaryLabel = {
                Box(
                    modifier =
                        Modifier.fillMaxWidth()
                            .height(16.dp)
                            .padding(top = 1.dp, bottom = 1.dp)
                            .placeholder(placeholderState = buttonPlaceholderState)
                )
            },
            icon = {
                Box(
                    modifier =
                        Modifier.size(ButtonDefaults.IconSize)
                            .placeholder(buttonPlaceholderState)
                )
                // Simulate the icon becoming ready after a period of time
                LaunchedEffect(Unit) {
                    delay(2000)
                    imageVector = Icons.Filled.Favorite
                }
            },
            colors =
                PlaceholderDefaults.placeholderButtonColors(
                    placeholderState = buttonPlaceholderState
                ),
            modifier = Modifier.fillMaxWidth().placeholderShimmer(buttonPlaceholderState)
        )
    }
}
// Simulate data being loaded after a delay
LaunchedEffect(Unit) {
    delay(2500)
    secondaryLabelText = "A secondary label"
    delay(500)
    labelText = "A label"
}
if (!buttonPlaceholderState.isHidden) {
    LaunchedEffect(buttonPlaceholderState) { buttonPlaceholderState.animatePlaceholder() }
}

The placeholderState determines when to 'show' and 'wipe off' the placeholder.

NOTE: The order of modifiers is important. If you are adding both Modifier.placeholder and Modifier.placeholderShimmer to the same composable then the shimmer must be first in the modifier chain. Example of Text composable with both placeholderShimmer and placeholder modifiers.

import androidx.compose.foundation.layout.width
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.placeholder
import androidx.wear.compose.material3.placeholderShimmer
import androidx.wear.compose.material3.rememberPlaceholderState

var labelText by remember { mutableStateOf("") }
val buttonPlaceholderState = rememberPlaceholderState { labelText.isNotEmpty() }

Text(
    text = labelText,
    overflow = TextOverflow.Ellipsis,
    textAlign = TextAlign.Center,
    modifier =
        Modifier.width(90.dp)
            .placeholderShimmer(buttonPlaceholderState)
            .placeholder(buttonPlaceholderState)
)

// Simulate content loading
LaunchedEffect(Unit) {
    delay(3000)
    labelText = "A label"
}
if (!buttonPlaceholderState.isHidden) {
    LaunchedEffect(buttonPlaceholderState) { buttonPlaceholderState.animatePlaceholder() }
}
Parameters
placeholderState: PlaceholderState

determines whether the placeholder is visible and controls animation effects for the placeholder.

shape: Shape = PlaceholderDefaults.Shape

the shape to apply to the placeholder

color: Color = MaterialTheme.colorScheme.onSurface .copy(alpha = 0.1f) .compositeOver(MaterialTheme.colorScheme.surfaceContainer)

the color of the placeholder.

@Composable
fun Modifier.placeholderShimmer(
    placeholderState: PlaceholderState,
    shape: Shape = PlaceholderDefaults.Shape,
    color: Color = MaterialTheme.colorScheme.onSurface
): Modifier

Modifier to draw a placeholder shimmer over a component. The placeholder shimmer is a 45 degree gradient from Top|Left of the screen to Bottom|Right. The shimmer is coordinated via the animation frame clock which orchestrates the shimmer so that every component will shimmer as the gradient progresses across the screen.

Example of a Button with icon and a label that put placeholders over individual content slots and then draws a placeholder shimmer over the result:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.style.TextOverflow
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.ButtonDefaults
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.PlaceholderDefaults
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.placeholder
import androidx.wear.compose.material3.placeholderShimmer
import androidx.wear.compose.material3.rememberPlaceholderState

var labelText by remember { mutableStateOf("") }
var imageVector: ImageVector? by remember { mutableStateOf(null) }
val buttonPlaceholderState = rememberPlaceholderState {
    labelText.isNotEmpty() && imageVector != null
}

Button(
    onClick = { /* Do something */ },
    enabled = true,
    label = {
        Text(
            text = labelText,
            maxLines = 2,
            overflow = TextOverflow.Ellipsis,
            modifier = Modifier.fillMaxWidth().placeholder(buttonPlaceholderState)
        )
    },
    icon = {
        Box(
            modifier =
                Modifier.size(ButtonDefaults.IconSize).placeholder(buttonPlaceholderState)
        ) {
            if (imageVector != null) {
                Icon(
                    imageVector = imageVector!!,
                    contentDescription = "Heart",
                    modifier =
                        Modifier.wrapContentSize(align = Alignment.Center)
                            .size(ButtonDefaults.IconSize)
                            .fillMaxSize(),
                )
            }
        }
    },
    colors =
        PlaceholderDefaults.placeholderButtonColors(
            originalButtonColors = ButtonDefaults.buttonColors(),
            placeholderState = buttonPlaceholderState
        ),
    modifier = Modifier.fillMaxWidth().placeholderShimmer(buttonPlaceholderState)
)
// Simulate content loading completing in stages
LaunchedEffect(Unit) {
    delay(2000)
    imageVector = Icons.Filled.Favorite
    delay(1000)
    labelText = "A label"
}
if (!buttonPlaceholderState.isHidden) {
    LaunchedEffect(buttonPlaceholderState) { buttonPlaceholderState.animatePlaceholder() }
}

Example of a Button with icon and a primary and secondary labels that draws another Button over the top of it when waiting for placeholder data to load and then draws a placeholder shimmer over the top:

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.wear.compose.material3.Button
import androidx.wear.compose.material3.ButtonDefaults
import androidx.wear.compose.material3.Icon
import androidx.wear.compose.material3.PlaceholderDefaults
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.placeholder
import androidx.wear.compose.material3.placeholderShimmer
import androidx.wear.compose.material3.rememberPlaceholderState

var labelText by remember { mutableStateOf("") }
var secondaryLabelText by remember { mutableStateOf("") }
var imageVector: ImageVector? by remember { mutableStateOf(null) }

val buttonPlaceholderState = rememberPlaceholderState {
    labelText.isNotEmpty() && secondaryLabelText.isNotEmpty() && imageVector != null
}
Box {
    if (buttonPlaceholderState.isHidden || buttonPlaceholderState.isWipingOff) {
        Button(
            onClick = { /* Do something */ },
            enabled = true,
            label = {
                Text(
                    text = labelText,
                    maxLines = 1,
                    overflow = TextOverflow.Ellipsis,
                    modifier = Modifier.fillMaxWidth()
                )
            },
            secondaryLabel = {
                Text(
                    text = secondaryLabelText,
                    maxLines = 1,
                    overflow = TextOverflow.Ellipsis,
                    modifier = Modifier.fillMaxWidth()
                )
            },
            icon = {
                if (imageVector != null) {
                    Icon(
                        imageVector = imageVector!!,
                        contentDescription = "Heart",
                        modifier =
                            Modifier.wrapContentSize(align = Alignment.Center)
                                .size(ButtonDefaults.IconSize)
                                .fillMaxSize(),
                    )
                }
            },
            colors = ButtonDefaults.filledTonalButtonColors(),
            modifier = Modifier.fillMaxWidth()
        )
    }
    if (!buttonPlaceholderState.isHidden) {
        Button(
            onClick = { /* Do something */ },
            enabled = true,
            label = {
                Box(
                    modifier =
                        Modifier.fillMaxWidth()
                            .height(16.dp)
                            .padding(top = 1.dp, bottom = 1.dp)
                            .placeholder(placeholderState = buttonPlaceholderState)
                )
            },
            secondaryLabel = {
                Box(
                    modifier =
                        Modifier.fillMaxWidth()
                            .height(16.dp)
                            .padding(top = 1.dp, bottom = 1.dp)
                            .placeholder(placeholderState = buttonPlaceholderState)
                )
            },
            icon = {
                Box(
                    modifier =
                        Modifier.size(ButtonDefaults.IconSize)
                            .placeholder(buttonPlaceholderState)
                )
                // Simulate the icon becoming ready after a period of time
                LaunchedEffect(Unit) {
                    delay(2000)
                    imageVector = Icons.Filled.Favorite
                }
            },
            colors =
                PlaceholderDefaults.placeholderButtonColors(
                    placeholderState = buttonPlaceholderState
                ),
            modifier = Modifier.fillMaxWidth().placeholderShimmer(buttonPlaceholderState)
        )
    }
}
// Simulate data being loaded after a delay
LaunchedEffect(Unit) {
    delay(2500)
    secondaryLabelText = "A secondary label"
    delay(500)
    labelText = "A label"
}
if (!buttonPlaceholderState.isHidden) {
    LaunchedEffect(buttonPlaceholderState) { buttonPlaceholderState.animatePlaceholder() }
}

NOTE: The order of modifiers is important. If you are adding both Modifier.placeholder and Modifier.placeholderShimmer to the same composable then the shimmer must be before in the modifier chain. Example of Text composable with both placeholderShimmer and placeholder modifiers.

import androidx.compose.foundation.layout.width
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.placeholder
import androidx.wear.compose.material3.placeholderShimmer
import androidx.wear.compose.material3.rememberPlaceholderState

var labelText by remember { mutableStateOf("") }
val buttonPlaceholderState = rememberPlaceholderState { labelText.isNotEmpty() }

Text(
    text = labelText,
    overflow = TextOverflow.Ellipsis,
    textAlign = TextAlign.Center,
    modifier =
        Modifier.width(90.dp)
            .placeholderShimmer(buttonPlaceholderState)
            .placeholder(buttonPlaceholderState)
)

// Simulate content loading
LaunchedEffect(Unit) {
    delay(3000)
    labelText = "A label"
}
if (!buttonPlaceholderState.isHidden) {
    LaunchedEffect(buttonPlaceholderState) { buttonPlaceholderState.animatePlaceholder() }
}
Parameters
placeholderState: PlaceholderState

the current placeholder state that determine whether the placeholder shimmer should be shown.

shape: Shape = PlaceholderDefaults.Shape

the shape of the component.

color: Color = MaterialTheme.colorScheme.onSurface

the color to use in the shimmer.

fun Modifier.rangeSemantics(
    value: Float,
    enabled: Boolean,
    onValueChange: (Float) -> Unit,
    valueRange: ClosedFloatingPointRange<Float>,
    steps: Int
): Modifier

Modifier to add semantics signifying progress of the Stepper/Slider.

Parameters
value: Float

Current value of the ProgressIndicator/Slider. If outside of valueRange provided, value will be coerced to this range. Must not be NaN.

enabled: Boolean

If false then semantics will not be added.

onValueChange: (Float) -> Unit

Lambda which updates value.

valueRange: ClosedFloatingPointRange<Float>

Range of values that value can take. Passed value will be coerced to this range.

steps: Int

If greater than 0, specifies the amounts of discrete values, evenly distributed between across the whole value range. If 0, any value from the range specified is allowed. Must not be negative.

fun Modifier.scrollAway(
    scrollInfoProvider: ScrollInfoProvider,
    screenStage: () -> ScreenStage
): Modifier

Scroll an item vertically in/out of view based on scroll state provided by a scrolling list. Typically used to scroll a TimeText item out of view as the user starts to scroll a vertically scrollable list of items upwards and bring additional items into view.

Example of using ScrollAway directly (in practice, it is recommended to use AppScaffold and ScreenScaffold to provide the correct scroll away behavior by default):

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.wear.compose.foundation.ScrollInfoProvider
import androidx.wear.compose.foundation.lazy.AutoCenteringParams
import androidx.wear.compose.foundation.lazy.ScalingLazyColumn
import androidx.wear.compose.foundation.lazy.rememberScalingLazyListState
import androidx.wear.compose.material3.FilledTonalButton
import androidx.wear.compose.material3.ListHeader
import androidx.wear.compose.material3.ScreenStage
import androidx.wear.compose.material3.Text
import androidx.wear.compose.material3.TimeText
import androidx.wear.compose.material3.scrollAway

val state = rememberScalingLazyListState()

Box(modifier = Modifier.fillMaxSize()) {
    ScalingLazyColumn(
        state = state,
        modifier = Modifier.fillMaxSize(),
        autoCentering = AutoCenteringParams(itemIndex = 10)
    ) {
        item {
            ListHeader {
                Text(
                    modifier = Modifier.fillMaxWidth(),
                    text = "ScalingLazyColumn",
                    textAlign = TextAlign.Center
                )
            }
        }
        items(50) {
            FilledTonalButton(
                modifier = Modifier.fillMaxWidth().padding(horizontal = 36.dp),
                onClick = {},
                label = { Text("Item ${it + 1}") },
            )
        }
    }
    TimeText(
        // In practice, it is recommended to use the [AppScaffold] and [ScreenScaffold],
        // so that the Material3 scroll away behavior is provided by default, rather than using
        // [Modifier.scrollAway] directly.
        modifier =
            Modifier.scrollAway(
                scrollInfoProvider = ScrollInfoProvider(state),
                screenStage = {
                    if (state.isScrollInProgress) ScreenStage.Scrolling else ScreenStage.Idle
                }
            ),
        content = {
            text("ScrollAway")
            separator()
            time()
        }
    )
}
Parameters
scrollInfoProvider: ScrollInfoProvider

Used as the basis for the scroll-away implementation, based on the state of the scrollable container. See ScrollInfoProvider methods for creating a ScrollInfoProvider from common lists such as ScalingLazyListState.

screenStage: () -> ScreenStage

Function that returns the screen stage of the active screen. Scrolled away items are shown when the screen is new, then scrolled away or hidden when scrolling, and finally shown again when idle.

touchTargetAwareSize

fun Modifier.touchTargetAwareSize(size: Dp): Modifier

Modifier to set both the size and recommended touch target for IconButton and TextButton.

Top-level properties

val LocalContentColorProvidableCompositionLocal<Color>

CompositionLocal containing the preferred content color for a given position in the hierarchy. This typically represents the on color for a color in ColorScheme. For example, if the background color is ColorScheme.surfaceContainer, this color is typically set to ColorScheme.onSurface.

This color should be used for any typography / iconography, to ensure that the color of these adjusts when the background color changes. For example, on a dark background, text should be light, and on a light background, text should be dark.

Defaults to Color.White if no color has been explicitly set.

LocalMinimumInteractiveComponentEnforcement

@ExperimentalWearMaterial3Api
val LocalMinimumInteractiveComponentEnforcementProvidableCompositionLocal<Boolean>

CompositionLocal that configures whether Wear Material components that have a visual size that is lower than the minimum touch target size for accessibility (such as Button) will include extra space outside the component to ensure that they are accessible. If set to false there will be no extra space, and so it is possible that if the component is placed near the edge of a layout / near to another component without any padding, there will not be enough space for an accessible touch target.

LocalTextConfiguration

val LocalTextConfigurationProvidableCompositionLocal<TextConfiguration>

CompositionLocal containing the preferred TextConfiguration that will be used by Text components by default consisting of text alignment, overflow specification and max lines. Material3 components related to text such as Button, CheckboxButton, SwitchButton, RadioButton use LocalTextConfiguration to set values with which to style child text components.

val LocalTextStyleProvidableCompositionLocal<TextStyle>

CompositionLocal containing the preferred TextStyle that will be used by Text components by default. To set the value for this CompositionLocal, see ProvideTextStyle which will merge any missing TextStyle properties with the existing TextStyle set in this CompositionLocal.

See also
ProvideTextStyle