Styling the components
The Fluent UI Web Components are designed to be stylistically flexible, allowing dramatic changes to visual design with minimal code changes. This is possible through the extensive use of Design Tokens and an adaptive color system.
Design Tokens
The following Design Tokens can be used to configure components stylistically.
Light and dark mode
The most common need for setting a token is to switch between light and dark mode.
baseLayerLuminance
: Set toStandardLuminance.DarkMode
to switch into dark mode.
This is a decimal value, and the LightMode
and DarkMode
constants represent the standard points for light and dark mode. You could set it to any value 0
(black) to 1
(white) depending on your needs.
Layers and fill color
The second most common need for manually applying color is to define layers. When you adjust baseLayerLuminance
as above, you're actually adjusting the neutralLayer*
recipe colors.
fillColor
: Sets a value that may be applied to an element's styles and used as context for child color recipes. The default value isneutralLayer1
. Ex: Set toneutralLayer2
for a 'lower' container, like beneath a Card or Accordion.
Important: This token is easy to misuse and we're evaluating a more elegant solution for this common use case:
<div id="myCardContainer">
<fluent-card>
<fluent-button>Hello</fluent-button>
</fluent-card>
...
</div>
const layer = document.getElementById('myCardContainer');
fillColor.setValueFor(layer, neutralLayer2);
#myCardContainer {
background-color: ${fillColor};
}
The details: Avoid setting this to a fixed color value. The scenario above works because the neutral layer recipe colors come from the neutral palette. The fillColor
token is used by most color recipes only as a reference for the luminance (or brightness) context. That's because the recipes are still drawing from their palette, and setting the fillColor
does not change the palette.
Adjust neutral or accent colors
neutralBaseColor
: Set to a custom swatch to use for color recipes for layers and other neutral components.
Ex:SwatchRGB.from(parseColorHexRGB('#A90000')!)
accentBaseColor
: Set to a custom swatch to use for color recipes for accent buttons, checkboxes, etc.
Typography
bodyFont
: Used to specify the font string to apply to components. Note that this does not import fonts, so they must either be web standard, assumed to be installed, or imported at the top of your app.
These tokens and values represent the default Fluent type ramp. The tokens should be used and adjusted relatively. For instance, if the type should be larger overall, increase the size of the entire type ramp instead of restyling a component to use "Plus 1" instead of "base".
Level | Font Size Token Name | Line Height Token Name |
---|---|---|
Minus 2 (smallest) | typeRampMinus2FontSize |
typeRampMinus2LineHeight |
Minus 1 | typeRampMinus1FontSize |
typeRampMinus1LineHeight |
Base (body) | typeRampBaseFontSize |
typeRampBaseLineHeight |
Plus 1 | typeRampPlus1FontSize |
typeRampPlus1LineHeight |
Plus 2 | typeRampPlus2FontSize |
typeRampPlus2LineHeight |
Plus 3 | typeRampPlus3FontSize |
typeRampPlus3LineHeight |
Plus 4 | typeRampPlus4FontSize |
typeRampPlus4LineHeight |
Plus 5 | typeRampPlus5FontSize |
typeRampPlus5LineHeight |
Plus 6 (largest) | typeRampPlus6FontSize |
typeRampPlus6LineHeight |
Sizing
Here are the common sizing tokens you may want to adjust:
controlCornerRadius
: Sets the corner radius used by controls with backplates.
Ex: Increase to6px
for slightly rounder buttons and text fields.layerCornerRadius
: Sets the corner radius used layers like cards, flyouts, and dialogs.
Ex: Increase to20px
for very round cards.density
(in process): A modifier used with sizing tokensbaseHeightMultiplier
andbaseHorizontalSpacingMultiplier
.
Ex: Set to1
to increase control size or-1
to decrease.
These are less common and more nuanced:
baseHeightMultiplier
: This value, multiplied bydesignUnit
, sets the base height of most controls. Works with adaptivedensity
values.baseHorizontalSpacingMultiplier
(future): This value, multiplied bydesignUnit
, sets the internal horizontal padding of most controls. Works with adaptivedensity
values.designUnit
: The unit size of the design grid. Used to calculate height and spacing sizes for controls.
Miscellaneous
Common:
direction
: The primary document direction (LTR or RTL).
Less common:
strokeWidth
: Controls the width of the stroke of a component that has a stroke.focusStrokeWidth
: Controls with width of the stroke of a component that has a stroke when it has document focus.disabledOpacity
: The opacity of disabled controls. Careful with values that are too high as the control may no longer look disabled. There are no contrast requirements for a disabled control.
Adaptive color system
The design tokens are built around an adaptive color system that provides some unique advantages:
- Ensure text meets WCAG contrast requirements.
- Easily swap from light mode to dark, or anywhere in-between.
- Color theming through palette tinting.
- Perceptually uniform UI across background colors.
To accomplish these goals, the web components make heavy use of algorithmic colors called Recipes. Recipes are a combination of an algorithm and input values that produce a desired result. Just as you can bake different types of cookies with different combinations of sugar, butter, flour, and salt, you can produce different design system treatments by altering recipe values (measurements) or algorithms (instructions).
The current base recipes are closely related to their algorithm, but that's a convention and not a requirement. What follows is a list of the algorithms, which function on like-named values. For instance, accentFill
relies on accentFillRestDelta
, accentFillHoverDelta
, accentFillActiveDelta
, and accentFillFocusDelta
.
Recipes are currently used for color values, but they are not limited to that and their usage will be expanded soon.
To better visualize how this works, the FAST team built an application specifically for exploring the system. Check out the Color Explorer.
Common functionality
Most color recipes are based on a palette
. Currently there is built-in support for accent
and neutral
palettes.
Most color recipes take a reference
Swatch
. This is a core concept of Adaptive UI which allows the recipes to vary based on the containing component's color. For instance, supporting a button with consistent treatment between light and dark modes is done with a single recipe.
Many recipes are "stateful", meaning they support rest, hover, active, and focus states for a component.
"Fill" means the recipe is intended to fill a larger area, commonly like a component backplate.
"Foreground" means the recipe is intended for text, icons, or other lightweight decorations where you need or want to meet contrast requirements.
"Stroke" means the recipe is intended for lines, either outline or divider.
Accent algorithms
accentFill
Stateful.
Relies on textColor
and contrastTarget
to find the closest colors from the supplied palette that can be used for component states. For instance, colors needed to support white text and a 14px font (which requires 4.5:1 contrast).
accentForeground
Stateful.
Commonly for link text or icon. Also for smaller elements that might not show up well using accentFill
, for instance if your accent color is dark purple and you support a dark mode interface.
Like accentFill
this relies on textColor
and contrastTarget
to find the closest colors from the supplied palette that can be used for component states.
foregroundOnAccent
Not stateful.
Technically this doesn't use the accent palette, but it's designed to be used over the accent palette. This algorithm simply returns black or white based on the provided contrastTarget
. It returns white if possible, as a common treatment for an accent button is white text over the accent color.
Neutral algorithms
neutralDivider
Not stateful.
Used for decorative dividers that do not need to meet contrast requirements.
neutralFill
Stateful.
The most basic fill used for buttons or other components.
neutralFillContrast
Stateful.
Often Used as a selected state or anywhere you want to draw attention. Meets contrast requirements with the containing background.
neutralFillInput
Stateful.
Another basic fill, applied to input elements to allow easy differentiation from other components like buttons.
neutralFillStealth
Stateful.
More subtle than neutralFill
in that the resting state is transparent. Often used for low-priority features to draw less attention.
neutralForeground
Not stateful.
Most common recipe, used for plain text or icons.
neutralForegroundHint
Not stateful.
Used for subtle text. Meets 4.5:1 minimum contrast requirement.
neutralStroke
Stateful.
Used for strong outline, either alone or with a fill.
Layers
The layer recipes are used for different sections of an app or site. They are designed to be able to stack, but that is not required. When stacked in sequence, the layers will lighten on top of each other.
The key feature of layering is to support the primary container color for light or dark mode. This produces absolute colors based on the baseLayerLuminance
value, which sets the luminance for layer one. This is any value between 0 for black or 1 for white.
The difference between each layer is defined with neutralFillLayerRestDelta
.
Layers are not stateful.
neutralFillLayer
The only layer recipe that's relative to the container color instead of absolute. The most common example of this is a Card, which will be one layer color lighter than its container.
neutralLayer1, neutralLayer2, neutralLayer3, and neutralLayer4
Absolute layer colors derived from and starting at baseLayerLuminance
. Layer one is lightest and the values darken as the layer number increases.
neutralLayerCardContainer
A special layer to support experiences primarily built with cards, especially in light mode, so cards can be white and the container color can be one layer darker.
neutralLayerFloating
A special layer for floating layers, like flyouts or menus. It will be lighter than any other layers if possible, but will also be white in default light mode, as will neutral layer one.
Adaptive Color "Don'ts"
The adaptive color system lives entirely in JavaScript, emitting CSS custom properties for styling purposes where appropriate. This means that you should consider the CSS custom properties emitted by color Design Tokens to be immutable. If you declare the CSS custom property in CSS, the adaptive Color System is unable to know that has happened and components will render with incorrect colors, which can lead to accessibility issues. If you need to change the values for those CSS custom properties, set the value using the DesignToken.setValueFor() API.