Skeleton Text
A placeholder for a paragraph: lines skeleton lines lineHeight tall, the last one shorter, each in colors where they are not the theme's. The column carries one contentDescription for all of them.
import com.pantrixui.components.elements.skeleton.PantrixSkeletonText
- 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
In place of a paragraph
At its plainest: three lines standing in for a paragraph that is loading. lines is the number of lines; the last line is shorter than the others, so the block reads as a paragraph.
The band that moves across them says something is loading; when the system asks for reduced motion the band keeps still. A screen reader says "Loading" once for the three lines.
PantrixSkeletonText(lines = 3, modifier = Modifier.fillMaxWidth())
In its own colour
colors puts the skeleton in the colours it is given, not the theme's. There are two: base is the block's own colour, highlight the band that moves across it. Here both are pale versions of the app's own purple: they show whatever the ground is. When the system asks for reduced motion the band keeps still and only base shows.
Only a colour that is set changes; one that is left out stays the theme's role.
val own = ownColors()
PantrixSkeletonText(
lines = 3,
modifier = Modifier.fillMaxWidth(),
colors = SkeletonColors(base = own.color.copy(alpha = 0.35f), highlight = own.color.copy(alpha = 0.15f))
)
Line height
lineHeight is the height of each line; its default is PantrixTheme.spacing.md, 12dp. It is chosen to suit the size of the text it stands in for: 8dp at the top for small text, the default in the middle, and 20dp at the bottom for a heading. The space between the lines does not change.
PantrixSkeletonText(lines = 2, modifier = Modifier.fillMaxWidth(), lineHeight = PantrixTheme.spacing.sm)
PantrixSkeletonText(lines = 2, modifier = Modifier.fillMaxWidth())
PantrixSkeletonText(lines = 2, modifier = Modifier.fillMaxWidth(), lineHeight = 20.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)
}
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. The surface here is in the info role's container.
base is a pale version of the colour written on that surface (onContainer), and highlight is the surface's own colour: the band looks like an opening that passes through the lines.
val info = PantrixTheme.colors.info
PantrixSurface(modifier = Modifier.fillMaxWidth(), color = info.container) {
PantrixSkeletonText(
lines = 2,
modifier = Modifier.fillMaxWidth().padding(PantrixTheme.spacing.lg),
colors = SkeletonColors(base = info.onContainer.copy(alpha = 0.3f), highlight = info.container)
)
}
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
lines
A placeholder for a paragraph: lines skeleton lines lineHeight tall, the last one shorter, each in colors where they are not the theme's. The column carries one contentDescription for all of them.
| Parameter | Type | Default | What it is |
|---|---|---|---|
lines | Int | ||
modifier | Modifier | Modifier | the column's modifier: its width, above all. |
lineHeight | Dp | PantrixTheme.spacing.md | |
colors | SkeletonColors? | null | |
contentDescription | String? | PantrixTheme.strings.loading | |
tagKey | String? | null | the column's automation key: it is SkeletonText_<tagKey>, and its lines have no tags of their own. Without one it has no tag. |
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.