Custom Themes
In this guide, you will learn how to create fully custom themes and how to use them to maintain consistent styling in your Compose apps.
Create a theme
To create a theme, use the buildTheme { }
function.
val MyTheme = buildTheme { }
It returns a theming @Composable
that you can use to wrap your app with:
@Composable
fun App() {
MyTheme {
Box(Modifier.fillMaxSize()) {
Text("My awesome app")
}
}
}
The theming function we just created forwards any styling properties to its children.
Children can access those properties 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:
Customize your theme
Let's define some colors. To do this, let's create a colors property that will hold some color tokens:
val colors = ThemeProperty<Color>("colors")
val background = ThemeToken<Color>("background")
val onBackground = ThemeToken<Color>("on_background")
val MyTheme = buildTheme {
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
buildTheme
is not a@Composable
function, the scope it provides for defining your properties is. This is handy for when you need to load properties asynchronously without blocking your app (such as loading fonts) and creating dynamic themes.
Styling your app using your theme
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])) {
Text("My awesome app", color = Theme[colors][onBackground])
}
}
}
And that's the gist. You now know how to create custom themes, customize them with the properties you need, and use them in your app.
Default properties
Compose Unstyled themes come with some default properties you can set to style your app.
Content Color
Sets the default Color
used by all Unstyled components to render their content.
val MyTheme = buildTheme {
defaultContentColor = Color(0XFF0C0A09)
}
Text Style
Sets the default TextStyle
used by Text and TextField components to render their text contents.
val MyTheme = buildTheme {
defaultTextStyle = TextStyle(
fontWeight = FontWeight.Medium,
fontSize = 16.sp
)
}
Indication
Sets the default Indication
used by interactive elements such as buttons and clickables. This is the same as providing an Indication
value for the LocalIndication
.
import com.composeunstyled.theme.rememberColoredIndication
val MyTheme = buildTheme {
defaultIndication = rememberColoredIndication(
hoveredColor = Color.White.copy(alpha = 0.3f),
pressedColor = Color.White.copy(alpha = 0.5f),
focusedColor = Color.Black.copy(alpha = 0.1f),
)
}
TextSelectionColors
Controls the colors used by text and text fields for text selection. This is the same as providing a TextSelectionColors
value for the LocalTextSelectionColors
.
val MyTheme = buildTheme {
defaultTextSelectionColors = TextSelectionColors(
handleColor = Color.Blue,
backgroundColor = Color.Blue.copy(alpha = 0.4f)
)
}
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 = buildTheme {
name = "LightTheme"
}