Keeping Things Organized

Scaling the Microsoft Teams Component Libraries (TCL) in Figma

Josh Cusick
Inside Designing Microsoft Teams
18 min readOct 22, 2021

--

Illustration by Devansh Parikh for this article

The Teams Component Libraries (TCL) are the Figma UI kits that adopt Fluent UI components but are themed and customized for Microsoft Teams. TCL contains four kits, covering every platform type.

This is a prescriptive article and resource that highlights how the TCL — Web & Desktop kit was built, how it is maintained, and the parameters we set up for people to contribute.

We will cover the following topics:

  1. Structuring pages
  2. Naming things
  3. Aligning with code
  4. Design tokens
  5. Version control

1. Structuring pages

When deciding how to structure our pages the following priorities were considered:

  1. We must provide clear component location endpoints.
  2. We must make it easy to import components.
  3. We must provide clear health status indicators of components at said endpoints.

The conclusion was that each component should get its own page. This makes it easier for designers to scan a page and quickly copy what they were looking for, rather than trying to visually filter out what they don’t need. The status of a component is at the top level and the designer can see this before even importing. These ideas came from aligning closer to code.

Figma UI showing page names ordered from A to Z with colored emojis at the end of each page name.
Example showing pages in Figma sorted from A-Z and health indicators

A common file structure practice in React or TypeScript is to group by file type where each component has its own subfolder nested inside a parent folder like this:

src/components/Button/Button.tsx

💡 Note: src means “source.”

Github UI showing Fluent UI’s repository of components.
In Fluent’s GitHub repo, components each have their folder and are sorted from A-Z

Page status indicators

The name of each component page has a status emoji at the end.

  • Green (🟢) means all good and the component is healthy and ready to use.
  • Yellow (🟡) means that the component can be used but exercise caution as it is being worked on.
  • Red (🔴) means do not use under any circumstances; the component is unstable.

2. Naming things

The goal is to have a 1:1 component naming parity with code, but there are a few rare exceptions. This principle helps designers and engineers easily communicate with each other and identify what goes where. There are a few guiding naming conventions that are used and helped inspire our naming structures. Let’s review BEM and PascalCase:

BEM

BEM stands for block, element, modifier.

Breaking this down:

  • Block: a standalone entity that is meaningful on its own. Examples: header, container, menu, checkbox, input .
  • Element: a part of a block that has no standalone meaning and is semantically tied to its block. Examples: menu item, list item, checkbox caption, header title
  • Modifier: a flag on a block or element. Use them to change appearance or behavior. Examples: disabled, highlighted, checked, fixed, size big, color yellow

We don’t use BEM literally, more as an inspiration. If you want to learn more about how BEM works, go to http://getbem.com/.

PascalCase

PascalCase is a naming convention in which the first letter of each word in a compound word is capitalized.

“Software developers often use PascalCase when writing source code to name functions, classes, and other objects. PascalCase is similar to camelCase, except the first letter in PascalCase is always capitalized.”

-Techterms.com

We use PascalCase when naming components.

Layers and subcomponents

We name layers and subcomponents to communicate semantic meaning specifically to designers and contributors to TCL. Avoid trying to map layers to CSS classes since the web implementation will not always mirror the design.

To explain how we name layers and subcomponents, let’s start with a simple example. Here is the Button component:

Button component in Figma UI
Button component in Figma

Because we have 240 variants of Button inside of Figma, we have created a subcomponent.

A subcomponent contains all the necessary content for a component to function properly while allowing for global, sweeping changes across multiple instances.

Since we do not want this subcomponent to be available to the end-user (other designers) we prepend the name with a period and title it .Base.

If we were to have multiple subcomponents we would enumerate starting at 1 e.g. .Base1 , .Base2 , .Base3 , etc…

“To prevent Figma from publishing your styles and components, you can add a prefix or modifier to the component’s name in the layers panel.

Figma will skip over these styles and components during the publishing process and list them in the Private to this file sections of the Assets panel and library modal.

