Pantrix UI

Spinner

A spinning arc that says something is in progress, size square; it keeps still when the system asks for reduced motion. Drawn in color, or else the content colour of where it sits, as in a solid button, or the primary colour: the theme's own grounds give no content colour, so on the page, on a surface and in a card it is the brand's. contentDescription reaches screen readers as a polite live region; pass null inside something that already says it is loading.

import com.pantrixui.components.elements.spinner.PantrixSpinner

Examples

On its own

At its plainest: no parameter is given. The spinner is the style's size (18dp), and is announced to a screen reader as "Loading".

No colour is given either. The example stands on the theme's ground, and the ground gives no content colour: the spinner spins in its own default, the brand's colour.

PantrixSpinner()

Sizes

size is the spinner's side: here 16, 24, 32 and 48 dp. The arc's thickness grows with the size, so they all read at the same weight.

The second one's size is not a number but a step of the theme's spacing scale: PantrixTheme.spacing.xl, 24dp. A size taken from the scale scales with the app's density; one given as a number does not.

Row(
    horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.lg),
    verticalAlignment = Alignment.CenterVertically
) {
    PantrixSpinner(size = 16.dp)
    PantrixSpinner(size = PantrixTheme.spacing.xl)
    PantrixSpinner(size = 32.dp)
    PantrixSpinner(size = 48.dp)
}

Colours

color draws the arc in the colour it is given. In order: the theme's success and danger roles, the secondary text colour, and the app's own purple, which no role of the theme has.

val colors = PantrixTheme.colors
Row(
    horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.lg),
    verticalAlignment = Alignment.CenterVertically
) {
    PantrixSpinner(size = 24.dp, color = colors.success.color)
    PantrixSpinner(size = 24.dp, color = colors.danger.color)
    PantrixSpinner(size = 24.dp, color = colors.textSecondary)
    PantrixSpinner(size = 24.dp, color = ownColors().color)
}

On a fill

A spinner that is given no colour takes the content colour of where it sits. The first surface is in the theme's primary colour: the spinner spins in the role's onColor. The second is in the success role's container: the spinner is in onContainer. Neither is given a color.

The button's spinner is the button's own: loading = true puts it in place of the leading icon, in the button's content colour.

val colors = PantrixTheme.colors
FlowRow(
    horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.lg),
    verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.md),
    itemVerticalAlignment = Alignment.CenterVertically
) {
    PantrixSurface(color = colors.primary.color) {
        PantrixSpinner(modifier = Modifier.padding(PantrixTheme.spacing.md), size = 24.dp)
    }
    PantrixSurface(color = colors.success.container) {
        PantrixSpinner(modifier = Modifier.padding(PantrixTheme.spacing.md), size = 24.dp)
    }
    PantrixButton(text = "Saving", onClick = {}, loading = true, tagKey = "saving")
}

While a page loads

A large spinner in the centre, standing in for the content until it arrives: size = PantrixTheme.spacing.xxl, 32dp.

contentDescription says what is loading: a screen reader says "Loading orders" in place of "Loading". tagKey is given too: automation finds the spinner by the tag Spinner_orders_loading. Press the button: the content arrives and the spinner goes.

var loading by rememberSaveable { mutableStateOf(true) }
PantrixSurface(
    modifier = Modifier.fillMaxWidth().height(160.dp),
    border = PantrixTheme.colors.divider
) {
    if (loading) {
        Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
            PantrixSpinner(
                size = PantrixTheme.spacing.xxl,
                contentDescription = "Loading orders",
                tagKey = "orders_loading"
            )
        }
    } else {
        PantrixText(text = "Three orders are on their way.", modifier = Modifier.padding(PantrixTheme.spacing.lg))
    }
}
PantrixButton(
    text = if (loading) "Finish loading" else "Reload",
    onClick = { loading = !loading },
    variant = ButtonVariant.Outline,
    size = ButtonSize.Small,
    tagKey = "toggle_orders"
)

Beside a text that says it is loading

A spinner that is given contentDescription = null says nothing to a screen reader. The text beside it already says the work is in progress: the spinner need not say it as well.

Row(
    horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm),
    verticalAlignment = Alignment.CenterVertically
) {
    PantrixSpinner(size = 16.dp, contentDescription = null)
    PantrixText(text = "Saving changes", color = PantrixTheme.colors.textSecondary)
}

Default size from the style

SpinnerStyle holds the size of a spinner that is given none. ProvidePantrixStyles changes it for a part of the tree; the same change is given to the whole app through PantrixTheme's styles parameter.

The first spinner takes its size from the style: 28dp here. The second is given size: the parameter takes precedence over the style.

val styles = remember { pantrixStyles(SpinnerStyle.override(all = SpinnerStyle(size = 28.dp))) }
ProvidePantrixStyles(styles = styles) {
    Row(
        horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.lg),
        verticalAlignment = Alignment.CenterVertically
    ) {
        PantrixSpinner()
        PantrixSpinner(size = 16.dp)
    }
}

API

modifier

A spinning arc that says something is in progress, size square; it keeps still when the system asks for reduced motion. Drawn in color, or else the content colour of where it sits, as in a solid button, or the primary colour: the theme's own grounds give no content colour, so on the page, on a surface and in a card it is the brand's. contentDescription reaches screen readers as a polite live region; pass null inside something that already says it is loading.

ParameterTypeDefaultWhat it is
modifierModifierModifierthe spinner's modifier.
sizeDpPantrixTheme.style(SpinnerStyle).size
colorColorColor.Unspecified
contentDescriptionString?PantrixTheme.strings.loading
tagKeyString?nullthe spinner's automation key: the spinner is Spinner_<tagKey>, and without one a key of where it is called. Visible text is never the key.

Accessibility