Icon Button
A button that shows only an icon: square, as tall as a size button, round by default, with the platform's minimum touch target around it. variant picks its colours; ButtonVariant.Text, the default, has no container, disabled or not. contentDescription names the action for screen readers, "Close" rather than "X".
import com.pantrixui.components.elements.iconbutton.PantrixIconButton
- Six variants.
variantpicks the button's colours: they arePantrixButton's variants. The default isButtonVariant.Text: it has no surface, and is for the actions in a toolbar. - Five sizes.
sizepicks the button's side and its icon's size together: the button from 24dp to 56dp, its icon from 16dp to 32dp. - Shape. It is fully round on every platform;
shapegives it one of the theme's shapes, or anyShape. - Description.
contentDescriptionis the name a screen reader reads, and it names the action, not the icon: "Close", not "cross". - A button without a description. Null is given only to a button that repeats what something a screen reader and the keyboard already reach does. Such a button is hidden from the reader and is no stop for the keyboard; a mouse and a finger still press it.
- Its own content. There is a second
PantrixIconButtonthat takes content in place of an icon: an icon with a badge, an animated icon. A screen reader hears the description alone. - Colours. By default
colorsis the variant's colours in theprimaryrole, and forDestructivein thedangerrole;PantrixColor.buttonColors(variant)gives them in another role, andButtonColorsin a colour entirely its own. - Disabled.
enabled = falsedraws the button faded, and the button takes no press. A variant with no fill stays without one when disabled.
Examples
At its plainest
The least it takes: an icon, a description that says what it does, and the action to run when it is pressed. Its variant is Text and its size Medium: a round button of 40dp with no fill.
Press the button: the line under it says how many times it was pressed. As it has no fill, the button's circle shows while it is pressed and while the keyboard focus is on it.
var refreshed by rememberSaveable { mutableIntStateOf(0) }
PantrixIconButton(
imageVector = PantrixIcons.Refresh,
contentDescription = "Refresh",
onClick = { refreshed += 1 },
tagKey = "refresh"
)
PantrixText(
text = "Times refreshed: $refreshed",
color = PantrixTheme.colors.textSecondary,
tagKey = "refreshed"
)
Variants
variant picks the button's colours; all six are PantrixButton's variants. Solid is the main action on a screen, Outline, Soft and Subtle are secondary actions, and Destructive says the action cannot be undone.
The default is Text: it has no surface, and only its icon is drawn. It is for the actions in a toolbar.
FlowRow(
horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm),
verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)
) {
ButtonVariant.entries.forEach { variant ->
PantrixIconButton(
imageVector = PantrixIcons.Star,
contentDescription = "Button in the ${variant.name} variant",
onClick = {},
variant = variant,
tagKey = "variant_${variant.name}"
)
}
}
Sizes
size picks one of five sizes: the button is a square of 24, 32, 40, 48 or 56 dp, and its icon is 16, 20, 24, 28 or 32 dp. The default is Medium. Beside a PantrixButton of the same size, the two are the same height.
The room around the small buttons is the touch target: a button is drawn small but takes up as much room as the platform's minimum touch target. That is 48dp on Android, 44dp on iOS, and 32dp on desktop and the web when they are used with a mouse.
FlowRow(
horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm),
verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm),
itemVerticalAlignment = Alignment.CenterVertically
) {
ButtonSize.entries.forEach { size ->
PantrixIconButton(
imageVector = PantrixIcons.Plus,
contentDescription = "Button in the ${size.name} size",
onClick = {},
variant = ButtonVariant.Soft,
size = size,
tagKey = "size_${size.name}"
)
}
}
Shape and style
An icon button is fully round on every platform. shape changes that: the second button has the theme's medium roundness (shapes.md), and the third has square corners (shapes.none).
style changes the button's dimensions: an icon button reads only the sizes of ButtonStyle. The last button is still Medium, but its icon is drawn at 16dp instead of 24dp. Only the field that is set changes, and the rest comes from the theme's style.
Row(
horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm),
verticalAlignment = Alignment.CenterVertically
) {
PantrixIconButton(
imageVector = PantrixIcons.Folder,
contentDescription = "Fully round button",
onClick = {},
variant = ButtonVariant.Soft,
tagKey = "pill"
)
PantrixIconButton(
imageVector = PantrixIcons.Folder,
contentDescription = "Slightly round button",
onClick = {},
variant = ButtonVariant.Soft,
shape = PantrixTheme.shapes.md,
tagKey = "rounded"
)
PantrixIconButton(
imageVector = PantrixIcons.Folder,
contentDescription = "Square-cornered button",
onClick = {},
variant = ButtonVariant.Soft,
shape = PantrixTheme.shapes.none,
tagKey = "square"
)
PantrixIconButton(
imageVector = PantrixIcons.Folder,
contentDescription = "Button with a small icon",
onClick = {},
variant = ButtonVariant.Soft,
style = ButtonStyle(medium = ButtonSizeStyle(iconSize = 16.dp)),
tagKey = "small_icon"
)
}
Disabled
enabled = false draws the button faded, and the button takes no press. A variant with a fill takes the theme's disabled fill; Text and Outline, which have no fill, stay without one when disabled, and do not turn into a grey shape.
Row(horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)) {
listOf(ButtonVariant.Text, ButtonVariant.Outline, ButtonVariant.Soft, ButtonVariant.Solid).forEach { variant ->
PantrixIconButton(
imageVector = PantrixIcons.Calendar,
contentDescription = "Add to calendar",
onClick = {},
variant = variant,
enabled = false,
tagKey = "disabled_${variant.name}"
)
}
}
In another role and in a colour of its own
A variant's colours come from the theme's primary role, and Destructive's from the danger role. PantrixColor.buttonColors(variant) gives the same variant in another role: the first two buttons are in the success and danger roles.
The last button's colour is in none of the theme's roles: ButtonColors takes the fill and the icon's colour directly. The icon is given no colour of its own: it takes the button's content colour by itself.
val colors = PantrixTheme.colors
val own = ownColors()
Row(horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)) {
PantrixIconButton(
imageVector = PantrixIcons.Check,
contentDescription = "Approve",
onClick = {},
colors = colors.success.buttonColors(ButtonVariant.Soft),
tagKey = "approve"
)
PantrixIconButton(
imageVector = PantrixIcons.Close,
contentDescription = "Reject",
onClick = {},
colors = colors.danger.buttonColors(ButtonVariant.Outline),
tagKey = "reject"
)
PantrixIconButton(
imageVector = PantrixIcons.Star,
contentDescription = "Add to collection",
onClick = {},
colors = ButtonColors(container = own.color, content = own.onColor),
tagKey = "own_colors"
)
}
Its own content: an icon with a badge
The PantrixIconButton that takes content in place of an icon: here an icon with a badge at its corner. The content is drawn in the button's content colour.
What is in the button is a picture of what the description says: a screen reader hears the description alone. So the badge's count is written in the description, "Inbox, 3 unread"; the badge itself is not read. "New message" raises the count, and a press on the icon button resets it.
var unread by rememberSaveable { mutableIntStateOf(3) }
Row(
horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.md),
verticalAlignment = Alignment.CenterVertically
) {
PantrixIconButton(
contentDescription = if (unread > 0) "Inbox, $unread unread" else "Inbox",
onClick = { unread = 0 },
tagKey = "inbox"
) {
PantrixBadgedBox(badge = { if (unread > 0) PantrixBadge(count = unread) }) {
PantrixIcon(imageVector = PantrixIcons.Inbox, contentDescription = null)
}
}
PantrixButton(
text = "New message",
onClick = { unread += 1 },
variant = ButtonVariant.Outline,
size = ButtonSize.Small,
tagKey = "new_message"
)
}
A button without a description
contentDescription = null is given only to a button that repeats what something else already does. Here the whole card is pressed and opens the order; the arrow at its end does the same thing and is a sign for the eye alone.
Such a button is hidden from screen readers and is no stop for the keyboard: a stop on something the reader will never read is worse than no stop at all. A mouse and a finger still press it. A button that is the only way to its action always has a description.
var opened by rememberSaveable { mutableIntStateOf(0) }
PantrixCard(
modifier = Modifier.widthIn(max = 360.dp),
variant = CardVariant.Outlined,
onClick = { opened += 1 },
tagKey = "order"
) {
Row(verticalAlignment = Alignment.CenterVertically) {
Column(modifier = Modifier.weight(1f)) {
PantrixText(text = "Order 8F2A-19C4", style = PantrixTheme.typography.callout)
PantrixText(text = "Arrives tomorrow", color = PantrixTheme.colors.textSecondary)
}
PantrixIconButton(
imageVector = PantrixIcons.ChevronForward,
contentDescription = null,
onClick = { opened += 1 },
tagKey = "open_order"
)
}
}
PantrixText(
text = "Times the order was opened: $opened",
color = PantrixTheme.colors.textSecondary,
tagKey = "order_opened"
)
API
imageVector
A button that shows only an icon: square, as tall as a size button, round by default, with the platform's minimum touch target around it. variant picks its colours; ButtonVariant.Text, the default, has no container, disabled or not. contentDescription names the action for screen readers, "Close" rather than "X".
| Parameter | Type | Default | What it is |
|---|---|---|---|
imageVector | ImageVector | the icon the button shows. | |
contentDescription | String? | ||
onClick | () -> Unit | what a press does. | |
modifier | Modifier | Modifier | the button's modifier. |
variant | ButtonVariant | ButtonVariant.Text | |
size | ButtonSize | ButtonSize.Medium | |
enabled | Boolean | true | whether the button can be pressed: one that cannot is drawn in the disabled colours and does nothing. |
shape | Shape | PantrixTheme.shapes.full | the button's corners: fully round unless told. |
colors | ButtonColors | variant.colors() | this call's own colours, in place of variant's. |
tagKey | String? | null | the button's automation key: the button is IconButton_<tagKey>, and without one a key of where it is called. Visible text is never the key. |
interactionSource | MutableInteractionSource? | null | the button's interactions, hoisted: its focus, its hover and its presses. It keeps a source of its own when this is null. |
style | ButtonStyle? | null | this call's own style: over every enclosing one and under the density. Only the fields it sets change. |
contentDescription
PantrixIconButton with any content in place of an ImageVector: an animated icon, or one with a badge.
| Parameter | Type | Default | What it is |
|---|---|---|---|
contentDescription | String? | ||
onClick | () -> Unit | what a press does. | |
modifier | Modifier | Modifier | the button's modifier. |
variant | ButtonVariant | ButtonVariant.Text | the button's colours: ButtonVariant.Text, with no container, unless told. |
size | ButtonSize | ButtonSize.Medium | the button's size: as tall, and as wide, as a size button is tall. |
enabled | Boolean | true | whether the button can be pressed: one that cannot is drawn in the disabled colours and does nothing. |
shape | Shape | PantrixTheme.shapes.full | the button's corners: fully round unless told. |
colors | ButtonColors | variant.colors() | this call's own colours, in place of variant's. |
tagKey | String? | null | the button's automation key: the button is IconButton_<tagKey>, and without one a key of where it is called. Visible text is never the key. |
interactionSource | MutableInteractionSource? | null | the button's interactions, hoisted: its focus, its hover and its presses. It keeps a source of its own when this is null. |
style | ButtonStyle? | null | this call's own style: over every enclosing one and under the density. Only the fields it sets change. |
content | @Composable () -> Unit |
ButtonStyle
PantrixButton's geometry: its shape, its press feedback, and a height, padding and icon size for each ButtonSize. PantrixIconButton reads the sizes only.
| Parameter | Type | Default | What it is |
|---|---|---|---|
shape | ShapeSpec | ShapeSpec.Unspecified | The button's shape: ShapeRole.Full on Android, desktop and the web, ShapeRole.Medium on iOS. |
pressedScale | Float | Float.NaN | Scale while pressed. 1f means none: the state layer carries the feedback. |
extraSmall | ButtonSizeStyle | ButtonSizeStyle() | ButtonSize.ExtraSmall's geometry. |
small | ButtonSizeStyle | ButtonSizeStyle() | ButtonSize.Small's geometry. |
medium | ButtonSizeStyle | ButtonSizeStyle() | ButtonSize.Medium's geometry. |
large | ButtonSizeStyle | ButtonSizeStyle() | ButtonSize.Large's geometry. |
extraLarge | ButtonSizeStyle | ButtonSizeStyle() | ButtonSize.ExtraLarge's geometry. |
ButtonColors
What a button is painted with. ButtonVariant.colors gives a variant's in primary, and PantrixColor.buttonColors the same prominences in any role.
| Parameter | Type | Default | What it is |
|---|---|---|---|
container | Color | The fill; transparent for an outline or a text button. | |
content | Color | The label's and the icon's colour. | |
border | Color | Color.Unspecified | The edge's colour, or Color.Unspecified for a button without an edge. |
Accessibility
- Touch target. As much room as the platform's minimum touch target is kept around the button: a button that is drawn small can be pressed with a finger too.