First-mover demo app for the Compose Styles API — the new experimental
declarative styling system in Jetpack Compose.
The Styles API (@ExperimentalFoundationStyleApi) introduces a declarative way to define visual properties and interaction states for composables. Instead of managing InteractionSource, animateColorAsState, and multiple modifier chains, you define everything in a single Style { } block:
// Before: 15+ lines of imperative state management
val isPressed by interactionSource.collectIsPressedAsState()
val bgColor by animateColorAsState(if (isPressed) Color.DarkBlue else Color.Blue)
val scale by animateFloatAsState(if (isPressed) 0.95f else 1f)
// After: Visual states in one block (still needs MutableStyleState wiring — see below)
val style = Style {
background(Color.Blue)
shape(RoundedCornerShape(12.dp))
contentPadding(16.dp)
pressed(Style {
animate(Style {
background(Color.DarkBlue)
scale(0.95f)
})
})
}
Box(Modifier.styleable(styleState = styleState, style = style))Read the full deep-dive at aditlal.dev/compose-styles.
Toggle switches simulate pressed, hovered, and focused states. Watch the showcase element react in real-time — all driven by a single Style definition.
selected(), checked(), and disabled() state blocks. Tap cards to see blue selection borders appear and green checked backgrounds animate in.
fontSize(), fontWeight(), contentColor(), contentBrush(), letterSpacing(), and textDecoration() — all inside Style {} blocks with automatic animation.
Styles read MaterialTheme colors at resolution time. Toggle dark/light mode and watch every styled element update instantly.
| # | Lab | Styles API Features |
|---|---|---|
| 1 | Interactive Buttons | pressed, hovered, focused + animate |
| 2 | Style Composition | Style.then(), Style(s1, s2, s3) factory |
| 3 | State-Driven Cards | selected, checked, disabled states |
| 4 | Animated Transforms | scale(), rotationZ(), translationX/Y() |
| 5 | Micro-Interactions | favorite, nav bar, pill toggle with checked() |
| 6 | Text Styling | fontWeight(), contentColor(), contentBrush() |
| 7 | Theme Integration | CompositionLocal access inside styles |
| 8 | Custom Components | style: Style as component parameter + defaults objects |
styleable(style = myStyle) without an explicit styleState does not detect interaction states from sibling modifiers. This is by design — earlier alphas had auto-detection but it conflicted with the interactionSource on clickable/toggleable. You wire it yourself:
// Toggle states (checked, selected, enabled) — set explicitly:
val styleState = remember { MutableStyleState(MutableInteractionSource()) }
styleState.isChecked = isChecked
// Interaction states (pressed, hovered) — share the interactionSource:
val interactionSource = remember { MutableInteractionSource() }
val styleState = remember { MutableStyleState(interactionSource) }
Box(
Modifier
.styleable(styleState = styleState, style = myStyle)
.clickable(interactionSource = interactionSource, indication = null) { }
)See STYLES_API_GUIDE.md for the full developer reference.
- Android Studio Ladybug or later
- Min SDK 24, Target SDK 35
androidx.compose.foundation:foundation:1.11.0-alpha06
./gradlew assembleDebug- Blog post: Deep-dive into the Compose Styles API
STYLES_API_GUIDE.md— Complete developer reference- Compose Skill — AI agent skill for Jetpack Compose (includes Styles API reference)
- AOSP Source —
androidx.compose.foundation.style
MIT




