What is the difference between a stateless and stateful composable?
Compare stateless and stateful composables by who owns the changing state.
What the interviewer is testing
This question is less about recognising two Compose labels and more about component responsibility.
An interviewer is usually trying to see whether you understand what changes when a composable owns mutable state itself versus leaving that decision to its caller. That affects how easy the component is to control, reuse, test, and coordinate with the rest of the UI.
A strong answer also avoids turning "stateless" into a rule. The useful judgement is knowing when outside code needs control and when local ownership is perfectly reasonable.
❌ Common mistake
If they ask you to elaborate
Imagine an expandable card whose expanded state is completely private to the card.
A stateful version can own that behaviour itself:
@Composable
fun ExpandableCard() {
var expanded by rememberSaveable { mutableStateOf(false) }
Card {
Header(
expanded = expanded,
onClick = { expanded = !expanded },
)
if (expanded) {
Details()
}
}
}That API is convenient. The caller asks for an ExpandableCard and doesn't need to know how its expanded state is managed.
But imagine another screen needs to expand the card from somewhere else, keep several cards coordinated, or decide the value from screen state. Now hiding expanded inside the card gets in the way.
The stateless version leaves that decision to the caller:
@Composable
fun ExpandableCard(
expanded: Boolean,
onExpandedChange: (Boolean) -> Unit,
) {
Card {
Header(
expanded = expanded,
onClick = { onExpandedChange(!expanded) },
)
if (expanded) {
Details()
}
}
}This composable can still change visually whenever expanded changes. It is stateless because it doesn't own that changing value.
That distinction matters. Stateless does not mean static or unchanging; it means the state comes from somewhere else.
There is also no reason you must choose only one API.
A reusable component can expose the stateless version for callers that need control and provide a stateful wrapper for callers that just want the convenient behaviour:
@Composable
fun ExpandableCard() {
var expanded by rememberSaveable { mutableStateOf(false) }
ExpandableCard(
expanded = expanded,
onExpandedChange = { expanded = it },
)
}Now the stateless composable is the controllable core, while the stateful version provides a convenient default.
Production thinking
In production code, I wouldn't try to make every composable stateless. I would decide how much control the caller actually needs.
A design-system component is a good example. A caller may initially be happy for a component to manage its own small interaction state. Later another screen may need to drive that same value from screen state, synchronize several components, restore it differently, or react to the change elsewhere.
If the component exposes a stateless API, that control is available without duplicating the component's UI logic. A stateful wrapper can still keep the simple case simple.
This is why stateless and stateful are not competing architectures. They are two API shapes with different ownership boundaries.
The important part is to keep that boundary intentional. Don't push private implementation details onto callers for purity, and don't hide state that the rest of the UI genuinely needs to control.