Compose Multiplatform themed @Preview
Recently Compose Multiplatform @Preview annotation received an update, and we got access to these parameters:
- name
- group
- widthDp
- heightDp
- locale
- showBackground
- backgroundColor
Today I tried it for my app and got a little bit frustrated that there is still no way to specify a dark or light theme. In Android, we can use the uiMode parameter to specify the UI configuration, but it doesn't exist in Compose Multiplatform.
So I started looking into how other people try to resolve this and stumbled upon the KotlinConf app PreviewHelper wrapper:
@Composable
fun PreviewHelper(
paddingEnabled: Boolean = true,
content: @Composable ColumnScope.() -> Unit,
) {
Column {
KotlinConfTheme(darkTheme = false) {
PreviewColumn(paddingEnabled, content)
}
KotlinConfTheme(darkTheme = true) {
PreviewColumn(paddingEnabled, content)
}
}
}The idea is to wrap preview content with PreviewHelper and show it twice: once with the dark theme and once with the light theme.
This works great with composables that are smaller than the preview default size, but what if we want to show a preview of the entire screen?
@Preview
@Composable
private fun ChatHistoryScreenPreview() = PreviewColumn {
ChatHistoryScreen(...)
}
The dark theme version doesn't fit into the preview window.
To fix this, I thought: why don't we just make the preview wider to fit two copies of the content? We just got access to widthDp and heightDp parameters, let's use it.
First of all, we need a custom @Preview annotation:
@Preview(
heightDp = PhoneScreenHeightDp,
widthDp = PhoneScreenWidthDp * 2,
)
annotation class ScreenPreviewSecond, we need to create a modified version of PreviewHelper for screen size content, and by the way, let's make it a Row to put content side-by-side:
@Composable
fun ScreenPreviewWrapper(
content: @Composable () -> Unit,
) {
Row {
AppTheme(darkTheme = false) {
PreviewContent(
content = content,
modifier = Modifier.width(PhoneScreenWidthDp.dp),
)
}
AppTheme(darkTheme = true) {
PreviewContent(
content = content,
modifier = Modifier.width(PhoneScreenWidthDp.dp),
)
}
}
}And finally, let's use it for our screen:
@ScreenPreview
@Composable
private fun ChatHistoryScreenPreview() = ScreenPreviewWrapper {
ChatHistoryScreen(...)
}Take a look at UI...

[Perfection meme placeholder] 😄
Here is the full version of the preview wrapper that was created. Feel free to use it and leave a comment if you found a better way to achieve the same.