In Jetpack Version 1.4.x rememberTextMeasurer is introduced to measure text. By measuring your text you can get width even before laying outt anything in a Composable as
val text = "Initial Text Size"
val density = LocalDensity.current
val textMeasurer: TextMeasurer = rememberTextMeasurer()
val style: TextStyle = MaterialTheme.typography.button
val initialWidthDp: Dp = remember(text) {
with(density) {
textMeasurer.measure(
text = text,
style= style,
).size.width.toDp()
}
}
Style of button is required to measure text correctly.

Full sample
@Preview
@Composable
private fun TextWidthSample() {
val text = "Initial Text Size"
val density = LocalDensity.current
val textMeasurer: TextMeasurer = rememberTextMeasurer()
val style: TextStyle = MaterialTheme.typography.button
val initialWidthDp: Dp = remember(text) {
with(density) {
textMeasurer.measure(
text = text,
style = style,
).size.width.toDp()
}
}
var isLoading by remember {
mutableStateOf(false)
}
Column(
modifier = Modifier
.fillMaxSize()
.padding(20.dp)
) {
Button(
onClick = { /*TODO*/ }
) {
Text(
modifier = Modifier
.width(initialWidthDp),
text = if (isLoading) "Loading" else text,
textAlign = TextAlign.Center
)
}
Spacer(modifier = Modifier.height(20.dp))
Button(
onClick = { isLoading = isLoading.not() }
) {
Text("Loading: $isLoading")
}
}
}
If version is lower than 1.4.0 and don't want to use experimental api you can use Modifier.onSizeChanged with another recomposition or SubcomposeLayout without another recomposition. SubcomposeLayout can be used to get dimensions of Composable even before it's measured and laid out like adding progress button inside Button while loading.
How to adjust size of component to it's child and remain unchanged when it's child size will change? (Jetpack Compose)