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
- The caller gives the size.
PantrixSkeletonhas no size of its own: it is given withmodifier, the size of the content it stands in for. - Shape.
shapeis the block's corners. Its default is the theme's smallest rounding (shapes.xs); in place of an avatar,shapes.fulldraws a circle. - Lines.
PantrixSkeletonTextdraws as many lines aslinessays. The last line is shorter than the others: the block reads as a paragraph.lineHeightis the height of the lines. - Band. A lighter band moves across the block, from one end to the other and back. When the system asks for reduced motion the band keeps still, and the block is in its own colour alone.
- Colours.
SkeletonColorsis two colours: the block's own (base) and the band that moves across it (highlight). A colour that is left out stays the theme's role:disabledContentanddivider. - On a fill. A skeleton does not look at the content colour around it: on a fill that is not one of the theme's grounds, the caller gives its colours.
- Announcing once. In a placeholder made of several skeletons the parts are given
contentDescription = null, and the parent around them says once that it is loading.
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.
| Parameter | Type | Default | What it is |
|---|---|---|---|
modifier | Modifier | Modifier | |
shape | Shape | PantrixTheme.shapes.xs | |
colors | SkeletonColors? | null | |
contentDescription | String? | PantrixTheme.strings.loading | |
tagKey | String? | 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.
| Parameter | Type | Default | What it is |
|---|---|---|---|
base | Color | Color.Unspecified | The block's own colour, and all of it under reduced motion. The theme's disabledContent. |
highlight | Color | Color.Unspecified | The lighter band that moves across the block. The theme's divider. |
Accessibility
- Screen reader. Every skeleton says its
contentDescription; the default is "Loading" in the theme's language.PantrixSkeletonTextsays it once for all its lines.