• Add a period . in front of the component layer's name.

• Add an underscore _ to the beginning of the component layer's name.”

-Figma.com

If we wanted to make the subcomponent available to users we would not append with a period nor use the .Base method.

Rather, we would use what is in code and if that name is not available, we’d semantically name the component.

For example, in code, we do not have a subheader component for the DatepickerCalender but we do have a DatepickerCalenderHeader component. So, we’d take the lead from that component’s name and call our subheader DatepickerCalenderSubheader.

DatepickerCalenderSubheader component in Figma UI
DatepickerCalenderSubheader component in Figma

Continuing with our Button example, we start with .Base nested in Button

Layers in Figma UI showing the subcomponent for Button called “.Base”
The subcomponent inside Button is called .Base

Let’s drill down again…

Layers in Figma UI showing the layers for “.Base”
The content inside the .Base subcomponent

The Button requires min-width: 96px for the medium-sized variant so we added two fixed-width vectors, one at the top and one at the bottom. The fallback name for anything that does not fit the naming convention is:

"Vector"-[description]

When using auto layout frames we structure the name like this:

[Element]-[element]-[element]-"stack"

💡 Note:

  • Use sentence casing; only capitalize the first word in the list of items.
  • Limit the number of element names to three. If there are more than three do not write them in the name.

When we look inside the Icons-string-loader-stack we see a few things:

Layers panel in Figma UI showing the layers inside “Icons-string-loader-stack”
Button layers in Figma Layers panel
  • The first element is an IconContainer which is a custom component built to handle style overrides and wraps the Icon component. Since there are two of the same component and it technically is just Icon, we group these and get the first part of the name — Icons.
  • The second element is a text layer. We structure the name of text layers like this:
"String"

or if multiple text layers are present, we append the name like:

"String"-[description]

e.g. Sting-title. We now have the second part of the name — Icons-string.

  • The third and final element in the stack is a frame called Loader-container that wraps a component called Loader. We will now add this to the end of our stack’s name and calling it Icons-string-loader-stack.

💡 Note: When using a frame with no auto layout in Figma, structure the name like this:

[Description]-"container"

3. Aligning with code

Aligning our Figma components beyond just their names with our coded components furthers our mission for 1:1 parity with code. These efforts continue to drive shared context between designers and engineers: this is critical for an elevated experience of both parties. By creating a common language with code and developers we reduce the deltas between design and product.

Before we continue, let’s review some key terminology:

API

The term API is an acronym, and it stands for “application programming interface.”

“Think of an API like a menu in a restaurant. The menu provides a list of dishes you can order, along with a description of each dish. When you specify what menu items you want, the restaurant’s kitchen does the work and provides you with some finished dishes. You don’t know exactly how the restaurant prepares that food, and you don’t really need to.”

-Howtogeek.com

Button controls inside Figma UI varaints panel
Button API in Figma

Props

Props (properties) or variants as Figma calls them are the inputs that each component is equipped with and define the component’s capabilities.

“Conceptually, components are like JavaScript functions. They accept arbitrary inputs (called “props”) and return React elements describing what should appear on the screen.”

- Reactjs.org

Button controls inside Figma UI variants panel highlighting all the props
Button props in Figma

Boolean

A boolean is a true or false data type.

“A boolean or bool is a data type with two possible values: true or false. It is named after the English mathematician and logician George Boole, whose algebraic and logical systems are used in all modern digital computers.”

- Computerhope.com

Button controls inside Figma UI variants panel highlighting the “Loading” prop
The Button “Loading” prop is a boolean

Enum

An enum represents a group of constraints or unchangeable variables.

“In computer programming, an enumerated type (also called enumeration or enum [..]) is a data type consisting of a set of named values called elements, members or enumerators of the type. The enumerator names are usually identifiers that behave as constants in the language.”

- Treehozz.com

Button controls inside Figma UI variants panel highlighting the “Appearance” prop
The Button “Appearance” prop is an enum

