# How to change themes programmatically in Jetpack Compose

> As easy as 1..2..3

Published 30 March 2023 by Alex Styl.

Happy Thursday! Alex here 👋

Following last week's tutorial about themes in Jetpack Compose, this week we are going through how to change themes via code.

Let's jump straight to it 🚀

## Define light and dark themes

Here is a slim down version of the theme generated when you create a new Jetpack Compose project in Android Studio:

```kotlin
@Composable
fun MyAppTheme(
    isDarkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit,
) {
    val colorScheme = if (isDarkTheme) darkColorScheme() else lightColorScheme()

    MaterialTheme(
        colorScheme = colorScheme,
        // shapes = ...,
        // typography = ...,
        content = content
    )
}
```

The above composable defines a new theme. It will update the look and feel of the children composable passed to _content_.

Note the `isSystemInDarkTheme()` function. As soon as the user changes their system wide theme preference (from light to dark and vise versa),
this function will automatically give you a new `Boolean` representing their preference.

Depending on the value emitted, we are using either the dark or the light color scheme. This is the way Jetpack Compose knows when it is time to update the UI and use dark or light color theme.

## Change themes programmatically

Instead of relying on the `isSystemInDarkTheme()` function to pick a light or dark theme, we can expect the user of the `MyAppTheme` to provide the _isDarkTheme_ value instead.

```kotlin
var isDarkTheme by remember { mutableStateOf(true) }

MyAppTheme(isDarkTheme = isDarkTheme) {
    Scaffold {
        Row(
            verticalAlignment = Alignment.CenterVertically,
            modifier = Modifier
                .fillMaxWidth()
                .padding(
                    horizontal = 16.dp,
                    vertical = 10.dp
                ),
            horizontalArrangement = Arrangement.spacedBy(8.dp)
        ) {
            Text("☀️")
            Switch(
                checked = isDarkTheme,
                onCheckedChange = {
                    isDarkTheme = it
                }
            )
            Text("🌘")
        }
    }
}
```

![Switch the theme from light to dark using a Switch](https://composables.com/blog-assets/static/images/lightdark.gif)

## Bonus 🎁: Implement the On/Off/System user setting for themes

You can take this a step further and introduce a third state for the user. You can let them decide if they want the app to be light, dark or follow the system wide theme.

Here is how to implement this:

```kotlin
var appTheme by remember { mutableStateOf(AppTheme.System) }

MyAppTheme(
    isDarkTheme = when (appTheme) {
        AppTheme.Light -> false
        AppTheme.Dark -> true
        AppTheme.System -> isSystemInDarkTheme()
    }
) {
    Scaffold {
        Column {
            LabeledRadioButton(
                label = "☀️",
                selected = appTheme == AppTheme.Light,
                onClick = {
                    appTheme = AppTheme.Light
                }
            )
            LabeledRadioButton(
                label = "🌘",
                selected = appTheme == AppTheme.Dark,
                onClick = {
                    appTheme = AppTheme.Dark
                }
            )
            LabeledRadioButton(
                label = "🤖",
                selected = appTheme == AppTheme.System,
                onClick = {
                    appTheme = AppTheme.System
                }
            )
        }
    }
}
```

To simplify the code sample I created a composable that combines some Text and a Radio button:

```kotlin
@Composable
fun LabeledRadioButton(
    selected: Boolean,
    onClick: () -> Unit,
    label: String,
) {
    Row(
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.spacedBy(8.dp)
    ) {
        RadioButton(
            selected = selected,
            onClick = onClick
        )
        Text(label)
    }
}
```

![Switch light, dark and system setting](https://composables.com/blog-assets/static/images/systemswitch.gif)

PS: You would need to persist the theme selected. You can either use [SharedPreferences](https://developer.android.com/training/data-storage/shared-preferences) or [Data Store](https://developer.android.com/jetpack/androidx/releases/datastore) to do this. I personally like DataStore more as it exposes Kotlin `Flows` instead of callbacks.

That's all for today.

Until the next one,

Alex
