Create a content page

A content page is a webpage that is rendered within the Teams client, which is a part of:

  • A personal-scoped custom tab: In this case, the content page is the first page the user encounters.
  • A channel or group custom tab: The content page is displayed after the user pins and configures the tab in the appropriate context.
  • A dialog: You can create a content page and embed it as a webview inside a dialog (referred as task module in TeamsJS v1.x). The page is rendered inside the modal pop-up.

This article is specific to using content pages as tabs; however, most of the guidance here applies regardless of how the content page is presented to the user.


This topic reflects version 2.0.x of the Microsoft Teams JavaScript client library (TeamsJS). If you are using an earlier version, refer to the TeamsJS library overview for guidance on the differences between the latest TeamsJS and earlier versions.

Tab content and design guidelines

Your tab's overall objective is to provide access to the meaningful and engaging content that has a practical value and an evident purpose.

You need to focus on making your tab design clean, navigation intuitive, and content immersive.For more information, see tab design guidelines and Microsoft Teams Store validation guidelines.

Integrate your code with Teams

For your page to display in Teams, you must include the Microsoft Teams JavaScript client library and include a call to app.initialize() after your page loads.


It takes close to 24-48 hours for any content or UI changes to reflect in the tab app due to cache.

The following code provides an example of how your page and the Teams client communicate:

<!DOCTYPE html>
    <script src="" 
      crossorigin="anonymous" >

Access additional content

You can access additional content by using TeamsJS to interact with Teams, creating deep links, using dialogs, and verifying if URL domains are included in the validDomains array.

Use TeamsJS to interact with Teams

The Teams client JavaScript library provides many more functions that you can find useful while developing your content page.

You can create deep links to entities in Teams. They're used to create links that navigate to content and information within your tab. For more information, see create deep links to content and features in Teams.


A dialog is a modal pop-up experience that you can trigger from your tab. In a content page, use dialogs to present forms for gathering additional information, displaying the details of an item in a list, or presenting the user with additional information. The dialogs themselves can be additional content pages or created completely using Adaptive Cards. For more information, see using dialogs in tabs.

Valid domains

Ensure that all URL domains used in your tabs are included in the validDomains array in your manifest. For more information, see validDomains in the manifest schema reference.


The core functionality of your tab exists within Teams and not outside of Teams.

Show a native loading indicator

Starting with manifest schema v1.7, you can provide a native loading indicator. For example, tab content page, configuration page, removal page, and dialogs in tabs.


The behavior on mobile clients isn't configurable through the native loading indicator property. Mobile clients show this indicator by default across content pages and iframe-based dialogs. This indicator on mobile is shown when a request is made to fetch content and gets dismissed as soon as the request gets completed.

If you indicate showLoadingIndicator : true in your app manifest, then all tab configuration, content, removal pages, and all iframe-based dialogs must follow these steps:

To show the loading indicator:

  1. Add "showLoadingIndicator": true to your manifest.

  2. Call app.initialize();.

  3. Call app.notifySuccess() in all iframe-based contents to notify Teams that your app has successfully loaded. If applicable, Teams hides the loading indicator. If notifySuccess isn't called within 30 seconds, Teams assumes that your app has timed out, and displays an error screen with a retry option. For app updates, this step is applicable for already configured tabs. If you don't perform this step, an error screen is displayed for the existing users. [Mandatory]

  4. If you're ready to print to the screen and wish to lazy load the rest of your application's content, you can hide the loading indicator manually by calling app.notifyAppLoaded();. [Optional]

  5. If your application doesn't load, you can call app.notifyFailure({reason: app.FailedReason.Timeout, message: "failure message"}); to let Teams know about the failure. The message property is currently not used, therefore the failure message doesn't appear in the UI, and a generic error screen appears to the user. The following code shows the enumeration that defines the possible reasons you can indicate for the application's failure to load:

    /* List of failure reasons */
    export const enum FailedReason {
        AuthFailed = "AuthFailed",
        Timeout = "Timeout",
        Other = "Other"

Next step

See also