Now that we’ve covered some key terms, we are ready to dig into an example.

Button example

In the example below we are looking at the Button component inside of Figma. On the right side of the image, you will see the list of available props that a user can select.

Button component inside Figma UI
Example of the Button component with props visible in Figma
Button component in live code playground
Example of the Button component in our internal doc site

Ideally, our Figma components’ APIs are 1:1 with code, but this is not always the case. Here are a few situations where we deviate:

  • Enums vs. booleans — Sometimes it makes sense to group an array of choices versus offering several true or false options. For example, the coded version of Button accepts boolean values for appearance styles such as primary={true} or inverted={true} , our Figma version of Button has a single prop called Appearance that can take a value of "Default" , "Primary" , "Outline" , "Subtle" , or "Inverted" .
Button controls inside Figma UI variants panel highlighting the “Appearance” prop
Button “Appearance” prop values in Figma
  • Prop name vs. propName — We choose to format the name of props slightly differently than our coded counterparts. For example, in code Button has a prop called iconPosition which can take values. But in Figma, we capitalize the first word and use a space. So, Button in Figma has a prop called Icon position that can take values. This makes the component more friendly and easy to parse for designers.
Button controls inside Figma UI variants panel highlighting the “Icon position” prop
Button “Icon position” prop in Figma
  • Sentence casing vs. lowercasing — We always capitalize the first word of a prop or prop value. For example, in code Button has an enum prop called size that can take a value of "small" or "medium" . Our Figma version of Button has an enum prop called Size that can take a value of "Small" or "Medium" . Again, more design-centric and easier to read.
Button controls inside Figma UI variants panel highlighting the “Size” prop
Button “Size” prop in Figma
  • Showing props vs. not showing props Props are not always applicable across design and code. For example, in our Figma version of Button, we use an enum prop called State that can take a value of "Rest" , "Hover" , "Pressed" , "Active" , "Focus" , or "Disabled". This logic is not applicable in code, rather the coded version only has two boolean props called disabled and disabledFocusable. For designers to use Button in their flows and mocks, they require all available states.
Button controls inside Figma UI variants panel highlighting the “State” prop
Button State prop values in Figma
  • Most options vs. all options — due to technical constraints in Figma and to limit the payload, we sometimes create additional components instead of a single massive component. For example, in code, Button has a boolean prop called iconOnly which renders only an Icon and no text string. In Figma there are two separate components: Button and IconButton .
IconButton inside Figma UI
IconButton in Figma

The “position” prop

The position prop defines where the position of a child node is placed in relation to its parent. We structure the name of this prop like:

[Element] "position"

or

"Position"

Either is acceptable. The reason we chose to use Position rather than Menu position in Menu , is because in code the prop that is passed is called position .

Let’s look at the MenuButton example in Figma:

MenuButton inside Figma UI
MenuButton in Figma

The MenuButton has an enum prop called Position that can accept a value of "-" , "Above" , "Below" , "Before" , or "After" , this prop defines the placement of the Menu nested in MenuButton.

MenuButton controls inside Figma UI variants panel highlighting the “Position” prop
MenuButton “Position” prop in Figma

Below is a chart of how we rank and name the options for a prop defining position in such a component. When setting values for an enum prop in Figma, we usually need to set a default value of "-" when the prop is not applicable, such as when the Menu is not open.

Chart of how the position prop is ranked and what values are passed to it
Chart of how the position prop is ranked and what values are passed to it
  1. The first option is "-" : this means null , or the absence of a value. When the Open prop is False meaning Menu is not opened, this is the fallback value.
  2. The second option is "Above" : when true, the node is placed above the component.
  3. The third option is "Below" : when true, the node is placed below the component.
  4. The fourth option is "Before" : when true, the node is placed before the component.
  5. The fifth option is "After" : when true, the node is placed after the component.

The “align” prop

The align prop defines how a child node is aligned to its parent. We structure the name of this prop like:

