Composable Functions Basics
A composable function is any Kotlin function annotated with @Composable. By convention it's named in PascalCase (like a class), because conceptually it represents a piece of UI rather than an ordinary computation. Composable functions can accept parameters, call other composables, and emit UI elements into the tree that Compose manages — but unlike normal functions, they don't 'return' UI in the traditional sense; they emit it as a side effect of being called within the composition.
Cricket analogy: A @Composable function is like a scoring app module named in a clear convention, say ScoreCardDisplay, that emits the visual scoreboard as a side effect of being called each ball, rather than handing back a value to store.
Anatomy of a Composable
A typical composable takes data parameters (what to display) and optionally event-handling lambdas (what to do when the user interacts), plus an optional Modifier parameter for styling and layout behavior. Good practice is to make composables 'stateless' where possible — they receive state and emit events upward rather than owning mutable state themselves — which keeps them reusable, testable, and easy to preview.
Cricket analogy: A stateless composable is like an umpire's signal display that just shows whatever decision it's given (out or not out) and reports the appeal upward, rather than deciding the verdict itself.
@Composable
fun UserProfileCard(
userName: String,
bio: String,
onFollowClick: () -> Unit,
modifier: Modifier = Modifier
) {
Card(modifier = modifier.padding(12.dp)) {
Column(modifier = Modifier.padding(16.dp)) {
Text(text = userName, style = MaterialTheme.typography.titleMedium)
Text(text = bio, style = MaterialTheme.typography.bodySmall)
Spacer(modifier = Modifier.height(8.dp))
OutlinedButton(onClick = onFollowClick) {
Text("Follow")
}
}
}
}
@Preview(showBackground = true)
@Composable
fun UserProfileCardPreview() {
MaterialTheme {
UserProfileCard(userName = "Asha", bio = "Android dev", onFollowClick = {})
}
}Composition, Not Inheritance
Compose favors composition over inheritance: complex UI is built by nesting and combining small, focused composables rather than subclassing large View classes. A screen composable might call a TopBarComposable, a ListComposable, and a FooterComposable, each independently previewable and testable. This mirrors good software design generally, but Compose makes it the default and idiomatic way to build UI.
Cricket analogy: Composition over inheritance is like a team built from specialist modules, an opener, a death-over bowler, a wicketkeeper, combined on the field rather than one giant all-rounder class subclassed endlessly.
The @Preview annotation lets Android Studio render a composable in the design surface without running the full app on a device or emulator, which massively speeds up UI iteration.
Parameter Conventions
Idiomatic Compose code places a trailing modifier: Modifier = Modifier parameter last (with a default), so callers can optionally customize layout/styling without changing every call site. Content lambdas (for composables like Column or Box that take a trailing @Composable lambda) go last per Kotlin's trailing-lambda syntax, letting call sites read almost like a DSL.
Cricket analogy: Placing the Modifier parameter last with a default is like a batting order where the specialist finisher slots in at number six by default, but the captain can freely reposition them without disturbing the rest of the lineup.
Forgetting the @Composable annotation on a function that calls other composables produces a compile error — composables can only be invoked from within a @Composable context (another composable, or specific entry points like setContent).
- Composable functions are Kotlin functions annotated @Composable, named in PascalCase by convention.
- They emit UI as a side effect of composition rather than returning a UI object.
- Stateless composables that receive state and emit events are more reusable and testable.
- Compose favors building UI via composition of small functions rather than class inheritance.
- A trailing Modifier parameter with a default lets any composable be customized by its caller.
- @Preview lets you render composables in Android Studio without a full app run.
Practice what you learned
1. What naming convention is idiomatic for composable functions?
2. Where can a @Composable function be called from?
3. What is the idiomatic position and default for a Modifier parameter in a composable?
4. What is the benefit of writing a 'stateless' composable that receives state via parameters and emits events via lambdas?
5. What does the @Preview annotation enable?
Was this page helpful?
You May Also Like
What Is Jetpack Compose?
Jetpack Compose is Android's modern toolkit for building native UI declaratively in Kotlin, replacing XML layouts with composable functions and a reactive recomposition model.
Modifiers in Compose
Modifiers are immutable, chainable objects that decorate or configure a composable's layout, appearance, and behavior — Compose's answer to layout params, styling, and gesture handling.
State Hoisting
Learn the Compose pattern of moving state up to a caller so composables become stateless, reusable, and easier to test.
Layouts: Row, Column, and Box
Row, Column, and Box are Compose's three foundational layout composables for arranging children horizontally, vertically, or stacked, forming the basis of nearly every screen.