Persistent Footer¶
The Persistent Footer is a footer that is designed to be placed at the bottom of its parent container. Like the navigation, bar it provides immediate actions to the user, however, the key difference is that the navigation bar is strictly used for navigation, whereas the footer supports other important actions (as well as navigation if needed).
The footer supports 1-3 actions on small screens and 1-4 actions on larger screens. The actions are described in order of significance: primary button, secondary button, tertiary button (on large screens only), helper text, and an overflow icon button.
Anatomy¶
Structurally, the primary button is constrained to be displayed at the end of the footer and is a filled button, by default, to establish emphasis over the rest of the actions.
There are three action modes that determine how the Persistent Footer should be laid out, with ActionMode.RelatedActions
being the default action mode.
ActionMode.RelatedActions
, which aligns the buttons at the end of the footerActionMode.OpposingActions
, which aligns the buttons on opposite ends of the footerActionMode.SingleActionFillMaxWidth
, which displays a single button that expands to the width of the footer
The following is an example of a Persistent Footer set with ActionMode.SingleActionFillMaxWidth
, which supports one action that fills the entire width of the footer.
Usage¶
The Persistent Footer and its variations can be implemented with a single API. Note that all parameters are optional with the button actions being any type of Composable
. Theoretically, any Composable
can be passed into the Persistent Footer, but buttons are strictly recommended by design:
@Composable
fun PersistentFooter(
modifier: Modifier = Modifier,
primaryButton: (@Composable () -> Unit)? = null,
actionMode: ActionMode = ActionMode.RelatedActions,
secondaryButton: (@Composable () -> Unit)? = null,
tertiaryButton: (@Composable () -> Unit)? = null,
overflowMenuButton: (@Composable () -> Unit)? = null,
helperText: (@Composable () -> Unit)? = null,
divider: (@Composable () -> Unit)? = null,
elevation: Dp = 3.dp,
colors: PersistentFooterColors = PersistentFooterDefaults.colors(),
styles: PersistentFooterStyles = PersistentFooterDefaults.styles()
)
Persistent Footer with Related Actions¶
The Persistent Footer with ActionMode.RelatedActions
supports a primary button, secondary button, tertiary button (only on larger screens), and an overflow button. Developers can display all or none of the buttons. In this example, the FioriFilledButton
and FioriTonalButton
are being passed as the Composable
parameters. It is important to note that the overflow menu button must be provided by developers.
PersistentFooter(
primaryButton = {
FioriFilledButton(
buttonContent = FioriButtonContent(
title = primaryButtonText
),
onClick = { }
)
},
secondaryButton = {
FioriTonalButton(
buttonContent = FioriButtonContent(title = secondaryButtonText),
onClick = { }
)
},
overflowMenuButton = {
//The overflow button must be supplied by the application
OverflowActionButton()
},
modifier = Modifier.windowInsetsPadding(WindowInsets.navigationBars),
)
Persistent Footer with related actions:
The following example shows an example of the primary, secondary, and tertiary button as icon buttons. On larger screens, the overflow button is aligned with the primary, secondary, and tertiary buttons.
PersistentFooter(
primaryButton = {
FioriStandardIconButton(onClick = { }) { modifier, tint ->
Icon(
painter = painterResource(id = R.drawable.ic_sap_icon_accept),
contentDescription = "icon button",
modifier = modifier,
tint = tint
)
}
},
actionMode = ActionMode.RelatedActions,
secondaryButton = {
FioriStandardIconButton(onClick = { }) { modifier, tint ->
Icon(
painter = painterResource(id = R.drawable.ic_sap_icon_decline),
contentDescription = "icon button",
modifier = modifier,
tint = tint
)
}
},
tertiaryButton = {
FioriStandardIconButton(onClick = { }) { modifier, tint ->
Icon(
painter = painterResource(id = R.drawable.ic_sap_icon_save),
contentDescription = "icon button",
modifier = modifier,
tint = tint
)
}
},
overflowMenuButton = {
OverflowActionButton()
},
modifier = Modifier.windowInsetsPadding(WindowInsets.navigationBars),
)
Icon buttons displayed on a larger screen with ActionMode.RelatedActions
:
Persistent Footer with Opposing Actions¶
The Persistent Footer with ActionMode.Opposing
supports a primary button, secondary button, and a helper text. Developers can display all or none of the components. The HelperText
Composable
is provided by the SDK and is the recommended Text
Composable
to use with the Persistent Footer:
@Composable
fun HelperText(
text: String,
modifier: Modifier = Modifier,
color: Color = PersistentFooterDefaults.colors().helperTextColor().value,
textStyle: TextStyle = PersistentFooterDefaults.textStyles().helperTextStyle().value
)
In this example, the FioriTextButton
and HelperText
are being passed as the Composable
parameters. The secondary button has a negative semantic applied to it:
PersistentFooter(
primaryButton = {
FioriTextButton(
buttonContent = FioriButtonContent(
title = primaryButtonText
),
onClick = { footerToSet = 28 }
)
},
actionMode = ActionMode.OpposingActions,
secondaryButton = {
FioriTextButton(
buttonContent = FioriButtonContent(
title = secondaryButtonText
),
onClick = { footerToSet = 0 },
semanticType = FioriButtonSemanticType.Negative
)
},
helperText = { HelperText(text = "Helper Text") },
modifier = Modifier.windowInsetsPadding(WindowInsets.navigationBars)
)
Persistent Footer with opposing actions and a helper text:
Persistent Footer with Single Action¶
The Persistent Footer with ActionMode.SingleActionFillMaxWidth
supports only the primary button and fills the entire width of the footer. Note that the Modifier
parameter is mandatory for the footer to display correctly:
PersistentFooter(
primaryButton = {
FioriFilledButton(
modifier = Modifier.fillMaxWidth(),
buttonContent = FioriButtonContent(
title = primaryButtonText,
icon = acceptIcon,
displayIconAtStart = true
),
onClick = { }
)
},
actionMode = ActionMode.SingleActionFillMaxWidth,
modifier = Modifier.windowInsetsPadding(WindowInsets.navigationBars)
)
Persistent Footer with a single action that fills the width of the footer: