skip to Main Content

LocalMaterialTheme: From Prop Hell to Theme Nirvana — Material3

March 15, 20263 minute read

  

Image generated using Perplexity

Jetpack Compose Material 3 1.5.0-alpha15 introduces a subtle but powerful refactor

MaterialTheme now uses a single LocalMaterialTheme CompositionLocal instead of separate locals for color, typography, shapes, and motion.

While this simplifies internal theme management, its real value emerges when building custom design systems and theme-aware Modifier libraries.

The Refactor: Cleaner Under the Hood

  • Previously, MaterialTheme relied on multiple CompositionLocals:
Source:https://android-review.googlesource.com/c/platform/frameworks/support/+/3949000/16/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/MaterialTheme.kt
  • Now: Everything flows through one unified source:
Source:https://android-review.googlesource.com/c/platform/frameworks/support/+/3949000/16/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/MaterialTheme.kt

This reduces allocations and simplifies the theme provider.

⭐️ Where It Shines: Design Systems & Custom Modifiers ⭐️

The game-changer is CompositionLocalConsumerModifierNode support.

Custom Modifiers that handle drawing/layout outside @Composable scopes can now read theme data directly:

object BrandGradientOverlayElement : ModifierNodeElement<BrandGradientOverlayNode>() {

override fun create(): BrandGradientOverlayNode = BrandGradientOverlayNode()

override fun update(node: BrandGradientOverlayNode) {
// No-Op
}

override fun InspectorInfo.inspectableProperties() {
name = "brandGradientOverlay"
}

override fun equals(other: Any?): Boolean = (this === other)

override fun hashCode(): Int = javaClass.hashCode()

}



class BrandGradientOverlayNode :
Modifier.Node(),
DrawModifierNode,
CompositionLocalConsumerModifierNode {

override fun ContentDrawScope.draw() {

// Read color scheme to access colors
val colorScheme =
currentValueOf(MaterialTheme.LocalMaterialTheme).colorScheme

val gradient = Brush.linearGradient(
listOf(
colorScheme.primary,
colorScheme.secondary)
)

drawContent()
drawRect(brush = gradient)
}
}

// Modifier
fun Modifier.brandGradientOverlay(): Modifier =
this then BrandGradientOverlayElement

Usage

@Composable
fun LocalMaterialThemeEx() {
MaterialTheme {
Card {
Box(
modifier = Modifier
.brandGradientOverlay()
) {
Text("Sample LocalMaterialTheme")
}
}
}
}

Before Unified LocalMaterialTheme

Before this change, CompositionLocalConsumerModifierNode couldn’t directly access the theme subsystems because there was no unified LocalMaterialTheme.

  • Pass theme data via params
fun Modifier.brandGradientOverlay(
// Manual prop from parent composable
primaryColor: Color,
secondaryColor: Color
): Modifier = drawWithCache {
val brandGradient = Brush.linearGradient(
0f to primaryColor,
1f to secondaryColor
)
onDrawWithContent {
drawContent()
drawRect(brush = brandGradient)
}
}

// Usage
Card(
modifier = Modifier.brandGradientOverlay(
primary = MaterialTheme.colorScheme.primary,
secondary = MaterialTheme.colorScheme.secondary
)
)
  • Capture from Composable (Recomposition-Heavy).
fun Modifier.brandGradientOverlay(): Modifier = composed {
// Captured here
val colorScheme = MaterialTheme.colorScheme

drawWithCache {
val brandGradient = Brush.linearGradient(
0f to colorScheme.primary,
1f to colorScheme.secondary
)
onDrawWithContent {
drawContent()
drawRect(brush = brandGradient)
}
}
}

❌ When Not to Use It

// ✅ DO: Regular composables
@Composable
fun MyButton() {
Button(colors = ButtonDefaults.colors(
containerColor = MaterialTheme.colorScheme.primary // Works unchanged
)) { }
}

// ❌ DON'T: Overcomplicate simple cases
@Composable
fun MyButton() {
// No need for LocalMaterialTheme.current here
val subsystems = MaterialTheme.LocalMaterialTheme.current
Button(colors = ButtonDefaults.colors(
containerColor = subsystems.colorScheme.primary
)) { }
}

References

Compose Material 3 | Jetpack | Android Developers

Keep in touch

https://www.linkedin.com/in/navczydev/


LocalMaterialTheme: From Prop Hell to Theme Nirvana — Material3 was originally published in ProAndroidDev on Medium, where people are continuing the conversation by highlighting and responding to this story.

 

Web Developer, Web Design, Web Builder, Project Manager, Business Analyst, .Net Developer

No Comments

This Post Has 0 Comments

Leave a Reply

Back To Top