Custom Themes
Learn how to create fully custom themes and how to use them to maintain consistent styling in your Jetpack Compose apps.
View MarkdownInstallation
Include the Theming module in your app’s dependencies:
implementation("com.composables:composeunstyled-theming:2.9.2")Create a theme
To create a theme, use the buildThemeV2 { } function.
Note
buildTheme {}also exists for compatibility with existing themes.buildThemeV2 {}adds color-scheme support and is recommended for new themes.
val MyTheme = buildThemeV2 {
name = "MyTheme"
}It returns a theme that you can invoke as a composable to wrap your app with:
@Composable
fun App() {
MyTheme {
Box(Modifier.fillMaxSize()) {
BasicText("My awesome app")
}
}
}To define light, dark, or custom variants of this theme, see Color Schemes.
The theme makes the values you define available to its content.
Content can access those values using the Theme object. Those are usually colors, typography, shapes
and anything you need to style your apps with.
But we haven’t defined any, so let’s do that next:
Define theme values
Let’s define some colors. To do this, let’s create a ‘colors’ theme property.
Theme Properties hold a Map of theme tokens. This links the tokens to the actual values.
val colors = ThemeProperty<Color>("colors")
val background = ThemeToken<Color>("background")
val onBackground = ThemeToken<Color>("on_background")
val MyTheme = buildThemeV2 {
properties[colors] = mapOf(
background to Color(0xFFFAFAFA),
onBackground to Color(0XFF0C0A09),
)
}Compose Unstyled does not force the structure of your themes and does not come with default styling options that you will end up removing afterwards.
You can create any kind of properties you need that fit your design needs.
Even though
buildThemeV2is not a@Composablefunction, the scope it provides for defining your properties is. This is handy for when you need to prepare properties asynchronously without blocking the UI thread (such as loading fonts) and creating dynamic themes.
Reading theme values
We can now style our app using the Theme object to access the values for each token:
@Composable
fun App() {
MyTheme {
Box(Modifier.fillMaxSize().background(Theme[colors][background])) {
BasicText("My awesome app", style = TextStyle(color = Theme[colors][onBackground]))
}
}
}To set defaults for theme content or override values for a subtree, see Theme Values.
Debugging your theme
Unstyled will throw an exception when you try to access a token that is not present in the current theme.
To make it simpler to debug such scenarios, it is highly recommended to name your themes when you create them.
By doing so, Unstyled will provide descriptive error messages when you try to access a token that does not exist during runtime.
val LightTheme = buildThemeV2 {
name = "LightTheme"
}