[Child] "align"

or

"Align"

Either is acceptable. The reason we chose to use Align rather than Menu align in MenuButton is because in code the prop that is passed is called align .

The aligned prop usually goes hand-in-hand with the position prop.

MenuButton controls inside Figma UI variants panel highlighting the “Align” prop
MenuButton Align prop values example in Figma

Below is a chart of how the align prop works. Depending on where a node is placed in relation to another node, we will either use the term “Start” or “End.”

Graphic depicting how the align prop works and what values are passed to it
Graphic depicting how the align prop works and what values are passed to it

4. Design tokens

Design tokens are essential to iterate quickly, design within defined parameters, and of course, align to code.

“Design tokens are the visual design atoms of the design system — specifically, they are named entities that store visual design attributes. We use them in place of hard-coded values (such as hex values for color or pixel values for spacing) in order to maintain a scalable and consistent visual system for UI development.”

- Lightning Design System

Tokens in code

We strive to stay in sync with our live design tokens. In code, we support three themes: light theme, dark theme, and high-contrast theme.

Table showing the design tokens for Fluent UI
Design tokens table in internal Fluent UI doc site

There are a few types of design color tokens in code, but we will focus on the alias design tokens.

Alias design tokens are context-driven tokens.

Alias color tokens’ names in code are structured like:

[color].[surface][enum]

In design-speak? This just means that we would start with the name of the color, we would then add a period, and then we would add the name of the surface this token is for. Typically the surface is only a foreground or background, although there are some exceptions.

The word “enum” at the end means that if we have more than one token we can enumerate, starting at 0. We don’t actually write “0” though. We would append tokens starting after the first with “1” and count up.

Let’s continue…

When using a token for a state like :hover it would be structured like this:

[color].[surface].["Hover" | "Pressed" | "Active" | "Focus" | "Disabled"][enum]

💡Note: a pipe (| ) simply means “or.”

“Union types in Typescript allows a variable to have the ability to store a value of several types. We define union types by using a pipe (|) to separate each of the possible types. Hence, number | string | boolean is the type of a variable, which can have the value that can be a number, a string, or a boolean .”

-Tektutorialshub.com

Tokens in Figma

Two themes are supported in Figma: light theme and dark theme. The tokens nested in either the 🌕 Light theme or 🌑 Dark theme folders are 1:1 with each other. Meaning the only difference is the actual HEX or RGBA value. This allows for theme switching with our plugin or manual token swapping.

Microsoft Teams Power Pack Figma plugin UI
Teams Power Pack Figma plugin

Color design tokens

Let’s take a look at an example. All of the tokens in Figma mirror the tokens in code. So we start with our doc site.

Table showing the design tokens for Fluent UI
Design tokens in internal Fluent UI doc site

The two things we need to pay attention to are the palette name, in this case, that is “brand” and the token name, which is “Background.” Let’s transcribe this to Figma.

How tokens are named in Figma:

[Color palette] [Token name]
Figma UI color picker showing the saved value called “Brand Background”
Brand Background alias token for rest state example in Figma

Notice we capitalized “Brand.”

The same goes for state-based tokens like Brand Background Hover . We just take the literal name from the doc site…

Figma UI color picker showing the saved value called “Brand Background Hover”
Brand Background Hover alias token for hover state example in Figma

A high-level overview of our color token organizational structure in Figma:

[Theme] / [State] / [Surface] / [Token]

More specifically…

["🌕 Light theme" | "🌑 Dark theme"] / ["Rest" | "Hover" | "Pressed" | "Active" | "Focus" | "Disabled"] / ["Foreground" | "Background" | "Border"] / [Token Name]

💡 Note: There are two exemptions to this convention though: the “Loading” and “Component styles” subfolders. More on that below.

At the top-most level lives the themes 🌕 Light theme and 🌑 Dark theme .

Parent folders in Figma

