Skip to content

Theming

Instead of repeating color, shape, and highlight arguments at every call site, you can provide a PlaceholderTheme that supplies defaults for every Modifier.placeholder and Modifier.placeholderText call in its scope. Explicitly passed arguments always override the theme.

ProvidePlaceholderTheme

ProvidePlaceholderTheme(
    PlaceholderTheme(
        color = Color.LightGray,
        shape = RoundedCornerShape(8.dp),
        highlight = PlaceholderDefaults.shimmer,
    ),
) {
    // Every placeholder call inside this scope picks up the theme defaults
    Text("...", modifier = Modifier.placeholder(enabled = isLoading))
    Box(modifier = Modifier.size(80.dp).placeholder(enabled = isLoading))
}

The full surface is:

Property Default
color Color.Gray.copy(alpha = 0.35f)
shape RectangleShape
highlight PlaceholderDefaults.fade
placeholderFadeTransitionSpec { spring() }
contentFadeTransitionSpec { spring() }

PlaceholderTheme.Default exposes these so you can derive a theme that overrides only some properties.

Material Theme Integration

For Material 3 apps, materialPlaceholderTheme() builds a theme derived from the current MaterialTheme.colorScheme, so placeholders track the active light/dark scheme automatically.

ProvidePlaceholderTheme(materialPlaceholderTheme()) {
    // Background uses MaterialTheme.colorScheme.surfaceVariant
    // Highlight is a shimmer colored from MaterialTheme.colorScheme.onSurface
    YourScreen()
}

You can also override the specific colors:

ProvidePlaceholderTheme(
    materialPlaceholderTheme(
        color = MaterialTheme.colorScheme.tertiaryContainer,
        highlightColor = MaterialTheme.colorScheme.onTertiaryContainer.copy(alpha = 0.4f),
        shape = RoundedCornerShape(12.dp),
    ),
) {
    YourScreen()
}

Reusing a Theme

If you want to capture the theme once and reuse it across multiple ProvidePlaceholderTheme boundaries, use rememberMaterialPlaceholderTheme():

val theme = rememberMaterialPlaceholderTheme()

ProvidePlaceholderTheme(theme) { /* … */ }
ProvidePlaceholderTheme(theme) { /* … */ }

Reading the Active Theme

If you need to read the current theme from inside a composable (for example, to apply it to a non-modifier draw), use the LocalPlaceholderTheme CompositionLocal:

val theme = LocalPlaceholderTheme.current
val barColor = theme.color