Pantrix UI

Skeleton

A placeholder for content still loading: a block in shape with a shimmer across it, which keeps still when the system asks for reduced motion. Size it with modifier. colors are the block's own, where it does not take the theme's. A screen reader hears contentDescription, the theme's "loading" string by default; pass null where a parent already announces it. tagKey is its automation key: the block is Skeleton_<tagKey>, and a test knows the content has arrived when it is gone. Without one it has no tag.

import com.pantrixui.components.elements.skeleton.PantrixSkeleton

Examples

A single block and its shape

PantrixSkeleton is a single block and has no size of its own: modifier gives it its size, that of the content it stands in for. shape is the block's corners.

In order: an avatar's circle (shapes.full), an image's rectangle (shapes.md), a button's pill, and a line that is given no shape. The default shape is the theme's smallest rounding: shapes.xs.

FlowRow(
    horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.lg),
    verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.md),
    itemVerticalAlignment = Alignment.CenterVertically
) {
    PantrixSkeleton(modifier = Modifier.size(48.dp), shape = PantrixTheme.shapes.full)
    PantrixSkeleton(modifier = Modifier.size(width = 96.dp, height = 64.dp), shape = PantrixTheme.shapes.md)
    PantrixSkeleton(modifier = Modifier.size(width = 88.dp, height = 32.dp), shape = PantrixTheme.shapes.full)
    PantrixSkeleton(modifier = Modifier.size(width = 120.dp, height = 12.dp))
}

A row announced once

An avatar and two lines: the skeleton of a list row. If both parts said "Loading", a screen reader would say it twice for the same row.

The parts are given contentDescription = null. The row as a whole says once that it is loading, in the theme's own string: PantrixTheme.strings.loading.

val loading = PantrixTheme.strings.loading
Row(
    modifier = Modifier.fillMaxWidth().semantics(mergeDescendants = true) { contentDescription = loading },
    horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.md),
    verticalAlignment = Alignment.CenterVertically
) {
    PantrixSkeleton(modifier = Modifier.size(40.dp), shape = PantrixTheme.shapes.full, contentDescription = null)
    PantrixSkeletonText(lines = 2, modifier = Modifier.weight(1f), contentDescription = null)
}

Until the content arrives

A skeleton resembles the content it stands in for: a circle of the same size in place of the avatar, two lines in place of two lines of text. Press the button: the content arrives and takes the skeleton's place. The caller decides which of the two is drawn.

While it loads, the circle has no description; the lines beside it say "Loading" once. The lines' tag (tagKey) is what a test waits on: once SkeletonText_profile is gone, the content has arrived.

var loading by rememberSaveable { mutableStateOf(true) }
Row(
    modifier = Modifier.fillMaxWidth(),
    horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.md),
    verticalAlignment = Alignment.CenterVertically
) {
    if (loading) {
        PantrixSkeleton(
            modifier = Modifier.size(40.dp),
            shape = PantrixTheme.shapes.full,
            contentDescription = null
        )
        PantrixSkeletonText(lines = 2, modifier = Modifier.weight(1f), tagKey = "profile")
    } else {
        PantrixAvatar(contentDescription = null, initials = "AY", size = 40.dp)
        Column(modifier = Modifier.weight(1f)) {
            PantrixText(text = "Ayşe Yılmaz", tagKey = "profile_name")
            PantrixText(
                text = "Design team",
                style = PantrixTheme.typography.footnote,
                color = PantrixTheme.colors.textSecondary
            )
        }
    }
}
PantrixButton(
    text = if (loading) "Bring in the content" else "Reload",
    onClick = { loading = !loading },
    variant = ButtonVariant.Outline,
    size = ButtonSize.Small,
    tagKey = "toggle_profile"
)

API

modifier

A placeholder for content still loading: a block in shape with a shimmer across it, which keeps still when the system asks for reduced motion. Size it with modifier. colors are the block's own, where it does not take the theme's. A screen reader hears contentDescription, the theme's "loading" string by default; pass null where a parent already announces it. tagKey is its automation key: the block is Skeleton_<tagKey>, and a test knows the content has arrived when it is gone. Without one it has no tag.

ParameterTypeDefaultWhat it is
modifierModifierModifier
shapeShapePantrixTheme.shapes.xs
colorsSkeletonColors?null
contentDescriptionString?PantrixTheme.strings.loading
tagKeyString?null

SkeletonColors

What PantrixSkeleton and PantrixSkeletonText are painted with, for a placeholder that does not take the theme's: a colour that is set is used, and one that is left out stays the theme's role.

ParameterTypeDefaultWhat it is
baseColorColor.UnspecifiedThe block's own colour, and all of it under reduced motion. The theme's disabledContent.
highlightColorColor.UnspecifiedThe lighter band that moves across the block. The theme's divider.

Accessibility