Drilling down under 🌕 Light theme live the states. These are the six subfolders each named by state:

  1. Rest : tokens for default color — e.g. the background-color for Button at its primitive state with no current or pending interaction.
  2. Hover : tokens for hover-context colors — e.g. the background-color for Button being hovered by a mouse cursor.
  3. Pressed : tokens that for pressed-context colors — e.g the background- color forButton on mouse click.
  4. Active : tokens for active-context or “selected” colors — e.g the background-color for ToggleButton when selected.
  5. Focus : tokens for focus-context colors — e.g. the focus-ring for Button when a screenreader is focused on it.
  6. Disabled: tokens for disabled-context colors — e.g the background-color for Button when disabled.
Figma UI Color Styles panel showing 8 folders called “Rest”, “Hover”,”Pressed”, “Active”, “Focus”, “Disabled”, “Loading”, and “Component styles.”
State-based subfolders in Figma

The bottom two subfolders below the state-based ones are:

  1. Loading: tokens for loading-specific components that require gradients such as Skeleton and Loader . Because of limitations in Figma such not being able to point gradient tokens to multiple variables, these are not 1:1 with code and specific only to our local styles in Figma. The end result is the same but the tokens do not match.
  2. Component styles: tokens used locally to build components such as the shadows in AppBar and ScrollBar .

💡 Note: the naming conventions in the Loading and Component styles folders are not finalized and may be subject to change.

Figma UI Color Styles panel showing 8 folders called “Rest”, “Hover”,”Pressed”, “Active”, “Focus”, “Disabled”, “Loading”, and “Component styles.”
“Loading” and “Component styles” subfolders in Figma

Nested inside each of the state-based subfolders are one of three subfolders contextual to the surface type:

  1. Foreground : tokens for foreground elements such as color for a text span
  2. Background : tokens for background elements such background-color for Button
  3. Border : tokens for borders such as border-color for Card
Figma UI Color Styles panel showing folders called “Foreground”, “Background”, and “Border.”
“Foreground”, “Background”, and “Border” subfolders in Figma

Finally, nested in each surface-type subfolder are the alias color tokens. Tokens are sorted as follows:

  1. Default
  2. Silver
  3. Brand
  4. Red
  5. Orange
  6. Yellow
  7. Green
  8. Pink
  9. Onyx

💡 Note: each token group is sorted starting at 0 (remember when 0 no number is appended to the token name). Not all tokens are available in Figma from code as they are added as uses are identified.

Alias color tokens inside the “Border” subfolder in Figma UI
Alias color tokens inside the “Border” subfolder in Figma

Shadow tokens

The shadow or “elevation” story is being revamped for new versions of Fluent UI which TCL will snap to. Currently, we name our shadows like this:

"shadow"-[enum]

and if the shadow is pointing in another direction other than down we name the token like this:

"shadow"-["up" | "left" | "right"]-[enum]

We start at “2” and work up to “32.” Shadows mimic the z-index, meaning that shadow-2 is a lower z-index than shadow-16 .

Shadow tokens inside Figma UI
Shadow tokens in Figma

Typography tokens

Again, due to some limitations in Figma, we sort our typestyles a bit differently than code. New ordering is in the works.

Currently, we have six folders, sorted from smallest font size to largest font size, with a local styles folder at the end:

  1. Smaller
  2. Small
  3. Medium
  4. Large
  5. Larger
  6. Component styles
Text style tokens inside Figma UI

In each folder, styles are named like:

[weight number]

and if it is italic or underlined we name it like this:

[weight number] ["italic" | "underlined"]

They are sorted from the lowest number to the highest number.

Text style tokens inside Figma UI

5. Version control

Semantic Versioning or SemVer, in short, is a versioning system to incrementally organize published versions of a project. This is most common for engineers or software developers, but we have borrowed some of the principles for our Figma kit. The numbering is structured like this:

