---
# System prepended metadata

title: Vertical Apps - V9 Migration

---

# Vertical Apps - V9 Migration

The purpose of this design doc is to present and describe the different decisions and research required to achieve a smooth migration from Fluent UI Northstar (v0) to Fluent UI v9 in the Teams verticals monorepo.

## Encapsulating v9 usage

The verticals repository has all reusable UI code in the `@microsoft/modernworkplace-ui-core` repo. All northstar exports are done through `@microsoft/modernworkplace-ui-core/src/components/northstar`. Although the deep import is considered an antipattern in the JS ecosystem, the good thing is that this import is used consistently throughout.

We can simply create a new export path `@microsoft/modernworkplace-ui-core/src/components/fluentui`  as the primary export path of v9 components and do a gradual migration.

The existence of this export path if no code is used should not impact any of the production code.

## Styling 

Currently the packages inside the verticals apps repo are using `mergeStyleSets` from `@uifabric`:

```javascript
import { mergeStyleSets } from "@uifabric/merge-styles";
```

It's convenient, since the syntax is very similar to `@griffel`

All style files are under the pattern `ComponentName.styles.ts`, what can facilitate automation with codemodes. 

Let's take the `FacePile` styles for example, currently we have:

```typescript
import { avatarClassName, pxToRem } from "@fluentui/react-northstar";
import { mergeStyleSets } from "@uifabric/merge-styles";

import { ComponentClassNames } from "../../styles/classNames";

type IFacePileClasses = ComponentClassNames<"facePile" | "userName">;

/**
 * Get class names.
 * @returns Class names.
 */
export const getClassNames = (): IFacePileClasses => {
    return mergeStyleSets({
        facePile: {
            selectors: {
                [`.${avatarClassName}`]: {
                    marginRight: pxToRem(3)
                },
                [`.${avatarClassName}.disabled`]: {
                    filter: "grayscale(1)"
                }
            }
        },
        userName: {
            marginLeft: pxToRem(2),
            display: "inline-block",
            overflow: "hidden",
            textOverflow: "ellipsis"
        }
    });
};
```

By convernting it to `griffel` it will look like:

```typescript
import { avatarClassName, pxToRem } from "@fluentui/react-northstar";
import { makeStyles, shorthands } from "@griffel/react";

/**
 * Get class names.
 * @returns Class names.
 */
export const getClassNames = makeStyles({
    facePile: {
        selectors: {
            [`.${avatarClassName}`]: {
                ...shorthands.margin("0", pxToRem(3), "0", "0")
            },
            [`.${avatarClassName}.disabled`]: {
                filter: "grayscale(1)"
            }
        }
    },
    userName: {
        ...shorthands.margin("0", "0", "0", pxToRem(2)),
        ...shorthands.overflow("hidden"),
        display: "inline-block",
        textOverflow: "ellipsis"
    }
});
```

### Automated migration

There is already a library that will automatically try to migrate northstar styles to v9 styles: https://github.com/YuanboXue-Amber/style-transform-tool

A demo of this library can be seen: https://yellow-meadow-005156603.1.azurestaticapps.net/

This library will not work out of the box on mergeStyleSets but the expected format is similar so we can reuse some of the code in there to help create tooling that will.

Since the styles are all consistently in `.styles.ts` files, once we have tooling in place to do this automatically, it should be fairly easy to run.

### Potential performance gain

The modern workplace repo currently uses `@uifabric/merge-styles@7.19.1` as the main styling solution of choice. Running some benchmarks that were implemented in https://github.com/microsoft/griffel/pull/252 we can see the following results

> NOTE: That build time optimizations were not applied for Griffel (v9) styling, the values could potentially be further improved by applying build time optimizations

