Publish an SPFx web part as a Teams tab and app
Add TeamsTab and TeamsPersonalApp to supportedHosts in the web part manifest. Check this.context.sdks.microsoftTeams to detect Teams. Build the .sppkg with Heft, deploy it tenant-wide, then select Sync to Teams in the app catalog. The app then appears in the Built for your org section of Teams.
Before you start
- An SPFx 1.24 project with a web part, built with the Heft toolchain.
- A tenant app catalog and the SharePoint Administrator role to upload the package to it.
- To upload a Teams package manually: the Teams Administrator or Global Administrator role.
- A Teams client signed in to the same tenant as SharePoint.
Step 1: Declare the Teams hosts in the manifest
Open src/webparts/<name>/<Name>WebPart.manifest.json. The supportedHosts property lists where the web part can be used.
TeamsTab exposes it as a tab in a channel or group chat. TeamsPersonalApp exposes it as a personal app. Keep SharePointWebPart to keep using it on SharePoint pages.
Without supportedHosts, the default host is SharePointWebPart only. An empty array removes the web part from SharePoint and from the generated Teams manifest.
The name and description of the generated Teams app come from preconfiguredEntries[0].title and preconfiguredEntries[0].description. Write them with care.
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
"id": "<component GUID>",
"alias": "MyWebPart",
"componentType": "WebPart",
"supportedHosts": ["SharePointWebPart", "TeamsTab", "TeamsPersonalApp"],
"preconfiguredEntries": [
{
"title": { "default": "Request tracker" },
"description": { "default": "List of the team's requests" }
}
]
}Check: supportedHosts contains TeamsTab, TeamsPersonalApp or both.
Step 2: Detect the Teams context in code
When the web part runs in Teams, Outlook or the Microsoft 365 app, this.context.sdks.microsoftTeams is populated. On a SharePoint page, it is empty.
To read the context, call this.context.sdks.microsoftTeams.teamsJs.app.getContext(). The this.context.sdks.microsoftTeams.context property has been deprecated since SPFx 1.16.
The TeamsJS v2 context provides, for example, team.displayName, channel.displayName, app.host.name and app.theme.
Do not install your own version of @microsoft/teams-js: Microsoft does not support it in an SPFx component. Use the instance provided by the context.
protected async onInit(): Promise<void> {
await super.onInit();
const teams = this.context.sdks.microsoftTeams;
if (teams) {
const ctx = await teams.teamsJs.app.getContext();
this._hostName = ctx.app.host.name; // "Teams", "Outlook", "Office"…
this._teamName = ctx.team?.displayName; // empty in a personal app
this._theme = ctx.app.theme; // default | dark | contrast…
} else {
this._hostName = "SharePoint";
}
}Check: The web part shows different content on a SharePoint page and in a Teams tab.
Step 3: Handle theme and configuration
By default, the web part theme comes from the underlying SharePoint site, not from Teams. In dark mode, the result can look out of place.
Read app.theme from the context (default, dark, contrast, or glass on Apple Vision Pro) and subscribe to changes with app.registerOnThemeChangeHandler.
In a channel tab, the web part property pane serves as the configuration page. SPFx stores the settings for you. Set canUpdateConfiguration to false in the manifest to hide this configuration.
A personal app has no property pane. Provide configuration in the web part UI, or in a separate settings web part.
const teams = this.context.sdks.microsoftTeams;
if (teams) {
teams.teamsJs.app.registerOnThemeChangeHandler((theme: string) => {
this.domElement.dataset.theme = theme; // your CSS styles rely on this attribute
this.render();
});
}Check: Switching Teams to the dark theme changes the web part's appearance without reloading the tab.
Step 4: Prepare the project's teams folder
The teams folder at the project root holds two icons per component: <componentId>_color.png and <componentId>_outline.png. Replace them while keeping exactly these names, otherwise they are not packaged.
Teams expects a 192 × 192 pixel color icon and a 32 × 32 pixel outline icon.
To control the Teams manifest yourself (several tabs in a personal app, your own app ID and name), place a TeamsSPFxApp.zip package in this folder. Zip the folder's contents, not the folder itself.
In that manifest, add the webApplicationInfo entry below. It is required for API calls to succeed from Teams clients.
"webApplicationInfo": {
"resource": "https://{teamSiteDomain}",
"id": "00000003-0000-0ff1-ce00-000000000000"
}Check: The teams folder contains both correctly named icons, plus TeamsSPFxApp.zip if you provide your own manifest.
Step 5: Build and deploy the SharePoint package
Build the .sppkg with Heft as usual. The package includes the teams folder, including TeamsSPFxApp.zip if present.
Upload it to the tenant app catalog and select "Make this solution available to all sites in the organization". The upload details are in our guide on deploying an SPFx solution to the app catalog.
A site-scoped deployment is possible, but the solution must then be installed on each team's SharePoint site before use.
heft build --production
heft package-solution --production
ls sharepoint/solution/*.sppkgCheck: The app catalog's "App Package Error Message" column is empty for the solution.
Step 6: Publish the app to Teams
In the app catalog, select the solution, then the Sync to Teams button in the ribbon (Files tab). Depending on the UI version, Microsoft also calls it Add to Teams.
Without TeamsSPFxApp.zip, SharePoint generates the Teams manifest and package, then publishes them to the organization's Teams app catalog. With that file, it publishes your package as is.
Alternatively, upload the Teams package in the Teams admin center, under Teams apps > Manage apps > Upload new app. The generated package can be downloaded from _api/web/tenantappcatalog/downloadteamssolution(id)/$value, where id is the solution's numeric ID in the app catalog.
App permission policies in the Teams admin center then determine who can use the app.
https://contoso.sharepoint.com/sites/appcatalog/_api/web/tenantappcatalog/downloadteamssolution(12)/$valueCheck: A successful sync message appears at the top right of the app catalog.
Step 7: Test in Teams
In Teams, open Apps. The app appears in the Built for your org section. Allow a few minutes because of caching.
For a tab: in a channel, select +, search for the app, then select Add and Save. The property pane opens for the initial configuration.
For a personal app: add it from the store. It opens without a team context, so team is empty.
Check permissions: a channel tab runs in the context of the team's SharePoint site. Data reads and API calls follow the user's permissions on that site and the API permissions approved for SPFx.
Check: The tab shows the team name and the personal app opens without errors.
Step 8: Ship an update
Increment solution.version, rebuild, upload the .sppkg again, then run Sync to Teams again.
If the "Failed to sync solution to teams" message appears, delete the previous version of the app in Teams, then sync again. Syncing does not overwrite an existing app.
If you manage the package in the Teams admin center, upload the new version from the app's details page with Upload file.
Check: Teams loads the new version of the web part in the existing tab.
Common errors
- Sync to Teams fails with "Failed to sync solution to teams".
- A previous version already exists in the Teams app catalog. Delete it (in Teams or in Manage apps), then run the sync again.
- Teams shows the default icons instead of your images.
- Keep the names
<componentId>_color.pngand<componentId>_outline.pngin theteamsfolder, with the exact component ID, then rebuild the package. - Teams rejects the
TeamsSPFxApp.zippackage. - You zipped the folder instead of its contents. The
manifest.jsonfile and the icons must be at the root of the zip. - The web part stays light when the user switches Teams to the dark theme.
- By default, the theme comes from the SharePoint site. Read
app.themeand hook upapp.registerOnThemeChangeHandlerto apply your styles.
Sources
- Microsoft Learn — Build a Teams tab with SPFx (tutorial) (opens in a new tab)
- Microsoft Learn — Build Teams tabs with SPFx (opens in a new tab)
- Microsoft Learn — Deployment options for SPFx Teams solutions (opens in a new tab)
- Microsoft Learn — Expose SPFx web parts in Teams (opens in a new tab)
- Microsoft Learn — Configure SPFx web parts in Teams (opens in a new tab)
- Microsoft Learn — IClientSideWebPartManifest interface (supportedHosts) (opens in a new tab)
- Microsoft Learn — SPFx 1.16 release notes (TeamsJS v2) (opens in a new tab)
- Microsoft Learn — Teams tab context and theme changes (opens in a new tab)
- Microsoft Learn — Teams app icons (opens in a new tab)
- Microsoft Learn — Teams custom app policies and settings (opens in a new tab)