[Major].[Minor].[Patch]
  • Major: these are massive versions, sweeping and breaking changes. This occurs typically only once a year, such as rebuilding a bunch of new components to align with a new Figma release.
  • Minor: these are scheduled to occur on the last Friday of every month, usually a batch of new components or significant non-breaking component updates are grouped and released under this version.
  • Patch: these are scheduled every Friday, except for the last Friday of the month. They include mostly bug fixes or small changes.
Figma file cover pointing to the version number
Figma file cover pointing to the version number

Communicating versions

There are three ways we communicate new versions to users:

  • Release notes in Figma: before we hit that “Publish” button, we type our release notes in the input box inside the Figma publishing window.
Figma publishing window
Figma publishing window
  • Changelog page in Figma: in Figma, there is a page titled “Changelog”, on that page we post our release notes.
  • Design Systems Teams channel: to provide transparency and quick access to components that were added, modified, or moved to the Graveyard we post our release notes in a Teams channel.
Release notes published in Microsoft Teams

Here is how we structure the release notes:

Teams Component Library Update: (TCL [date])-[V#]🎉  What’s New• [Component name with link] component
• [Component name with link] component
• [Component name with link] component
🛠 What’s Modified• Bug fix for [Component name with link]
• Thing updated for [Component name with link]
⚰️ What’s Moved to Graveyard• Old [Component name with link] component
• Old [Component name with link] component
• Old [Component name with link] component

Deprecating old components

When the time comes to deprecate old components, we do the following:

  1. Select the component to deprecate a move it to the page called “Graveyard.”
  2. Change the name to:
[Current name] / "⚠️ DEPRECATED MIGRATE TO NEW VERSION ⚠"
Figma UI dialog renaming multiple components to be deprecated.
For multiple components that are being deprecated, we can select them all at once and rename them

3. When publishing a new version add this component to the “⚰️ Moved to graveyard” section.

Final thoughts

Thank you for taking the time to read this article, many hours were put into making it consumable and digestible for designers. Future versions are being planned. Stay tuned for updates by following this publication on Medium and show your support by clicking 👏 the “clap” button.

Glossary

  • API: an acronym that stands for “application programming interface”
  • Auto layout: similar to CSS flexbox, auto layout is a property in Figma that you can add to frames and components. It lets you create designs that grow to fill or shrink to fit, and reflow as their contents change.
  • BEM: an acronym that stands for “block element modifier”
  • Boolean: a true or false data type
  • Design tokens: the visual design atoms of the design system — specifically, they are named entities that store visual design attributes.
  • Enum: a group of constraints or unchangeable variables.
  • Prop: arguments passed into React components.
  • Semantic Versioning: semantic and incremental versioning that takes place in the form of [Major].[Minor].[Patch] .
  • Subcomponent: a component that contains all the necessary content for its parent component to function properly while allowing for global, sweeping changes across multiple instances.

Sources

  1. BEM — Block Element Modifier. (n.d.). Get BEM. http://getbem.com/
  2. Computer Hope. (2021, February 1). What is a Boolean? https://www.computerhope.com/jargon/b/boolean.htm
  3. Facebook Inc. (n.d.). Components and Props –. React — A JavaScript Library for Building User Interfaces. https://reactjs.org/docs/components-and-props.html#:%7E:text=Conceptually,%20components%20are%20like%20JavaScript%20functions.%20They%20accept%20arbitrary%20inputs%20(called%20%E2%80%9Cprops%E2%80%9D)%20and%20return%20React%20elements%20describing%20what%20should%20appear%20on%20the%20screen.
  4. Figma. (n.d.). Create dynamic designs with auto layout. https://help.figma.com/hc/en-us/articles/360040451373-Create-dynamic-designs-with-Auto-Layout
  5. Hoffman, C. (2021, August 13). What Is an API, and How Do Developers Use Them? How-To Geek. https://www.howtogeek.com/343877/what-is-an-api/
  6. Tree Hozz. (2020, March 1). What is an enum in Javascript? https://treehozz.com/what-is-an-enum-in-javascript

--

--