Text Skeleton¶
Modifier.placeholder always renders a single rectangle — fine for icons and avatars, but for paragraph-style text it produces one large block instead of separate line bars. Modifier.placeholderText solves this by drawing lines skeleton bars sized to the supplied TextStyle, with the last bar narrowed by lastLineFraction for a natural ragged ending.
Basic Usage¶
Text(
text = body ?: "",
style = MaterialTheme.typography.bodyLarge,
modifier = Modifier
.fillMaxWidth()
.placeholderText(
enabled = body == null,
lines = 3,
lastLineFraction = 0.6f,
style = MaterialTheme.typography.bodyLarge,
),
)
Parameters¶
| Parameter | Default | Description |
|---|---|---|
enabled |
true |
When true, draws skeleton bars; when false, the host's content is shown. |
lines |
3 |
Number of bars to draw. |
lastLineFraction |
0.6f |
Width of the final bar relative to the host width, in 0f..1f. |
style |
LocalTextStyle.current |
Text style used to derive line height and bar height. |
color / shape / highlight |
LocalPlaceholderTheme.current.* |
Same theme-driven defaults as Modifier.placeholder. |
Layout Behavior¶
While enabled is true, the host is forced to reserve at least lines × lineHeight of vertical space. This is what lets you attach the modifier to an empty Text("") or a null-content composable and still display the full skeleton.
When enabled flips to false, the minimum-height enforcement is dropped and the host collapses to its natural size — the bars fade away and the actual content takes over.
Resolving Line Height¶
The modifier reads style.lineHeight and style.fontSize and converts them to pixels via LocalDensity. Specifically:
- If
style.lineHeightis insp, it's used directly. - If
style.lineHeightis inemandstyle.fontSizeis insp, line height is computed asfontSize × emValue. - If
style.lineHeightis unspecified, it falls back tofontSize × 1.4— the multiplier most font systems use as a sensible default.
Composing with Theming and Coordination¶
placeholderText reads the same defaults from LocalPlaceholderTheme and participates in PlaceholderSurface coordination, so it composes cleanly with the rest of the API:
ProvidePlaceholderTheme(materialPlaceholderTheme()) {
PlaceholderSurface {
Column {
Text(
text = title ?: "",
style = MaterialTheme.typography.titleMedium,
modifier = Modifier.placeholderText(
enabled = title == null,
lines = 1,
style = MaterialTheme.typography.titleMedium,
),
)
Text(
text = body ?: "",
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.placeholderText(
enabled = body == null,
lines = 3,
lastLineFraction = 0.5f,
style = MaterialTheme.typography.bodyMedium,
),
)
}
}
}
In this example every bar — title and body, across both Text composables — shimmers in lockstep with surrounding placeholders, using the active Material color scheme.