| name | android-compose-components |
| description | Complete catalog of Android Jetpack Compose and Material Design 3 components.
Covers M3 Expressive (2025), gesture system, graphics/drawing, navigation patterns,
theming, and mapping guidance for Crystal cross-platform UI integration via JNI.
|
| user-invocable | true |
| allowed-tools | Read, Write, Edit, Glob, Grep, Bash, WebSearch, WebFetch |
| version | 1.0.0 |
Android Jetpack Compose / Material 3 Components Reference
This document is the authoritative reference for Android Jetpack Compose and Material
Design 3 UI components as of 2025 (compose-material3 1.4.0 stable, 1.5.x alpha series).
It covers Material 3 Expressive, the full gesture system, Canvas/graphics APIs, adaptive
navigation, theming tokens, and platform-specific Android APIs. It provides implementation
priority guidance for the asset_pipeline Crystal library's Android::Renderer (JNI bridge).
The asset_pipeline maps Crystal UI::View types to native Android elements at compile
time. The Android::Renderer (in src/ui/renderers/android_renderer.cr) calls through
the JNI bridge (jni_bridge.c) to Kotlin/Java, which creates the actual View or Composable
objects. The JNI collection bridge (src/ui/native/jni_collections.cr) provides typed
wrappers for JNI references, ViewGroup batch operations, and string marshaling.
1. Overview
Material Design 3 and M3 Expressive
Material Design 3 (M3) is the current Google design system, launched alongside Android 12
(Material You). As of 2025 the system has evolved into M3 Expressive, announced at
Google I/O 2025, which adds:
- Five new component families: ButtonGroup, SplitButtonLayout, FloatingActionButtonMenu,
LoadingIndicator/WavyProgressIndicator, and Floating Toolbars
- 35 new shape definitions and shape-morphing animations
- A physics-based spring motion system replacing fixed easing curves
- Enhanced typography expressiveness
- Research backed by 46 studies and 18,000+ participants
The Jetpack Compose implementation ships in androidx.compose.material3 (latest stable
1.4.0, released September 24 2025). Experimental and expressive APIs continue in the
1.5.x alpha series.
Jetpack Compose vs Traditional Android Views
| Aspect | Jetpack Compose | Traditional Android Views |
|---|
| Paradigm | Declarative (describe what, not how) | Imperative (XML + Java/Kotlin mutations) |
| State | State<T>, MutableState<T>, remember {} | ViewModel + LiveData/StateFlow observers |
| Layout | Compose layout pass (intrinsics-based) | Measure/layout/draw pass on View hierarchy |
| Thread | Main thread, coroutines for side effects | Main thread for UI; background via Handler |
| Styling | Modifier chains, MaterialTheme | XML attributes, style resources, themes |
| Crystal JNI | Lower priority — hard to drive from native | Higher priority — jobject ViewGroup refs |
Crystal Integration: JNI Bridge Pattern
Crystal UI::View tree
|
v
Android::Renderer (src/ui/renderers/android_renderer.cr)
visit(label) / visit(button) / ...
|
v [Crystal -> C via @[Link] fun declarations]
jni_bridge.c (C wrapper functions)
|
v [C -> JVM via JNIEnv* calls]
Kotlin/Java Activity or Fragment
- Inflates Views or creates Composables
- Returns jobject back to C
|
v [back to Crystal]
NativeHandle (UI::JNI.global(env, local_ref))
stored in NativeView node
The JNI collection bridge (src/ui/native/jni_collections.cr) provides:
UI::JNI::JString — Crystal String <-> jstring marshaling
UI::JNI::ObjectArray — Crystal Array <-> jobjectArray
UI::JNI::ArrayList — Crystal Array <-> java.util.ArrayList
UI::JNI.viewgroup_add_views(env, parent, children) — batch addView()
UI::JNI.local_frame(env, capacity) — scoped local reference tables
Critical JNI rule: Local refs are only valid within the current native method call.
Use UI::JNI.global(env, local_ref) to promote any View reference that Crystal must
hold past the return boundary, then NativeHandle tracks the lifetime.
API Level Requirements Summary
| Feature | Min API |
|---|
| All Compose basics | 21 (Android 5.0) |
| Dynamic Color (Material You) | 31 (Android 12) |
| RenderEffect / blur | 31 (Android 12) |
| RuntimeShader / AGSL | 33 (Android 13) |
| Predictive back gesture | 34 (Android 14) |
| Compose BOM 2024+ | 21 |
| WideNavigationRail | 21 (M3 Expressive, lib-based) |
| FloatingActionButtonMenu | 21 (M3 Expressive, lib-based) |
| WavyLinearProgressIndicator | 21 (M3 Expressive, lib-based) |
| Picture-in-Picture | 26 (Android 8.0) |
| Glance Widgets | 23 (Android 6.0) |
2. Material 3 Components by Category
All components require:
implementation("androidx.compose.material3:material3:1.4.0")
Experimental APIs require @OptIn(ExperimentalMaterial3Api::class).
Expressive APIs (1.5.x alpha) additionally require @OptIn(ExperimentalMaterial3ExpressiveApi::class).
2.1 Buttons and FABs
Standard Buttons
| Compose Function | Emphasis | Traditional View | Crystal UI::View Equiv. | Priority |
|---|
Button | High — filled, primary color | MaterialButton | UI::Button (maps here) | P0 (done) |
FilledButton | High — alias for Button | MaterialButton | Same as Button | P0 |
ElevatedButton | Medium — elevated surface | MaterialButton (elevation style) | — | P1 |
FilledTonalButton | Medium — secondary container fill | MaterialButton (tonal style) | — | P1 |
OutlinedButton | Low — bordered, transparent fill | MaterialButton (outlined style) | — | P1 |
TextButton | Lowest — text only | MaterialButton (text style) | — | P2 |
All button parameters:
Button(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
shape: Shape = ButtonDefaults.shape,
colors: ButtonColors = ButtonDefaults.buttonColors(),
elevation: ButtonElevation? = ButtonDefaults.buttonElevation(),
border: BorderStroke? = null,
contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
interactionSource: MutableInteractionSource? = null,
content: @Composable RowScope.() -> Unit
)
Icon Buttons
| Compose Function | Traditional View | Priority |
|---|
IconButton | ImageButton | P1 |
FilledIconButton | MaterialButton (icon, filled) | P2 |
FilledTonalIconButton | MaterialButton (icon, tonal) | P2 |
OutlinedIconButton | MaterialButton (icon, outlined) | P2 |
IconToggleButton | ImageButton + toggle state | P2 |
Floating Action Buttons (FABs)
| Compose Function | Size | Traditional View | Priority |
|---|
FloatingActionButton | Standard (56dp) | FloatingActionButton | P1 |
SmallFloatingActionButton | Small (40dp) | FloatingActionButton (mini) | P2 |
LargeFloatingActionButton | Large (96dp) | FloatingActionButton (large) | P2 |
ExtendedFloatingActionButton | Pill with text | ExtendedFloatingActionButton | P2 |
FAB parameters:
FloatingActionButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
shape: Shape = FloatingActionButtonDefaults.shape,
containerColor: Color = FloatingActionButtonDefaults.containerColor,
contentColor: Color = contentColorFor(containerColor),
elevation: FloatingActionButtonElevation = FloatingActionButtonDefaults.elevation(),
interactionSource: MutableInteractionSource? = null,
content: @Composable () -> Unit
)
NEW: M3 Expressive Button Components (1.4.x / 1.5.x-alpha)
| Compose Function | Description | Traditional View Equiv. | Priority |
|---|
ButtonGroup | Horizontal or vertical group of semantically related buttons with connected styling | LinearLayout of MaterialButton | P2 |
SplitButtonLayout | Two-zone button: action zone + dropdown trigger zone | Custom compound MaterialButton | P2 |
FloatingActionButtonMenu | FAB that expands into a menu of secondary actions | Custom CoordinatorLayout pattern | P2 |
ToggleFloatingActionButton | FAB with toggled (expanded/collapsed) state, used as anchor for FABMenu | FloatingActionButton | P2 |
FloatingActionButtonMenuItem | Individual item inside a FABMenu | MaterialButton in overlay | P2 |
ButtonGroup(
modifier: Modifier = Modifier,
horizontalArrangement: Arrangement.Horizontal = ButtonGroupDefaults.horizontalArrangement,
verticalAlignment: Alignment.Vertical = Alignment.CenterVertically,
content: @Composable ButtonGroupScope.() -> Unit
)
FloatingActionButtonMenu(
expanded: Boolean,
button: @Composable () -> Unit,
modifier: Modifier = Modifier,
content: @Composable FloatingActionButtonMenuScope.() -> Unit
) {
FloatingActionButtonMenuItem(
onClick = { },
icon = { Icon(Icons.Default.Share, contentDescription = null) },
text = { Text("Share") }
)
}
2.2 Selection Controls
Checkbox
| Compose Function | Traditional View | Parameters | Priority |
|---|
Checkbox | CheckBox | checked, onCheckedChange, enabled, colors | P1 |
TriStateCheckbox | CheckBox (partial state) | state: ToggleableState, onClick, enabled, colors | P2 |
Checkbox(
checked: Boolean,
onCheckedChange: ((Boolean) -> Unit)?,
modifier: Modifier = Modifier,
enabled: Boolean = true,
colors: CheckboxColors = CheckboxDefaults.colors(),
interactionSource: MutableInteractionSource? = null
)
RadioButton
| Compose Function | Traditional View | Priority |
|---|
RadioButton | RadioButton | P1 |
RadioButton has no built-in group; you track selection state in the parent composable.
Traditional equivalent for a group: RadioGroup containing RadioButton views.
RadioButton(
selected: Boolean,
onClick: (() -> Unit)?,
modifier: Modifier = Modifier,
enabled: Boolean = true,
colors: RadioButtonColors = RadioButtonDefaults.colors()
)
Switch
| Compose Function | Traditional View | Crystal UI::View Equiv. | Priority |
|---|
Switch | SwitchCompat / MaterialSwitch | — | P1 |
Switch(
checked: Boolean,
onCheckedChange: ((Boolean) -> Unit)?,
modifier: Modifier = Modifier,
thumbContent: (@Composable () -> Unit)? = null,
enabled: Boolean = true,
colors: SwitchColors = SwitchDefaults.colors(),
interactionSource: MutableInteractionSource? = null
)
Chips
All chips require @OptIn(ExperimentalMaterial3Api::class).
| Compose Function | Use Case | Traditional View | Priority |