-
Notifications
You must be signed in to change notification settings - Fork 114
Overriding Tokens
This document explains how to override tokens from the Fluent Design System using FluentUI's Theming system.
Alias tokens are stored on the FluentTheme object, so they can be overridden by passing an inherited class to alias Token in fluent Theme. Extend AliasTokens class and update complete properties which is then passed to FluentTheme.
//AliasTokens.kt
@Parcelize
open class AliasTokens : Parcelable {
enum class BrandColorTokens {
Color10,
Color20,
Color30,
Color40,
Color50,
Color60,
Color70,
Color80,
Color90,
Color100,
Color110,
Color120,
Color130,
Color140,
Color150,
Color160
}
open val brandColor: TokenSet<BrandColorTokens, Color> by lazy {
TokenSet { token ->
when (token) {
BrandColorTokens.Color10 -> Color(0xFF061724)
BrandColorTokens.Color20 -> Color(0xFF082338)
BrandColorTokens.Color30 -> Color(0xFF0A2E4A)
BrandColorTokens.Color40 -> Color(0xFF0C3B5E)
BrandColorTokens.Color50 -> Color(0xFF0E4775)
BrandColorTokens.Color60 -> Color(0xFF0F548C)
BrandColorTokens.Color70 -> Color(0xFF115EA3)
BrandColorTokens.Color80 -> Color(0xFF0F6CBD)
BrandColorTokens.Color90 -> Color(0xFF2886DE)
BrandColorTokens.Color100 -> Color(0xFF479EF5)
BrandColorTokens.Color110 -> Color(0xFF62ABF5)
BrandColorTokens.Color120 -> Color(0xFF77B7F7)
BrandColorTokens.Color130 -> Color(0xFF96C6FA)
BrandColorTokens.Color140 -> Color(0xFFB4D6FA)
BrandColorTokens.Color150 -> Color(0xFFCFE4FA)
BrandColorTokens.Color160 -> Color(0xFFEBF3FC)
}
}
}
}
// MyAliasTokens.kt
class MyAliasTokens : AliasTokens() {
override val brandColor: TokenSet<BrandColorTokens, Color> by lazy {
TokenSet { token ->
when (token) {
BrandColorTokens.Color10 -> Color(0xFF443168)
BrandColorTokens.Color20 -> Color(0xFF584183)
BrandColorTokens.Color30 -> Color(0xFF430E60)
BrandColorTokens.Color40 -> Color(0xFF7B64A3)
BrandColorTokens.Color50 -> Color(0xFF5B1382)
BrandColorTokens.Color60 -> Color(0xFF6C179A)
BrandColorTokens.Color70 -> Color(0xFF9D87C4)
BrandColorTokens.Color80 -> Color(0xFF7719AA)
BrandColorTokens.Color90 -> Color(0xFF862EB5)
BrandColorTokens.Color100 -> Color(0xFFC0AAE4)
BrandColorTokens.Color110 -> Color(0xFFCEBBED)
BrandColorTokens.Color120 -> Color(0xFFDCCDF6)
BrandColorTokens.Color130 -> Color(0xFFA864CD)
BrandColorTokens.Color140 -> Color(0xFFEADEFF)
BrandColorTokens.Color150 -> Color(0xFFD1ABE6)
BrandColorTokens.Color160 -> Color(0xFFE6D1F2)
}
}
}
}
var aliasTokens by rememberSaveable { mutableStateOf(AliasTokens()) }
FluentTheme(aliasTokens = aliasTokens) {
Column(verticalArrangement = Arrangement.spacedBy(5.dp, Alignment.CenterVertically)) {
Row(
horizontalArrangement = Arrangement.spacedBy(5.dp, Alignment.CenterHorizontally),
modifier = Modifier.fillMaxWidth()
) {
Button(onClick = { aliasTokens = AliasTokens() }, text = "Theme1")
Button(onClick = { aliasTokens = MyAliasTokens() }, text = "Theme2")
}
CreateButtons()
}
}
Like alias tokens, control tokens are stored on the FluentTheme object, so overriding them uses the same mechanism as described in Overriding Global Tokens. These tokens are updated for every control inside the scope of mentioned FluentTheme call.
Another way to update control token is to pass it in the control call itself. This has the benefit of updating only a specific instance of control and not all of them. Similar to methods seen in Overriding Global Tokens, the custom ControlToken object can be created either by sub classing or by updating properties.
@Composable
fun Button(
....
buttonTokens: ButtonTokens? = null,
....
)
App Theme Controller is a singleton object used to handle an app wide theme. Since a theme is combination of global, alias and all control tokens, the app theme controller works by handling these values across activities. FluentTheme's default values are picked from AppThemeController and therefore, using a FluentTheme without customization provides App Theme to the section.
object AppThemeController : ViewModel() {
var aliasTokens: MutableLiveData<AliasTokens> = MutableLiveData(AliasTokens())
var controlTokens: MutableLiveData<ControlTokens> = MutableLiveData(ControlTokens())
fun updateAliasTokens(overrideAliasTokens: AliasTokens) {
aliasTokens.value = overrideAliasTokens
}
fun updateControlTokens(overrideControlTokens: ControlTokens) {
controlTokens.value = overrideControlTokens
}
@Composable
fun observeAliasToken(initial: AliasTokens): State<AliasTokens> {
return this.aliasTokens.observeAsState(initial)
}
@Composable
fun observeControlToken(initial: ControlTokens): State<ControlTokens> {
return this.controlTokens.observeAsState(initial)
}
}
updateAliasTokens(overrideAliasTokens: AliasTokens)
updateControlTokens(overrideControlTokens: ControlTokens)
Note: Control Token customization provided directly to control has the highest priority and so updates via AppThemeController won't be visible there. Similary, if a FluentTheme call is customised, app wide change for that specific token type won't be visible in the section.