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 to StandardLuminance.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 is neutralLayer1. Ex: Set to neutralLayer2 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 to 6px for slightly rounder buttons and text fields.
  • layerCornerRadius: Sets the corner radius used layers like cards, flyouts, and dialogs.
    Ex: Increase to 20px for very round cards.
  • density (in process): A modifier used with sizing tokens baseHeightMultiplier and baseHorizontalSpacingMultiplier.
    Ex: Set to 1 to increase control size or -1 to decrease.

These are less common and more nuanced:

  • baseHeightMultiplier: This value, multiplied by designUnit, sets the base height of most controls. Works with adaptive density values.
  • baseHorizontalSpacingMultiplier (future): This value, multiplied by designUnit, sets the internal horizontal padding of most controls. Works with adaptive density 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.

Next steps