-
Notifications
You must be signed in to change notification settings - Fork 168
Design Tokens
This document covers the basics of our design token system and how it is implemented internally. For details of how to customize tokens in your component or app, see Overriding Tokens.
Design tokens come in three tiers.
- Global tokens are effectively friendly names for constants. These have no semantic meaning on their own.
- Example:
grey 64 = #A3A3A3
,medium icon size = 24 pt
- Example:
- Alias tokens are imbued with semantic meaning. They should be derived from global tokens. Color-based alias tokens will have a number variants for different contexts (e.g. light mode, dark mode, high contrast, etc) and may vary from endpoint to endpoint.
- Example:
neutral background 2 = gray 98 @ light, gray 36 @ dark
- Example:
- Control tokens define how a given control draws itself using alias tokens. This is most likely to be defined in a platform-specific manner.
- Example:
button background = neutral background 2
Our Swift representation of tokens will reflect his hierarchy, with a unidirectional dependency hierarchy. Controls should only depend on Control tokens, without ever directly referring to an alias or global token.
- Example:
For more information, see the official documentation for Fluent 2 design tokens here: https://fluent2.microsoft.design/design-tokens.
Let’s start with the basic definition of our global tokens. Below is a sample subset of the usage of various types of global tokens.
import SwiftUI
import FluentUI
let darkGrey = GlobalTokens.neutralSwiftUIColor(.grey94) // Color, #F0F0F0
let smallCornerRadius = GlobalTokens.corner(.radius20) // CGFloat, 2.0
These read-only tokens can be accessed via both Swift and Objective-C using the provided static lookup functions in GlobalTokens.swift
. However, because these values are completely unaware of their rendering context, you will usually build UI using Alias Tokens.
Alias tokens reference global tokens whenever possible. Their goal is to provide semantic meaning for the raw values defined in the global system.
These values are stored on a category of FluentTheme
so they can be easily accessed from any theme object. These are the values that most UI should be built using, paired with Global Tokens when appropriate for dimensional values such as spacing and line widths.
import SwiftUI
import FluentUI
struct MyView: View {
@Environment(.\fluentTheme) var fluentTheme: FluentTheme
var body: some View {
let backgroundColor = fluentTheme.swiftUIColor(.background1)
let foregroundColor = fluentTheme.swiftUIColor(.brandForeground1)
let cornerRadius = GlobalTokens.corner(.radius20)
// Create some view with these values
Text("I'm a text label!")
.foregroundStyle(foregroundColor)
.background(backgroundColor)
.clipShape(RoundedRect(cornerRadius: cornerRadius))
}
}
Control token sets are simply the collection of tokens used by a single control. These should utilize alias tokens whenever possible, though it may be necessary to reference a global token in cases where no such alias exists.
A default implementation of the component’s theme will exist alongside the component, providing clients the opportunity to subclass and provide custom values for these tokens. Custom Control tokens can be provided for any control either upon instantiation or after presentation via a public property.
Tokens for controls contained within another control should be defined in the hosting control’s tokens as optional, then passed down as a custom subclass of the contained control’s tokens to the contained control through override tokens.
open class ListTokens: ControlTokens {
open var dividerColor: DynamicColor? { nil }
}
private class CustomDividerTokens: DividerTokens {
var listTokens: ListTokens
init (listTokens: ListTokens) {
self.listTokens = listTokens
super.init()
}
override var color: DynamicColor {
listTokens.dividerColor ?? super.color
}
}
As an app, the first step towards providing a custom Fluent UI appearance for your app is to provide custom tokens for the control that you wish to override. Want to change button corner radii? Set custom values into your button instances' tokenSet
property.
However, there is another way to set properties more globally: FluentTheme
.
FluentTheme
represent a way to group together a custom set of alias and control tokens. Custom themes can be applied in one of two ways: globally, which applies to the entire application, or on a specific branch of the view hierarchy, including the root view or parent UIWindow
.
FluentUI
also supports applying both at once, so you can have a standard custom theme for your application, with one or more additional custom themes for specific windows or views.
For more details, see Applying a Custom FluentTheme.