![](https://i.imgur.com/gj7zMwY.png)
![](https://i.imgur.com/KwKlsNc.png)

You can see that in the purely runtime scenario Griffel could already be ~30% increase to styling performance.


## Deprecating northstar usage

Northstar will be deprecated since Teams is heavily investing into the migration of northstar to v9 for improved performance and other API related benefits.

We can create an eslint rule in `eslint-plugin-modernworkplace` that will throw an error for any new imports of northstar components to promote new code using v9 components. 

## Gradual migration

v9 can can be used side by side with northstar without any problems. If there are any problems discovered with using the two component libraries together, that is a bug that should be reported to the Fluent UI team.

### Components

Below is the usage statistics of northstar component usage at the moment of 11/10/2022

<details>
    
| Count | Component        |
|-------|------------------|
| 149   | Flex             |
| 99    | Text             |
| 67    | Button           |
| 26    | Box              |
| 17    | Divider          |
| 14    | Input            |
| 13    | Dropdown         |
| 12    | Header           |
| 12    | Avatar           |
| 11    | Dialog           |
| 10    | Skeleton         |
| 10    | FormField        |
| 10    | Ref              |
| 9     | FlexItem         |
| 9     | Checkbox         |
| 8     | Provider         |
| 8     | MenuButton       |
| 8     | Table            |
| 8     | Tooltip          |
| 6     | TextArea         |
| 6     | List             |
| 6     | Loader           |
| 6     | Popup            |
| 5     | FormLabel        |
| 5     | FormTextArea     |
| 5     | Accordion        |
| 4     | ListItem         |
| 4     | Label            |
| 4     | Image            |
| 3     | Datepicker       |
| 2     | Breadcrumb       |
| 2     | Pill             |
| 2     | FormInput        |
| 1     | Grid             |
| 1     | Segment          |
| 1     | FormDatepicker   |
| 1     | Alert            |
| 1     | SplitButton      |
| 1     | Portal           |
| 1     | Status           |
| 1     | RadioGroup       |
| 1     | Toolbar          |

    
</details>

It's quite clear the the most often used components are simpler layout components. The top three components add up in usages more than all other compnents combined:

* Flex
* Text
* Button

For simpler components, (especially the most used components as they are quite simple) we should look into the possibility of creating codemods for automatic migration to avoid as much developer manual work as possible.

### Icons

Below is a snapshot of all icons used in the MWT repo as of 11/10/2022

<details>

| Current Icon            | V9 Icon Equivalent |
|-------------------------|--------------------|
| CloseIcon               |                    |
| CalendarIcon            |                    |
| AcceptIcon              |                    |
| ChevronDownIcon         |                    |
| ParticipantAddIcon      |                    |
| AddIcon                 |                    |
| SearchIcon              |                    |
| LocationIcon            |                    |
| CheckmarkCircleIcon     |                    |
| CircleIcon              |                    |
| ChevronStartIcon        |                    |
| RedbangIcon             |                    |
| ExclamationCircleIcon   |                    |
| EditIcon                |                    |
| MoreIcon                |                    |
| ArrowDownIcon           |                    |
| FilesEmptyIcon          |                    |
| TrashCanIcon            |                    |
| InfoIcon                |                    |
| OpenOutsideIcon         |                    |
| ArrowRightIcon          |                    |
| ChevronEndIcon          |                    |
| ErrorIcon               |                    |
| ArchiveIcon             |                    |
| LinkIcon                |                    |
| SettingsIcon            |                    |
| ChevronEndMediumIcon    |                    |
| UserFriendsIcon         |                    |
| ArrowUpIcon             |                    |
| ApprovalsAppbarIcon     |                    |
| TeamCreateIcon          |                    |
| CalendarAgendaIcon      |                    |
| QuestionCircleIcon      |                    |
| BookmarkIcon            |                    |
| FormatIcon              |                    |
| FilesUploadIcon         |                    |
| OneDriveIcon            |                    |
| ThumbtackIcon           |                    |
| ThumbtackSlashIcon      |                    |
| UndoIcon                |                    |
| ExcelColorIcon          |                    |
| FilesCodeIcon           |                    |
| FilesHtmlColoredIcon    |                    |
| FilesPdfColoredIcon     |                    |
| FilesPictureColoredIcon |                    |
| FilesSoundIcon          |                    |
| FilesTextColoredIcon    |                    |
| FilesVideoIcon          |                    |
| FilesZipIcon            |                    |
| FluidFileIcon           |                    |
| OneNoteColorIcon        |                    |
| PowerPointColorIcon     |                    |
| VisioColorIcon          |                    |
| WordColorIcon           |                    |
| SyncIcon                |                    |
| TabsIcon                |                    |
| ExclamationTriangleIcon |                    |
| UrgentIcon              |                    |
| AttachmentIcon          |                    |
| RetryIcon               |                    |
| FilterIcon              |                    |
| ShiftActivityIcon       |                    |
| WorkOrSchoolIcon        |                    |

</details>

We should finish the above mapping of V9 icons to northstar icons.

Icon migration can be done separately to any components and the intended design of V9 icons is that they can be used with northstar components. 

We should also look into codemods for icon migration once we have a complete mapping.

A catalog of v9 icons is available https://react.fluentui.dev/?path=/docs/concepts-developer-icons-icons-catalog--page

## Component Migration

We can assume that we have the encapsulation of v9 setup described earlier.

### Extending TeamsContextProvider

The `TeamsContextProvider` componnet is responsible for applying all providers that is used by modern workplace controls. In this way, we can simply add the `FluentProvider` to the main provider. This would incur some minor bundlesize, but would not impact any northstar code and enables the use of v9 components in the entire repo.

**packages\modernworkplace-react-hooks\src\useTeamsContext\TeamsContextProvider.tsx**

```diff=
import { Provider as NorthstarThemeProvider, RendererContext } from "@fluentui/react-northstar";
+import { FluentProvider, teamsLightTheme } from "@microsoft/modernworkplace-ui-core-v9";
import { createEmotionRenderer } from "@fluentui/react-northstar-emotion-renderer";
import React from "react";

import { TextDirection, useTextDirection } from "../useTextDirection";

import { getClassNames } from "./TeamsContextProvider.styles";
import { TeamsThemeType, getComposedTeamsTheme } from "./getComposedTeamsTheme";
import { TeamsContext } from "./useTeamsContext";
import { useTeamsTheme } from "./useTeamsTheme";

/**
 * Component that connects to Teams and fetches its context.
 * @param props Children.
 * @param props.children Children of this component.
 * @returns Child component wrapped in Teams Context Provider.
 */
export const TeamsContextProvider: React.FC = props => {
-    /* Other code removed for simplicity */

    return (
        <RendererContext.Provider value={createEmotionRenderer()}>
            <TeamsContext.Provider value={{ theme: themeWithoutStaticStyles, themeType: theme as TeamsThemeType }}>
+           {/* We can also map v9 themes to current themes */}
+           <FluentProvider theme={teamsLightTheme}>
                <NorthstarThemeProvider
                    className={containerStyles}
                    theme={themeWithoutStaticStyles}
                    rtl={direction === TextDirection.RightToLeft}>
                    {props.children}
                </NorthstarThemeProvider>
+           </FluentProvider>
            </TeamsContext.Provider>
        </RendererContext.Provider>
    );
};

```

### Example

Here is an example of a more complex migration.
lets take `FacePile` as example and see what would need to be done in order to migrate the `Avatar` Component used inside. 

First we would need to use `FluentProvider` in the following places:

So the replacement in **packages\modernworkplace-ui-core\src\components\facePile\FacePile.tsx** is simple enough as: 

```diff=
-import { Avatar, Flex, Text } from "@fluentui/react-northstar";
+import { Avatar, AvatarSizes } from "@fluentui/react-components";
+import { Flex, SizeValue, Text } from "@fluentui/react-northstar";
 import { useTeamsContext } from "@microsoft/modernworkplace-react-hooks";
 import * as React from "react";

@@ -14,6 +15,16 @@ import { IFacePile } from "./IFacePile";
 // Default, maximum number of users to display.
 const defaultVisibleMax = 11;

+const sizesMap: Record<SizeValue, AvatarSizes> = {
+    smallest: 20,
+    smaller: 24,
+    small: 28,
+    medium: 32,
+    large: 64,
+    larger: 64,
+    largest: 96
+};
+
 /**
  * Renders face pile component.
  * @param props Component properties.
@@ -27,7 +38,7 @@ export const FacePile: React.FC<IFacePile> = props => {
     const classes = getClassNames();
     const maxVisible = props.maxNumberOfVisibleAvatars ?? defaultVisibleMax;
     const overflow = props.users.length > maxVisible;
-    const overflowLabel = (name: string) => `+${props.users.length - maxVisible}`;
+    const overflowLabel = `+${props.users.length - maxVisible}`;
     const avatarClass = props.disabled ? "disabled" : "";

     const size = props.size ?? "medium";
@@ -39,11 +50,9 @@ export const FacePile: React.FC<IFacePile> = props => {
     return (
         <Flex vAlign="center" className={classes.facePile}>
             {props.users.slice(0, maxVisible).map((user, idx) => {
-                return (
-                    <Avatar className={avatarClass} key={`${idx}-${user.id}`} name={user.displayName} image={user.imageUrl} size={size} />
-                );
+                return <Avatar key={`${idx}-${user.id}`} name={user.displayName} image={{ src: user.imageUrl }} size={sizesMap[size]} />;
             })}
-            {overflow && <Avatar getInitials={overflowLabel} size={size} className={avatarClass} />}
+            {overflow && <Avatar initials={overflowLabel} size={sizesMap[size]} className={avatarClass} />}
             {props.users.length === 1 && (
                 <Text
                     variables={textVariables}
```

One final touch, we need one more update in the styles since we are not exporting `avatarClassName` in v9 but `avatarClassNames` which is an object with class names for each slots. So the final change in the `styles` file would be:

```diff=
- import { avatarClassName } from "@fluentui/react-northstar";
+ import { avatarClassNames } from "@microsoft/modernworkplace-ui-core-v9";

- [`.${avatarClassName}`]: {
+ [`.${avatarClassNames.root}`]: {
```

We have migration instructions for several components, here we used [Avatar Migration](https://react.fluentui.dev/?path=/docs/concepts-migration-from-v0-components-avatar-migration--page)

### Accessibility 

Check the [accessibility migration doc](https://react.fluentui.dev/?path=/docs/concepts-migration-from-v0-custom-accessibility--page) where it exaplains how to migrate the 4 possible properties that an accessibility behavior has. For attributes we should add them directly to the component. 

Let's take **packages\modernworkplace-ui-members\src\Members.tsx** as example, where it's using `gridBehavior`:

```diff=
+import { useTabsterAttributes } from "@fluentui/react-tabster";

 export const Members: React.FC<IMembersProps> = props => {
     const { members } = useTranslations();

+    const arrowKeyNavigationAttributes = useTabsterAttributes({
+        mover: {
+            direction: 3 // grid
+        }
+    });
+

<Table 
-    accessibility={gridNestedBehavior}
+    {...arrowKeyNavigationAttributes}
```

Here we are replacing the focus zone property by using `react-tabster`

If we had a custom behavior such has:

```javascript=
const customBehavior = (props) => {
    attributes: {
        role="dialog",
        disabled: props.disabled
    }
}

<Component accessibility={customBehavior} />
```

That could be replaced by:

```jsx=
<Component role="dialog" disabled={props.disabled} />
```

## Validation

### Visual Regression

There is no visual regression testing in the modern workplace repo, therefore any visual regression will have to be done manually during migration. However what level of visual regression allowed should be discussed with designers since v9 is using the Fluent language which is intended to be the future design of all M365 experiences

### Unit tests

All unit tests that break as a result of migration should be investigated and fixed.

### Performance

There are performance tests setup for the `LoanManager` scenario. In order have an accurate perf tests between northstar and v0 we should try to quickly migrate `LoanManager` related controls to v9 and run the existing performance tests

### Bundle size

Bundle size is measured by looking at the final size of the js bundle that is built with the production webpack config. We can measure the bundle size of just integrating the FluentProvider at the start to see the initial impact and keep measuring as components as migrated



