---
# 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

### 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"
    }
});
```

### Component's Migratoin

All northstar components are exported from `@microsoft/modernworkplace-ui-core`, in order to use v9 components without affection production and allowing less invasive migration, it would be ideal to create a new exporting package for v9 such as `@microsoft/modernworkplace-ui-core-v9`. Once we have that set up, we need to use `FluentProvider` so tokens will be available, lets take again `FacePile` as example and see what would need to be done in order to migrate `Avatar` used inside. 

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

**packages\modernworkplace-ui-core\src\testing\renderWithCoreContext.tsx**

```diff=
@@ -5,6 +5,7 @@
 import { Provider } from "@fluentui/react-northstar";
 import { LegacyTranslationsProvider, LocalizersProvider } from "@microsoft/modernworkplace-i18n";
 import { TeamsContextProvider } from "@microsoft/modernworkplace-react-hooks";
+import { FluentProvider, teamsLightTheme } from "@microsoft/modernworkplace-ui-core-v9";
 import { RenderOptions, RenderResult, render } from "@testing-library/react";
 import React from "react";

@@ -33,9 +34,11 @@ export const wrapInProviders = (

     return (
         <Provider>
-            <TeamsContextProvider>
-                <CoreUITranslationsProvider>{contentWithLocalizers}</CoreUITranslationsProvider>
-            </TeamsContextProvider>
+            <FluentProvider theme={teamsLightTheme}>
+                <TeamsContextProvider>
+                    <CoreUITranslationsProvider>{contentWithLocalizers}</CoreUITranslationsProvider>
+                </TeamsContextProvider>
+            </FluentProvider>
         </Provider>
     );
 };
```

**packages/modernworkplace-ui-core/.storybook/preview.js**

```diff=
@@ -1,6 +1,7 @@
 import * as React from "react";

 import { LocalizersProvider } from "@microsoft/modernworkplace-i18n"
+import {FluentProvider, teamsLightTheme} from "@microsoft/modernworkplace-ui-core-v9";
 import { TeamsContext, TeamsThemeType, getComposedTeamsTheme, TextDirection } from "@microsoft/modernworkplace-react-hooks";
 import { Provider as NorthstarThemeProvider } from "@fluentui/react-northstar";
 import { withPerformance } from "storybook-addon-performance";
@@ -42,6 +43,7 @@ const withNecessaryProviders = (Story, context) => {
     const isRTL = context.globals.direction === TextDirection.RightToLeft;

     return (
+        <FluentProvider theme={teamsLightTheme}>
         <TeamsContext.Provider value={{ theme, themeType }}>
             <NorthstarThemeProvider theme={theme} rtl={isRTL}>
                 <LocalizersProvider>
@@ -51,6 +53,7 @@ const withNecessaryProviders = (Story, context) => {
                 </LocalizersProvider>
             </NorthstarThemeProvider>
         </TeamsContext.Provider>
+        </FluentProvider>
     );
 }
```

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 migrations instructions for several components, here we used [Avatar Migrition](https://react.fluentui.dev/?path=/docs/concepts-migration-from-v0-components-avatar-migration--page)