Professional Documents
Culture Documents
Office Dev Add Ins
Office Dev Add Ins
OVERVIEW QUICKSTART
Office Add-ins platform Set up an Excel add-in in 5
overview minutes
QUICKSTART QUICKSTART
Set up an Outlook add-in in 5 Set up a Word add-in in 5
minutes minutes
SAMPLE REFERENCE
Test and experiment with APIs Office JavaScript API reference
using Script Lab documentation
You can use the Office Add-ins platform to build solutions that extend Office
applications and interact with content in Office documents. With Office Add-ins, you can
use familiar web technologies such as HTML, CSS, and JavaScript to extend and interact
with Outlook, Excel, Word, PowerPoint, OneNote, and Project. Your solution can run in
Office across multiple platforms, including Windows, Mac, iPad, and in a browser.
Office Add-ins can do almost anything a webpage can do inside a browser. Use the
Office Add-ins platform to:
Add new functionality to Office clients - Bring external data into Office, automate
Office documents, expose functionality from Microsoft and others in Office clients,
and more. For example, use Microsoft Graph API to connect to data that drives
productivity.
Create new rich, interactive objects that can be embedded in Office documents -
Embed maps, charts, and interactive visualizations that users can add to their own
Excel spreadsheets and PowerPoint presentations.
Office Add-ins provide the following advantages over add-ins built using VBA, COM, or
VSTO.
Cross-platform support: Office Add-ins run in Office on the web, Windows, Mac,
and iPad.
Easy access via AppSource: You can make your solution available to a broad
audience by submitting it to AppSource.
Based on standard web technology: You can use any library you like to build Office
Add-ins.
) Important
COM and VSTO add-ins aren't supported in the new Outlook on Windows that's
currently in preview. These add-ins are still supported in the classic Outlook on
Windows desktop client. To learn more, see Develop Outlook add-ins for new
Outlook on Windows (preview).
Manifest
The manifest is an XML file that specifies settings and capabilities of the add-in, such as:
The add-in's display name, description, ID, version, and default locale.
The permission level and data access requirements for the add-in.
Web app
The most basic Office Add-in consists of a static HTML page that is displayed inside an
Office application, but that doesn't interact with either the Office document or any other
Internet resource. However, to create an experience that interacts with Office documents
or allows the user to interact with online resources from an Office client application, you
can use any technologies, both client and server side, that your hosting provider
supports (such as ASP.NET, PHP, or Node.js). To interact with Office clients and
documents, you use the Office.js JavaScript APIs.
You can add custom ribbon buttons and menu items to the ribbon in Office on the web
and on Windows. This makes it easy for users to access your add-in directly from their
Office application. Command buttons can launch different actions such as showing a
task pane with custom HTML or executing a JavaScript function.
Task panes
You can use task panes in addition to add-in commands to enable users to interact with
your solution. Clients that don't support add-in commands (Office on iPad) run your
add-in as a task pane. Users launch task pane add-ins via the My Add-ins button on the
Insert tab.
Extend Outlook functionality
Outlook add-ins can extend the Office app ribbon and also display contextually next to
an Outlook item when you're viewing or composing it. They can work with an email
message, meeting request, meeting response, meeting cancellation, or appointment
when a user is viewing a received item or replying or creating a new item.
Outlook add-ins can access contextual information from the item, such as an address or
tracking ID, and then use that data to access additional information on the server and
from web services to create compelling user experiences. In most cases, an Outlook
add-in runs without modification in the Outlook application to provide a seamless
experience on the desktop, web, and tablet and mobile devices.
Code samples
Learn how to build the simplest Office Add-in with only a manifest, HTML web page,
and a logo. The following samples will help you get started in the Office application
you're interested in.
See also
Core concepts for Office Add-ins
Develop Office Add-ins
Design Office Add-ins
Test and debug Office Add-ins
Publish Office Add-ins
Learn about the Microsoft 365 Developer Program
Beginner's guide
Article • 03/09/2023
Want to get started building your own cross-platform Office extensions? The following
steps show you what to read first, what tools to install, and recommended tutorials to
complete.
7 Note
If you're experienced in creating VSTO add-ins for Office, we recommend that you
immediately turn to VSTO add-in developer's guide, which is a superset of the
information in this article.
Step 0: Prerequisites
Office Add-ins are essentially web applications embedded in Office. So, you should
first have a basic understanding of web applications and how they are hosted on
the web. There is an enormous amount of information about this on the Internet,
in books, and in online courses. A good way to start if you have no prior
knowledge of web applications at all is to search for "What is a web app?" on Bing.
The primary programming language you will use in creating Office Add-ins is
JavaScript or TypeScript. You can think of TypeScript as a strongly-typed version of
JavaScript. If you are not familiar with either of these languages, but you have
experience with VBA, VB.Net, C#, you will probably find TypeScript easier to learn.
Again, there is a wealth of information about these languages on the Internet, in
books, and in online courses.
Office Add-ins Platform Overview: Find out what Office Web Add-ins are and how
they differ from older ways of extending Office, such as VSTO add-ins.
Develop Office Add-ins: Get an overview of Office Add-in development and
lifecycle including tooling, creating an add-in UI, and using the JavaScript APIs to
interact with the Office document.
"Hello world" samples : Learn how to build the simplest Office Add-in with only a
manifest, HTML web page, and a logo. These samples will help you understand the
fundamental parts of an Office Add-in.
There are a lot of links in those articles, but if you're a beginner with Office Add-ins, we
recommend that you come back here when you've read them and continue with the
next section.
Visual Studio
Node.js and Visual Studio Code
Step 3: Code
You can't learn to drive by reading the owner's manual, so start coding with this Excel
tutorial. You'll be using the Office JavaScript library and some XML in the add-in's
manifest. There's no need to memorize anything, because you'll be getting more
background about both in a later steps.
Then explore the Office JavaScript APIs with our Script Lab tool -- a sandbox for running
and exploring the APIs.
Next Steps
Congratulations on finishing the beginner's learning path for Office Add-ins! Here are
some suggestions for further exploration of our documentation:
Tutorials or quick starts for other Office applications:
OneNote quick start
Outlook tutorial
PowerPoint tutorial
Project quick start
Word tutorial
In this article, you'll walk through the process of building an Excel task pane add-in.
Yeoman generator
Prerequisites
7 Note
If you aren't familiar with Node.js or npm, you should start by setting up your
development environment.
The latest version of Yeoman and the Yeoman generator for Office Add-ins.
To install these tools globally, run the following command via the command
prompt.
command line
7 Note
command line
yo office
7 Note
When you run the yo office command, you may receive prompts about the
data collection policies of Yeoman and the Office Add-in CLI tools. Use the
information that's provided to respond to the prompts as you see fit.
When prompted, provide the following information to create your add-in project.
After you complete the wizard, the generator creates the project and installs
supporting Node components.
Tip
You can ignore the next steps guidance that the Yeoman generator provides
after the add-in project's been created. The step-by-step instructions within
this article provide all of the guidance you'll need to complete this tutorial.
The ./manifest.xml file in the root directory of the project defines the settings
and capabilities of the add-in. To learn more about the manifest.xml file, see
Office Add-ins XML manifest.
The ./src/taskpane/taskpane.html file contains the HTML markup for the task
pane.
The ./src/taskpane/taskpane.css file contains the CSS that's applied to
content in the task pane.
The ./src/taskpane/taskpane.js file contains the Office JavaScript API code
that facilitates interaction between the task pane and the Office client
application.
Try it out
1. Navigate to the root folder of the project.
command line
2. Complete the following steps to start the local web server and sideload your
add-in.
7 Note
Office Add-ins should use HTTPS, not HTTP, even while you're
developing. If you're prompted to install a certificate after you run one of
the following commands, accept the prompt to install the certificate that
the Yeoman generator provides. You may also have to run your command
prompt or terminal as an administrator for the changes to be made.
Tip
If you're testing your add-in on Mac, run the following command before
proceeding. When you run this command, the local web server starts.
command line
To test your add-in in Excel, run the following command in the root
directory of your project. This starts the local web server and opens Excel
with your add-in loaded.
command line
npm start
7 Note
command line
https://contoso.sharepoint.com/:t:/g/EZGxP7ksiE5DuxvY638G798Bpuhwl
uxCMfF1WZQj3VYhYQ?e=F4QM1R
npm run start:web -- --document
https://1drv.ms/x/s!jkcH7spkM4EGgcZUgqthk4IK3NOypVw?e=Z6G1qp
npm run start:web -- --document https://contoso-my.sharepoint-
df.com/:t:/p/user/EQda453DNTpFnl1bFPhOVR0BwlrzetbXvnaRYii2lDr_oQ?
e=RSccmNP
If your add-in doesn't sideload in the document, manually sideload it by
following the instructions in Manually sideload add-ins to Office on the
web.
3. In Excel, choose the Home tab, and then choose the Show Taskpane button
on the ribbon to open the add-in task pane.
5. At the bottom of the task pane, choose the Run link to set the color of the
selected range to yellow.
Next steps
Congratulations, you've successfully created an Excel task pane add-in! Next, learn
more about the capabilities of an Excel add-in and build a more complex add-in by
following along with the Excel add-in tutorial.
Code samples
Excel "Hello world" add-in : Learn how to build a simple Office Add-in with only a
manifest, HTML web page, and a logo.
See also
Office Add-ins platform overview
Develop Office Add-ins
Excel JavaScript object model in Office Add-ins
Excel add-in code samples
Excel JavaScript API reference
Using Visual Studio Code to publish
Get started developing Excel custom
functions
Article • 03/28/2023
With custom functions, developers can add new functions to Excel by defining them in
JavaScript or TypeScript as part of an add-in. Excel users can access custom functions
just as they would any native function in Excel, such as SUM() .
Prerequisites
7 Note
If you aren't familiar with Node.js or npm, you should start by setting up your
development environment.
The latest version of Yeoman and the Yeoman generator for Office Add-ins. To
install these tools globally, run the following command via the command prompt.
command line
7 Note
7 Note
If you don't already have Office, you can join the Microsoft 365 developer
program to get a free, 90-day renewable Microsoft 365 subscription to use
during development.
Build your first custom functions project
To start, you'll use the Yeoman generator to create the custom functions project. This
will set up your project with the correct folder structure, source files, and dependencies
to begin coding your custom functions.
1. Run the following command to create an add-in project using the Yeoman
generator.
command line
yo office
7 Note
When you run the yo office command, you may receive prompts about the
data collection policies of Yeoman and the Office Add-in CLI tools. Use the
information that's provided to respond to the prompts as you see fit.
When prompted, provide the following information to create your add-in project.
The Yeoman generator will create the project files and install supporting Node
components.
2. The Yeoman generator will give you some instructions in your command line about
what to do with the project, but ignore them and continue to follow our
instructions. Navigate to the root folder of the project.
command line
command line
4. Start the local web server, which runs in Node.js. You can try out the custom
function add-in in Excel. You may be prompted to open the add-in's task pane,
although this is optional. You can still run your custom functions without opening
your add-in's task pane.
To test your add-in in Excel on Windows or Mac, run the following command. When
you run this command, the local web server will start and Excel will open with your
add-in loaded.
command line
7 Note
Office Add-ins should use HTTPS, not HTTP, even when you are developing. If
you are prompted to install a certificate after you run one of the following
commands, accept the prompt to install the certificate that the Yeoman
generator provides. You may also have to run your command prompt or
terminal as an administrator for the changes to be made.
1. Select a cell and type =CONTOSO . Notice that the autocomplete menu shows the list
of all functions in the CONTOSO namespace.
2. Run the CONTOSO.ADD function, using numbers 10 and 200 as input parameters, by
typing the value =CONTOSO.ADD(10,200) in the cell and pressing enter.
The ADD custom function computes the sum of the two numbers that you specify as
input parameters. Typing =CONTOSO.ADD(10,200) should produce the result 210 in the cell
after you press enter.
If the CONTOSO namespace isn't available in the autocomplete menu, take the following
steps to register the add-in in Excel.
1. In Excel, choose the Insert tab and then choose the down-arrow located to the
right of My Add-ins.
2. In the list of available add-ins, find the Developer Add-ins section and select
My custom functions add-in to register it.
Next steps
Congratulations, you've successfully created a custom function in an Excel add-in! Next,
build a more complex add-in with streaming data capability. The following link takes
you through the next steps in the Excel add-in with custom functions tutorial.
Troubleshooting
You may encounter issues if you run the quick start multiple times. If the Office cache
already has an instance of a function with the same name, your add-in gets an error
when it sideloads. You can prevent this by clearing the Office cache before running npm
run start .
See also
Custom functions overview
Custom functions metadata
Runtime for Excel custom functions
Using Visual Studio Code to publish
Build your first OneNote task pane add-
in
Article • 05/02/2023
In this article, you'll walk through the process of building a OneNote task pane add-in.
Prerequisites
7 Note
If you aren't familiar with Node.js or npm, you should start by setting up your
development environment.
The latest version of Yeoman and the Yeoman generator for Office Add-ins. To
install these tools globally, run the following command via the command prompt.
command line
7 Note
command line
yo office
7 Note
When you run the yo office command, you may receive prompts about the data
collection policies of Yeoman and the Office Add-in CLI tools. Use the information
that's provided to respond to the prompts as you see fit.
When prompted, provide the following information to create your add-in project.
After you complete the wizard, the generator creates the project and installs supporting
Node components.
Tip
You can ignore the next steps guidance that the Yeoman generator provides after
the add-in project's been created. The step-by-step instructions within this article
provide all of the guidance you'll need to complete this tutorial.
The ./manifest.xml file in the root directory of the project defines the settings and
capabilities of the add-in.
The ./src/taskpane/taskpane.html file contains the HTML markup for the task
pane.
The ./src/taskpane/taskpane.css file contains the CSS that's applied to content in
the task pane.
The ./src/taskpane/taskpane.js file contains the Office JavaScript API code that
facilitates interaction between the task pane and the Office client application.
JavaScript
try {
await OneNote.run(async (context) => {
Try it out
1. Navigate to the root folder of the project.
command line
2. Start the local web server. Run the following command in the root directory of your
project.
command line
7 Note
Office Add-ins should use HTTPS, not HTTP, even while you're developing. If
you're prompted to install a certificate after you run one of the following
commands, accept the prompt to install the certificate that the Yeoman
generator provides. You may also have to run your command prompt or
terminal as an administrator for the changes to be made.
4. Choose Insert > Office Add-ins to open the Office Add-ins dialog.
If you're signed in with your consumer account, select the MY ADD-INS tab,
and then choose Upload My Add-in.
The following image shows the MY ADD-INS tab for consumer notebooks.
5. In the Upload Add-in dialog, browse to manifest.xml in your project folder, and
then choose Upload.
6. From the Home tab, choose the Show Taskpane button on the ribbon. The add-in
task pane opens in an iFrame next to the OneNote page.
7. At the bottom of the task pane, choose the Run link to set the page title and add
an outline to the body of the page.
Next steps
Congratulations, you've successfully created a OneNote task pane add-in! Next, learn
more about the core concepts of building OneNote add-ins.
See also
Office Add-ins platform overview
Develop Office Add-ins
OneNote JavaScript API programming overview
OneNote JavaScript API reference
Rubric Grader sample
Using Visual Studio Code to publish
Build your first Outlook add-in
Article • 03/28/2023
In this article, you'll walk through the process of building an Outlook task pane add-in
that displays at least one property of a selected message.
Yeoman generator
Prerequisites
7 Note
If you aren't familiar with Node.js or npm, you should start by setting up your
development environment.
The latest version of Yeoman and the Yeoman generator for Office Add-ins.
To install these tools globally, run the following command via the command
prompt.
command line
7 Note
command line
yo office
7 Note
When you run the yo office command, you may receive prompts about
the data collection policies of Yeoman and the Office Add-in CLI tools.
Use the information that's provided to respond to the prompts as you
see fit.
Tip
You can ignore the next steps guidance that the Yeoman generator
provides after the add-in project's been created. The step-by-step
instructions within this article provide all of the guidance you'll need to
complete this tutorial.
command line
The ./manifest.xml file in the root directory of the project defines the settings
and capabilities of the add-in.
The ./src/taskpane/taskpane.html file contains the HTML markup for the task
pane.
The ./src/taskpane/taskpane.css file contains the CSS that's applied to
content in the task pane.
The ./src/taskpane/taskpane.js file contains the Office JavaScript API code
that facilitates interaction between the task pane and Outlook.
Update the code
1. Open your project in VS Code or your preferred code editor.
Tip
On Windows, you can navigate to the root directory of the project via the
command line and then enter code . to open that folder in VS Code. On
Mac, you'll need to add the code command to the path before you
can use that command to open the project folder in VS Code.
HTML
3. In your code editor, open the file ./src/taskpane/taskpane.js, then add the
following code to the run function. This code uses the Office JavaScript API to
get a reference to the current message and write its subject property value to
the task pane.
JavaScript
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the MIT license.
* See LICENSE in the project root for license information.
*/
Office.onReady((info) => {
if (info.host === Office.HostType.Outlook) {
document.getElementById("sideload-msg").style.display = "none";
document.getElementById("app-body").style.display = "flex";
document.getElementById("run").onclick = run;
}
});
Try it out
7 Note
Office Add-ins should use HTTPS, not HTTP, even while you're developing. If
you're prompted to install a certificate after you run one of the following
commands, accept the prompt to install the certificate that the Yeoman
generator provides. You may also have to run your command prompt or
terminal as an administrator for the changes to be made.
1. Run the following command in the root directory of your project. When you
run this command, the local web server starts and your add-in will be
sideloaded.
command line
npm start
2. In Outlook, view a message in the Reading Pane , or open the message in its
own window.
3. Choose the Home tab (or the Message tab if you opened the message in a
new window), and then choose the Show Taskpane button on the ribbon to
open the add-in task pane.
7 Note
If you receive the error "We can't open this add-in from localhost" in the
task pane, follow the steps outlined in the troubleshooting article.
4. When prompted with the WebView Stop On Load dialog box, select OK.
7 Note
If you select Cancel, the dialog won't be shown again while this instance
of the add-in is running. However, if you restart your add-in, you'll see
the dialog again.
5. Scroll to the bottom of the task pane and choose the Run link to write the
message subject to the task pane.
Next steps
Congratulations, you've successfully created your first Outlook task pane add-in!
Next, learn more about the capabilities of an Outlook add-in and build a more
complex add-in by following along with the Outlook add-in tutorial.
See also
Using Visual Studio Code to publish
Build your first PowerPoint task pane
add-in
Article • 01/10/2023
In this article, you'll walk through the process of building a PowerPoint task pane add-in.
Yeoman generator
Prerequisites
7 Note
If you aren't familiar with Node.js or npm, you should start by setting up your
development environment.
The latest version of Yeoman and the Yeoman generator for Office Add-ins.
To install these tools globally, run the following command via the command
prompt.
command line
7 Note
command line
yo office
7 Note
When you run the yo office command, you may receive prompts about the
data collection policies of Yeoman and the Office Add-in CLI tools. Use the
information that's provided to respond to the prompts as you see fit.
When prompted, provide the following information to create your add-in project.
After you complete the wizard, the generator creates the project and installs
supporting Node components.
Tip
You can ignore the next steps guidance that the Yeoman generator provides
after the add-in project's been created. The step-by-step instructions within
this article provide all of the guidance you'll need to complete this tutorial.
The ./manifest.xml file in the root directory of the project defines the settings
and capabilities of the add-in. To learn more about the manifest.xml file, see
Office Add-ins XML manifest.
The ./src/taskpane/taskpane.html file contains the HTML markup for the task
pane.
The ./src/taskpane/taskpane.css file contains the CSS that's applied to
content in the task pane.
The ./src/taskpane/taskpane.js file contains the Office JavaScript API code
that facilitates interaction between the task pane and the Office client
application.
Try it out
1. Navigate to the root folder of the project.
command line
2. Complete the following steps to start the local web server and sideload your
add-in.
7 Note
Office Add-ins should use HTTPS, not HTTP, even while you're
developing. If you're prompted to install a certificate after you run one of
the following commands, accept the prompt to install the certificate that
the Yeoman generator provides. You may also have to run your command
prompt or terminal as an administrator for the changes to be made.
Tip
If you're testing your add-in on Mac, run the following command before
proceeding. When you run this command, the local web server starts.
command line
command line
npm start
7 Note
command line
https://contoso.sharepoint.com/:t:/g/EZGxP7ksiE5DuxvY638G798Bpuhwl
uxCMfF1WZQj3VYhYQ?e=F4QM1R
e=RSccmNP
If your add-in doesn't sideload in the document, manually sideload it by
following the instructions in Manually sideload add-ins to Office on the
web.
3. In PowerPoint, insert a new blank slide, choose the Home tab, and then
choose the Show Taskpane button on the ribbon to open the add-in task
pane.
4. At the bottom of the task pane, choose the Run link to insert the text "Hello
World" into the current slide.
Next steps
Congratulations, you've successfully created a PowerPoint task pane add-in! Next,
learn more about the capabilities of a PowerPoint add-in and build a more complex
add-in by following along with the PowerPoint add-in tutorial.
See also
Office Add-ins platform overview
Develop Office Add-ins
Using Visual Studio Code to publish
Build your first Project task pane add-in
Article • 05/02/2023
In this article, you'll walk through the process of building a Project task pane add-in.
Prerequisites
7 Note
If you aren't familiar with Node.js or npm, you should start by setting up your
development environment.
The latest version of Yeoman and the Yeoman generator for Office Add-ins. To
install these tools globally, run the following command via the command prompt.
command line
7 Note
command line
yo office
7 Note
When you run the yo office command, you may receive prompts about the data
collection policies of Yeoman and the Office Add-in CLI tools. Use the information
that's provided to respond to the prompts as you see fit.
When prompted, provide the following information to create your add-in project.
After you complete the wizard, the generator creates the project and installs supporting
Node components.
Tip
You can ignore the next steps guidance that the Yeoman generator provides after
the add-in project's been created. The step-by-step instructions within this article
provide all of the guidance you'll need to complete this tutorial.
The ./manifest.xml file in the root directory of the project defines the settings and
capabilities of the add-in.
The ./src/taskpane/taskpane.html file contains the HTML markup for the task
pane.
The ./src/taskpane/taskpane.css file contains the CSS that's applied to content in
the task pane.
The ./src/taskpane/taskpane.js file contains the Office JavaScript API code that
facilitates interaction between the task pane and the Office client application. In
this quick start, the code sets the Name field and Notes field of the selected task of
a project.
Try it out
1. Navigate to the root folder of the project.
command line
7 Note
Office Add-ins should use HTTPS, not HTTP, even when you are developing. If
you are prompted to install a certificate after you run one of the following
commands, accept the prompt to install the certificate that the Yeoman
generator provides. You may also have to run your command prompt or
terminal as an administrator for the changes to be made.
Run the following command in the root directory of your project. When you run
this command, the local web server will start.
command line
4. Load your add-in in Project by following the instructions in Sideload Office Add-ins
on Windows.
Next steps
Congratulations, you've successfully created a Project task pane add-in! Next, learn
more about the capabilities of a Project add-in and explore common scenarios.
Project add-ins
See also
Develop Office Add-ins
Core concepts for Office Add-ins
Using Visual Studio Code to publish
Build your first Word task pane add-in
Article • 04/17/2023
In this article, you'll walk through the process of building a Word task pane add-in.
Yeoman generator
Prerequisites
7 Note
If you aren't familiar with Node.js or npm, you should start by setting up your
development environment.
The latest version of Yeoman and the Yeoman generator for Office Add-ins.
To install these tools globally, run the following command via the command
prompt.
command line
7 Note
command line
yo office
7 Note
When you run the yo office command, you may receive prompts about the
data collection policies of Yeoman and the Office Add-in CLI tools. Use the
information that's provided to respond to the prompts as you see fit.
When prompted, provide the following information to create your add-in project.
After you complete the wizard, the generator creates the project and installs
supporting Node components.
Tip
You can ignore the next steps guidance that the Yeoman generator provides
after the add-in project's been created. The step-by-step instructions within
this article provide all of the guidance you'll need to complete this tutorial.
The ./manifest.xml file in the root directory of the project defines the settings
and capabilities of the add-in. To learn more about the manifest.xml file, see
Office Add-ins XML manifest.
The ./src/taskpane/taskpane.html file contains the HTML markup for the task
pane.
The ./src/taskpane/taskpane.css file contains the CSS that's applied to
content in the task pane.
The ./src/taskpane/taskpane.js file contains the Office JavaScript API code
that facilitates interaction between the task pane and the Office client
application.
Try it out
1. Navigate to the root folder of the project.
command line
2. Complete the following steps to start the local web server and sideload your
add-in.
7 Note
Office Add-ins should use HTTPS, not HTTP, even while you're
developing. If you're prompted to install a certificate after you run one of
the following commands, accept the prompt to install the certificate that
the Yeoman generator provides. You may also have to run your command
prompt or terminal as an administrator for the changes to be made.
Tip
If you're testing your add-in on Mac, run the following command before
proceeding. When you run this command, the local web server starts.
command line
To test your add-in in Word, run the following command in the root
directory of your project. This starts the local web server (if it's not
already running) and opens Word with your add-in loaded.
command line
npm start
7 Note
command line
https://contoso.sharepoint.com/:t:/g/EZGxP7ksiE5DuxvY638G798Bpuhwl
uxCMfF1WZQj3VYhYQ?e=F4QM1R
npm run start:web -- --document
https://1drv.ms/x/s!jkcH7spkM4EGgcZUgqthk4IK3NOypVw?e=Z6G1qp
npm run start:web -- --document https://contoso-my.sharepoint-
df.com/:t:/p/user/EQda453DNTpFnl1bFPhOVR0BwlrzetbXvnaRYii2lDr_oQ?
e=RSccmNP
If your add-in doesn't sideload in the document, manually sideload it by
following the instructions in Manually sideload add-ins to Office on the
web.
3. In Word, if the "My Office Add-in" task pane isn't already open, open a new
document, choose the Home tab, and then choose the Show Taskpane button
on the ribbon to open the add-in task pane.
4. At the bottom of the task pane, choose the Run link to add the text "Hello
World" to the document in blue font.
Next steps
Congratulations, you've successfully created a Word task pane add-in! Next, learn
more about the capabilities of a Word add-in and build a more complex add-in by
following along with the Word add-in tutorial.
Code samples
Word "Hello world" add-in : Learn how to build a simple Office Add-in with only
a manifest, HTML web page, and a logo.
See also
Office Add-ins platform overview
Develop Office Add-ins
Word add-ins overview
Word add-in code samples
Word JavaScript API reference
Using Visual Studio Code to publish
Single sign-on (SSO) quick start
Article • 05/02/2023
In this article, you'll use the Yeoman generator for Office Add-ins to create an Office
Add-in for Excel, Outlook, Word, or PowerPoint that uses single sign-on (SSO).
7 Note
The SSO template provided by the Yeoman generator for Office Add-ins only runs
on localhost and cannot be deployed. If you're building a new Office Add-in with
SSO for production purposes, follow the instructions in Create a Node.js Office
Add-in that uses single sign-on.
Prerequisites
Node.js (the latest LTS version).
The latest version of Yeoman and the Yeoman generator for Office Add-ins. To
install these tools globally, run the following command via the command prompt.
command line
7 Note
If you're using a Mac and don't have the Azure CLI installed on your machine, you
must install Homebrew . The SSO configuration script that you'll run during this
quick start will use Homebrew to install the Azure CLI, and will then use the Azure
CLI to configure SSO within Azure.
Tip
The Yeoman generator can create an SSO-enabled Office Add-in for Excel, Outlook,
Word, or PowerPoint with script type of JavaScript or TypeScript. The following
instructions specify JavaScript and Excel , but you should choose the script type
and Office client application that best suits your scenario.
Run the following command to create an add-in project using the Yeoman generator.
command line
yo office
7 Note
When you run the yo office command, you may receive prompts about the data
collection policies of Yeoman and the Office Add-in CLI tools. Use the information
that's provided to respond to the prompts as you see fit.
When prompted, provide the following information to create your add-in project.
Choose a project type: Office Add-in Task Pane project supporting single sign-
on (localhost)
Choose a script type: JavaScript
What do you want to name your add-in? My Office Add-in
Which Office client application would you like to support? Choose Excel ,
Outlook , Word , or Powerpoint .
After you complete the wizard, the generator creates the project and installs supporting
Node components.
Tip
You can ignore the next steps guidance that the Yeoman generator provides after
the add-in project's been created. The step-by-step instructions within this article
provide all of the guidance you'll need to complete this tutorial.
Configuration
The following files specify configuration settings for the add-in.
The ./manifest.xml file in the root directory of the project defines the settings and
capabilities of the add-in.
The ./.ENV file in the root directory of the project defines constants that are used
by the add-in project.
Task pane
The following files define the add-in's task pane UI and functionality.
The ./src/taskpane/taskpane.html file contains the HTML markup for the task
pane.
Authentication
The following files facilitate the SSO process and write data to the Office document.
Configure SSO
Now that your add-in project is created and contains the code that's necessary to
facilitate the SSO process, complete the following steps to configure SSO for your add-
in.
command line
command line
2 Warning
7 Note
4. After you enter your credentials, close the browser window and return to the
command prompt. As the SSO configuration process continues, you'll see status
messages being written to the console. As described in the console messages, files
within the add-in project that the Yeoman generator created are automatically
updated with data that's required by the SSO process.
1. When the SSO configuration process completes, run the following command to
build the project, start the local web server, and sideload your add-in in the
previously selected Office client application.
7 Note
Office Add-ins should use HTTPS, not HTTP, even when you are developing. If
you are prompted to install a certificate after you run one of the following
commands, accept the prompt to install the certificate that the Yeoman
generator provides. You may also have to run your command prompt or
terminal as an administrator for the changes to be made.
command line
npm start
2. When Excel, Word, or PowerPoint opens when you run the previous command,
make sure you're signed in with a user account that's a member of the same
Microsoft 365 organization as the Microsoft 365 administrator account that you
used to connect to Azure while configuring SSO in step 3 of the previous section.
Doing so establishes the appropriate conditions for SSO to succeed.
3. In the Office client application, choose the Home tab, and then choose Show
Taskpane to open the add-in task pane.
4. At the bottom of the task pane, choose the Get My User Profile Information
button to initiate the SSO process.
After a user accepts this permissions request, they won't be prompted again
in the future.
6. The add-in retrieves profile information for the signed-in user and writes it to the
document. The following image shows an example of profile information written to
an Excel worksheet.
Outlook
Complete the following steps to try out an Outlook add-in.
1. When the SSO configuration process completes, run the following command to
build the project and start the local web server.
7 Note
Office Add-ins should use HTTPS, not HTTP, even when you are developing. If
you are prompted to install a certificate after you run one of the following
commands, accept the prompt to install the certificate that the Yeoman
generator provides. You may also have to run your command prompt or
terminal as an administrator for the changes to be made.
command line
npm start
2. Follow the instructions in Sideload Outlook add-ins for testing to sideload the add-
in in Outlook. Make sure that you're signed in to Outlook with a user that's a
member of the same Microsoft 365 organization as the Microsoft 365
administrator account that you used to connect to Azure while configuring SSO in
step 3 of the previous section. Doing so establishes the appropriate conditions for
SSO to succeed.
4. In the message compose window, choose the Show Taskpane button to open the
add-in task pane.
5. At the bottom of the task pane, choose the Get My User Profile Information
button to initiate the SSO process.
6. If a dialog window appears to request permissions on behalf of the add-in, this
means that SSO is not supported for your scenario and the add-in has instead
fallen back to an alternate method of user authentication. This may occur when the
tenant administrator hasn't granted consent for the add-in to access Microsoft
Graph, or when the user isn't signed in to Office with a valid Microsoft account or
Microsoft 365 Education or Work account. Choose Accept to continue.
7 Note
After a user accepts this permissions request, they won't be prompted again
in the future.
7. The add-in retrieves profile information for the signed-in user and writes it to the
body of the email message.
Next steps
Congratulations, you've successfully created a task pane add-in that uses SSO when
possible, and uses an alternate method of user authentication when SSO is not
supported. To learn about customizing your add-in to add new functionality that
requires different permissions, see Customize your Node.js SSO-enabled add-in.
See also
Enable single sign-on for Office Add-ins
Customize your Node.js SSO-enabled add-in
Create a Node.js Office Add-in that uses single sign-on
Troubleshoot error messages for single sign-on (SSO)
Using Visual Studio Code to publish
Explore Office JavaScript API using
Script Lab
Article • 05/20/2023
Script Lab is a free tool for anyone to learn how to develop Office Add-ins. Script Lab
lets you to code and run the Office JavaScript APIs alongside your document in Excel,
Outlook, PowerPoint, and Word. Use this convenient tool to prototype and verify the
functionality you want in your own add-in.
Explore samples
Get started quickly with a collection of built-in sample snippets that show how to
complete tasks with the API. You can run the samples to instantly see the result in the
task pane or document, examine the samples to learn how the API works, and even use
samples to prototype your own add-in.
To call preview APIs within a snippet, you'll need to update the snippet's libraries to
use the beta content delivery network (CDN)
( https://appsforoffice.microsoft.com/lib/beta/hosted/office.js ) and the preview
type definitions @types/office-js-preview . Additionally, some preview APIs are
only accessible if you've signed up for the Microsoft 365 Insider program and
are running an Insider build of Office.
Import snippets
You can import a snippet into Script Lab either by specifying the URL to the public
GitHub gist where the snippet YAML is stored or by pasting in the complete YAML for
the snippet. This feature may be useful in scenarios where someone else has shared
their snippet with you by either publishing it to a GitHub gist or providing their snippet's
YAML.
Supported clients
Script Lab is supported for Excel, Word, and PowerPoint on the following clients.
Office on Windows*
Office on Mac
Office on the web
Outlook on Windows*
Outlook on Mac
Outlook on the web when using Chrome, Microsoft Edge, or Safari browsers
For more details on Script Lab for Outlook, see the related blog post .
) Important
* Script Lab no longer works with combinations of platform and Office version that
use the Trident (Internet Explorer) webview to host add-ins. This includes perpetual
versions of Office through Office 2019. For more information, see Browsers and
webview controls used by Office Add-ins.
Next steps
To use Script Lab in Excel, Word, or PowerPoint, install the Script Lab add-in from
AppSource.
To use Script Lab for Outlook, install the Script Lab for Outlook add-in from
AppSource.
You're welcome to expand the sample library in Script Lab by contributing new snippets
to the office-js-snippets GitHub repository.
When you're ready to create your first Office Add-in, try out the quick start for Excel,
Outlook, Word, OneNote, PowerPoint, or Project.
See also
Get Script Lab for Excel, Word, or Powerpoint
Get Script Lab for Outlook
Script Lab on GitHub
Developing Office Add-ins
Set up your development environment
Article • 03/09/2023
This guide helps you set up tools so you can create Office Add-ins by following our
quick starts or tutorials. If you already have these installed, you're ready to begin a quick
start, such as this Excel React quick start.
7 Note
Visual Studio for Mac doesn't include the project scaffolding templates for Office
Add-ins, so if your development computer is a Mac, you should work with the
Node.js environment.
Select the tab for the environment you choose.
Node.js environment
Node.js
npm
A code editor of your choice
Yo Office
The Office JavaScript linter
This guide assumes that you know how to use a command-line tool.
npm is an open source software registry from which to download the packages
used in developing Office Add-ins. It's usually installed automatically when you
install Node.js. To check if you already have npm installed and see the installed
version, run the following in the command line.
command line
npm -v
If, for any reason, you want to install it manually, run the following in the command
line.
command line
Tip
You may wish to use a Node version manager to allow you to switch between
multiple versions of Node.js and npm, but this isn't strictly necessary. For
details on how to do this, see npm's instructions .
Install a code editor
You can use any code editor or IDE that supports client-side development to build
your web part, such as:
command line
command line
If you create an Office Add-in project with the Yeoman generator for Office Add-ins
tool, then the rest of the setup is done for you. Run the linter with the following
command either in the terminal of an editor, such as Visual Studio Code, or in a
command prompt. Problems found by the linter appear in the terminal or prompt,
and also appear directly in the code when you're using an editor that supports
linter messages, such as Visual Studio Code. (For information about installing the
Yeoman generator, see Yeoman generator for Office Add-ins.)
command line
1. In the root of the project, create a text file named .eslintrc.json, if there isn't
one already there. Be sure it has properties named plugins and extends , both
of type array. The plugins array should include "office-addins" and the
extends array should include "plugin:office-addins/recommended" . The
JSON
{
"plugins": [
"office-addins"
],
"extends": [
"plugin:office-addins/recommended"
]
}
2. In the root of the project, open the package.json file and be sure that the
scripts array has the following member.
JSON
3. Run the linter with the following command either in the terminal of an editor,
such as Visual Studio Code, or in a command prompt. Problems found by the
linter appear in the terminal or prompt, and also appear directly in the code
when you're using an editor that supports linter messages, such as Visual
Studio Code.
command line
Next steps
Try creating your own add-in or use Script Lab to try built-in samples.
See also
Core concepts for Office Add-ins
Developing Office Add-ins
Design Office Add-ins
Test and debug Office Add-ins
Publish Office Add-ins
Learn about the Microsoft 365 Developer Program
Best practices for developing Office
Add-ins
Article • 05/20/2023
Effective add-ins offer unique and compelling functionality that extends Office
applications in a visually appealing way. To create a great add-in, provide an engaging
first-time experience for your users, design a first-class UI experience, and optimize your
add-in's performance. Apply the best practices described in this article to create add-ins
that help your users complete their tasks quickly and efficiently.
7 Note
If you plan to publish your add-in to AppSource and make it available within the
Office experience, make sure that you conform to the Commercial marketplace
certification policies. For example, to pass validation, your add-in must work across
all platforms that support the methods that you define (for more information, see
section 1120.3 and the Office Add-in application and availability page).
Reinforce the value proposition of your add-in on launch, rather than just asking
users to sign in.
If your content add-in binds to data in the user's document, include sample data
or a template to show users the data format to use.
Offer free trials. If your add-in requires a subscription, make some functionality
available without a subscription.
Make the sign-up experience simple. Prefill information, such as email and display
name, and skip email verifications.
Avoid pop-up windows. If you have to use them, guide the user to enable your
pop-up window.
For patterns that you can apply as you develop your first-run experience, see UX design
patterns for Office Add-ins.
Favor content over chrome. Avoid superfluous UI elements that don't add value to
the user experience.
Keep users in control. Ensure that users understand important decisions, and can
easily reverse actions the add-in performs.
Use branding to inspire trust and orient users. Do not use branding to overwhelm
or advertise to users.
Account for accessibility - make your add-in easy for all users to interact with, and
accommodate assistive technologies such as screen readers.
Design for all platforms and input methods, including mouse/keyboard and touch.
Ensure that your UI is responsive to different form factors.
7 Note
Ensure that all controls are appropriately sized for touch interaction. For example,
buttons have adequate touch targets, and input boxes are large enough for users
to enter input.
Ensure that your add-in works in both portrait and landscape modes. Be aware that
on touch devices, part of your add-in might be hidden by the soft keyboard.
7 Note
If you're using Fluent UI React for your design elements, many of these elements
are built into the design system.
Optimize and monitor add-in performance
Create the perception of fast UI responses. Your add-in should load in 500 ms or
less.
Use a content delivery network (CDN) to host images, resources, and common
libraries. Load as much as you can from one place.
Follow standard web practices to optimize your web page. In production, use only
minified versions of libraries. Only load resources that you need, and optimize how
resources are loaded.
If operations take time to execute, provide feedback to users. Note the thresholds
listed in the following table. For additional information, see Resource limits and
performance optimization for Office Add-ins.
Responsive 300-500 1 second Not fast, but still feels responsive. No feedback
ms necessary.
Continuous >500 5 seconds Medium wait, no longer feels responsive. Might need
ms feedback.
Monitor your service health, and use telemetry to monitor user success.
Minimize data exchanges between the add-in and the Office document. For more
information, see Avoid using the context.sync method in loops.
Use succinct and descriptive add-in titles. Include no more than 128 characters.
Write short, compelling descriptions of your add-in. Answer the question "What
problem does this add-in solve?".
Convey the value proposition of your add-in in your title and description. Don't
rely on your brand.
See also
Office Add-ins platform overview
Learn about the Microsoft 365 Developer Program
Office versions and requirement sets
Article • 08/15/2023
There are many versions of Office on several platforms, and they don't all support every
API in Office JavaScript API (Office.js). Office 2013 on Windows was the earliest version
of Office that supported Office Add-ins. You may not always have control over the
version of Office your users have installed. To handle this situation, we provide a system
called requirement sets to help you determine whether an Office application supports
the capabilities you need in your Office Add-in.
7 Note
7 Note
If your version of Office is different from this, see What version of Outlook do I
have? or About Office: What version of Office am I using? to understand how
to get this information for your version.
Deployment
How your add-in is deployed can affect your add-in's availability on the various
platforms and clients. To learn more about deployment options, see Deploy and publish
Office Add-ins.
Some Office applications have their own API requirement sets. For example, the first
requirement set for the Excel API was ExcelApi 1.1 and the first requirement set for the
Word API was WordApi 1.1 . Since then, multiple new ExcelApi requirement sets and
WordApi requirement sets have been added to provide additional API functionality.
In addition, other functionality such as add-in commands (ribbon extensibility) and the
ability to launch dialog boxes (Dialog API) were added to the Common API. Add-in
commands and Dialog API requirement sets are examples of API sets that various Office
applications share in common.
An add-in can only use APIs in requirement sets that are supported by the version of
Office application where the add-in is running. To know exactly which requirement sets
are available for a specific Office application version, refer to the following application-
specific requirement set articles.
Some requirement sets contain APIs that can be used by several Office applications. For
information about these requirement sets, refer to the following articles.
Office common requirement sets
Add-in commands requirement sets
Dialog API requirement sets
Dialog Origin requirement sets
Identity API requirement sets
Image Coercion requirement sets
Keyboard Shortcuts requirement sets
Open Browser Window requirement sets
Ribbon API requirement sets
Shared Runtime requirement sets
The version number of a requirement set, such as the "1.1" in ExcelApi 1.1 , is relative to
the Office application. The version number of a given requirement set (e.g., ExcelApi
1.1 ) does not correspond to the version number of Office.js or to requirement sets for
other Office applications (e.g., Word, Outlook, etc.). Requirement sets for the different
Office applications are released at different rates. For example, ExcelApi 1.5 was
released before the WordApi 1.3 requirement set.
The Office JavaScript API library (Office.js) includes all requirement sets that are currently
available. While there is such a thing as requirement sets ExcelApi 1.3 and WordApi
1.3 , there is no Office.js 1.3 requirement set. The latest release of Office.js is
maintained as a single Office endpoint delivered via the content delivery network (CDN).
For more details around the Office.js CDN, including how versioning and backward
compatibility is handled, see Understanding the Office JavaScript API.
See also
Specify Office applications and API requirements
Install the latest version of Office
Overview of update channels for Microsoft 365 Apps
Reimagine productivity with Microsoft 365 and Microsoft Teams
Requirements for running Office Add-
ins
Article • 05/20/2023
This article describes the software and device requirements for running Office Add-ins.
7 Note
If you plan to publish your add-in to AppSource and make it available within the
Office experience, make sure that you conform to the Commercial marketplace
certification policies. For example, to pass validation, your add-in must work across
all platforms that support the methods that you define (for more information, see
section 1120.3 and the Office Add-in application and availability page).
For a high-level view of where Office Add-ins are currently supported, see Office client
application and platform availability for Office Add-ins.
Server requirements
To be able to install and run any Office Add-in, you first need to deploy the manifest and
webpage files for the UI and code of your add-in to the appropriate server locations.
For all types of add-ins (content, Outlook, and task pane add-ins and add-in
commands), you need to deploy your add-in's webpage files to a web server, or web
hosting service, such as Microsoft Azure.
While not strictly required in all add-in scenarios, using an HTTPS endpoint for your
add-in is strongly recommended. Add-ins that are not SSL-secured (HTTPS) generate
unsecure content warnings and errors during use. If you plan to run your add-in in
Office on the web or publish your add-in to AppSource, it must be SSL-secured. If your
add-in accesses external data and services, it should be SSL-secured to protect data in
transit. Self-signed certificates can be used for development and testing, so long as the
certificate is trusted on the local machine.
Tip
When you develop and debug an add-in in Visual Studio, Visual Studio deploys and
runs your add-in's webpage files locally with IIS Express, and doesn't require an
additional web server.
For content and task pane add-ins, in the supported Office client applications - Excel,
PowerPoint, Project, or Word - you also need either an app catalog on SharePoint to
upload the add-in's XML manifest file, or you need to deploy the add-in using
Integrated Apps.
To test and run an Outlook add-in, the user's Outlook email account must reside on
Exchange 2013 or later, which is available through Microsoft 365, Exchange Online, or
through an on-premises installation. The user or administrator installs manifest files for
Outlook add-ins on that server.
7 Note
POP and IMAP email accounts in Outlook don't support Office Add-ins.
For Windows x86 and x64 desktops, and tablets such as Surface Pro:
The 32- or 64-bit version of Office 2013 or a later version, running on Windows
7 or a later version.
Excel 2013, Outlook 2013, PowerPoint 2013, Project Professional 2013, Project
2013 SP1, Word 2013, or a later version of the Office client, if you're testing or
running an Office Add-in specifically for one of these Office desktop clients.
Office desktop clients can be installed on premises or via Click-to-Run on the
client computer.
If you have a valid Microsoft 365 subscription and you don't have access to the
Office client, you can download and install the latest version of Office .
Microsoft Edge must be installed, but doesn't have to be the default browser. To
support Office Add-ins, the Office client that acts as host uses webview
components that are part of Microsoft Edge.
7 Note
Strictly speaking, it's possible to develop add-ins on a machine that has
Internet Explorer 11 (IE11) installed, but not Microsoft Edge. However, IE11
is used to run add-ins only on certain older combinations of Windows and
Office versions. See Browsers and webview controls used by Office Add-
ins for more details. We don't recommend using such old environments as
your primary add-in development environment. However, if you're likely to
have customers of your add-in that are working in these older
combinations, we recommend that you support the Trident webview that's
provided by Internet Explorer. For more information, see Support older
Microsoft webviews and Office versions.
Internet Explorer's Enhanced Security Configuration (ESC) must be turned
off for Office Web Add-ins to work. If you are using a Windows Server
computer as your client when developing add-ins, note that ESC is turned
on by default in Windows Server.
One of the following as the default browser: Internet Explorer 11, or the latest
version of Microsoft Edge, Chrome, Firefox, or Safari (Mac OS).
An HTML and JavaScript editor such as Visual Studio Code , Visual Studio and the
Microsoft Developer Tools , or non-Microsoft web development tool.
The following are the minimum client versions of Office on Mac that support Office
Add-ins.
7 Note
1 OWA for Android, OWA for iPad, and OWA for iPhone native apps have been
deprecated .
2
Modern Outlook on the web on iPhone and Android smartphones is no longer
required or available for testing Outlook add-ins.
3
Add-ins aren't supported in Outlook on Android, on iOS, and modern mobile web
with on-premises Exchange accounts.
Tip
You can distinguish between classic and modern Outlook in a web browser by
checking your mailbox toolbar.
modern
classic
See also
Office Add-ins platform overview
Office client application and platform availability for Office Add-ins
Browsers and webview controls used by Office Add-ins
Install the latest version of Office
Article • 05/11/2023
New developer features, including those still in preview, are delivered first to subscribers
who opt in to get the latest builds of Office.
3. Create a new file named configuration.xml and add the following XML.
XML
<!-- Office 365 client configuration file sample. To be used for Office
365 ProPlus apps,
Office 365 Business apps, Project Pro for Office 365 and Visio Pro for
Office 365.
The following sample allows you to download and install the 32 bit
version of the Office 365 ProPlus apps
and Visio Pro for Office 365 directly from the Office CDN using the
First Release Branch
settings -->
<Configuration>
<Add OfficeClientEdition="32" Branch="FirstReleaseCurrent">
<Product ID="O365ProPlusRetail">
<Language ID="en-us" />
</Product>
</Add>
</Configuration>
command line
7 Note
The command might take a long time to run without indicating progress.
When the installation process finishes, you will have the latest Office applications
installed. To verify that you have the latest build, go to File > Account from any Office
application. Under Office Updates, you'll see the (Office Insiders) label above the version
number.
Minimum Office builds for Office JavaScript API
requirement sets
Excel JavaScript API requirement sets
OneNote JavaScript API requirement sets
Outlook JavaScript API requirement sets
PowerPoint JavaScript API requirement sets
Word JavaScript API requirement sets
Dialog API requirement sets
Office Common API requirement sets
Browsers and webview controls used by
Office Add-ins
Article • 05/30/2023
Office Add-ins are web applications that are displayed using iframes when running in
Office on the web. In Office for desktop and mobile clients, Office Add-ins use an
embedded browser control (also known as a webview). Add-ins also need a JavaScript
engine to run the JavaScript. Both the embedded browser and the engine are supplied
by a browser installed on the user's computer. In this article, "webview" refers to the
combination of a webview control and a JavaScript engine.
7 Note
This article assumes that the add-in is running in a document that is not protected
with Windows Information Protection (WIP). For WIP-protected documents, there
are some exceptions to the information in this article. For more information, see
WIP-protected documents.
) Important
Webviews from Internet Explorer and Microsoft Edge Legacy are still used in
Office Add-ins
The following sections specify which browser is used for the various platforms and
operating systems.
Non-Windows platforms
For these platforms, the platform alone determines the browser that is used.
) Important
Conditional Access is not supported for Office Add-ins on iOS or Android. Those
add-ins use the Safari-based WKWebView or the Android-based WebView, not an
Edge-based browser control.
Windows
An add-in running on Windows might use any of three different webviews:
To determine whether Office 2016 or Office 2019 is retail or volume-licensed, use the
format of the Office version and build number. (For Office 2013 and Office 2021, the
distinction between volume-licensed and retail doesn't matter.)
Retail: For both Office 2016 and 2019, the format is YYMM (xxxxx.xxxxxx) , ending
with two blocks of five digits; for example, 2206 (Build 15330.20264 .
Volume-licensed:
For Office 2016, the format is 16.0.xxxx.xxxxx , ending with two blocks of four
digits; for example, 16.0.5197.1000 .
For Office 2019, the format is 1808 (xxxxx.xxxxxx) , ending with two blocks of
five digits; for example, 1808 (Build 10388.20027) . Note that the year and
month is always 1808 .
1
On Windows versions prior to Windows 11, the WebView2 control must be installed so
that Office can embed it. It's installed with perpetual Office 2021 or later; but it isn't
automatically installed with Microsoft Edge. If you have an earlier version of perpetual
Office, use the instructions for installing the control at Microsoft Edge WebView2 /
Embed web content ... with Microsoft Edge WebView2.
2
When you use either EdgeHTML or WebView2, the Windows Narrator (sometimes
called a "screen reader") reads the <title> tag in the page that opens in the task pane.
In Trident+, the Narrator reads the title bar of the task pane, which comes from the add-
in name that is specified in the add-in's manifest.
3 If your add-in uses an XML manifest and includes the <Runtimes> element in the
manifest or it uses the unified manifest and it includes an "extensions.runtimes.lifetime"
property, then it won't use EdgeHTML. If the conditions for using WebView2 are met,
then the add-in uses WebView2. Otherwise, it uses Trident+. For more information, see
Runtimes and Configure your Outlook add-in for event-based activation.
Windows 11, Microsoft 365 ver. < 16.0.116291 Doesn't Trident+ (Internet
Windows 10 matter Explorer 11)
ver. >= 1903
1 See the update history page and how to find your Office client version and update
channel for more details.
2
On Windows versions prior to Windows 11, the WebView2 control must be installed so
that Office can embed it. It's installed with Microsoft 365, Version 2101 or later, but it
isn't automatically installed with Microsoft Edge. If you have an earlier version of
Microsoft 365, use the instructions for installing the control at Microsoft Edge
WebView2 / Embed web content ... with Microsoft Edge WebView2. On Microsoft 365
builds before 16.0.14326.xxxxx, you must also create the registry key
HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\16.0\WEF\Win32WebView2 and
set its value to dword:00000001 .
3
When you use either EdgeHTML or WebView2, the Windows Narrator (sometimes
called a "screen reader") reads the <title> tag in the page that opens in the task pane.
In Trident+, the Narrator reads the title bar of the task pane, which comes from the add-
in name that is specified in the add-in's manifest.
4
If your add-in uses an XML manifest and includes the <Runtimes> element in the
manifest or it uses the unified manifest and it includes an "extensions.runtimes.lifetime"
property, then it won't use EdgeHTML. If the conditions for using WebView2 are met,
then the add-in uses WebView2. Otherwise, it uses Trident+. For more information, see
Runtimes and Configure your Outlook add-in for event-based activation.
Write your code in ECMAScript 2015 (also called ES6) or later JavaScript, or in
TypeScript, and then compile your code to ES5 JavaScript using a compiler such as
babel or tsc .
Write in ECMAScript 2015 or later JavaScript, but also load a polyfill library such
as core-js that enables IE to run your code.
For more information about these options, see Support older Microsoft webviews and
Office versions.
Also, Trident+ doesn't support some HTML5 features such as media, recording, and
location. To learn more, see Determine the webview the add-in is running in at runtime.
WIP-protected documents
Add-ins running in a WIP-protected document never use WebView2 (Microsoft Edge
Chromium-based). In the sections Perpetual versions of Office on Windows and
Microsoft 365 subscription versions of Office on Windows earlier in this article,
substitute EdgeHTML (Microsoft Edge Legacy) for WebView2 (Microsoft Edge
Chromium-based) wherever the latter appears.
See also
Requirements for Running Office Add-ins
Runtimes in Office Add-ins
Runtimes in Office Add-ins
Article • 07/21/2023
Types of runtimes
There are two types of runtimes used by Office Add-ins:
Details about these types are later in this article at JavaScript-only runtime and Browser
runtime.
The following table shows which possible features of an add-in use each type of
runtime.
dialog
function command
The following table shows the same information organized by which type of runtime is
used for the various possible features of an add-in.
In Office on the web, everything always runs in a browser type runtime. With one
exception, everything in an add-in on the web runs in the same browser process: the
browser process in which the user has opened Office on the web. The exception is when
a dialog is opened with a call of Office.ui.displayDialogAsync and the
DialogOptions.displayInIFrame option is not passed and set to true . When the option
isn't passed (so it has the default false value), the dialog opens in its own process. The
same principle applies to the OfficeRuntime.displayWebDialog method and the
OfficeRuntime.DisplayWebDialogOptions.displayInIFrame option.
When an add-in is running on a platform other than the web, the following principles
apply.
7 Note
By default, task panes, function commands, and Excel custom functions each run in
their own runtime process. However, for some Office host applications, the add-in
manifest can be configured so that any two, or all three, can run in the same
runtime. See Shared runtime.
Depending on the host Office application and the features used in the add-in, there may
be many runtimes in an add-in. Each usually will run in its own process but not
necessarily simultaneously. The following are examples.
A PowerPoint or Word add-in that doesn't share any runtimes, and includes the
following features, has as many as three runtimes.
A task pane
A function command
A dialog (A dialog can be launched from either the task pane or the function
command.)
7 Note
It's not a good practice to have multiple dialogs open simultaneously, but
if the add-in enables the user to open one from the task pane and another
from the function command at the same time, this add-in would have four
runtimes. A task pane, and a given invocation of a function command can
have only one open dialog at a time; but if the function command is
invoked multiple times, a new dialog is opened on top of its predecessor
with each invocation, so there could be many runtimes. The remainder of
this list ignores the possibility of multiple open dialogs.
An Excel add-in that doesn't share any runtimes, and includes the following
features, has as many as four runtimes.
A task pane
A function command
A custom function
A dialog (A dialog can be launched from either the task pane, the function
command, or a custom function.)
An Excel add-in with the same features and is configured to share the same
runtime across the task pane, function command, and custom function, has two
runtimes. A shared runtime can open only one dialog at a time.
An Excel add-in with the same features, except that it has no dialog, and is
configured to share the same runtime across the task pane, function command,
and custom function, has one runtime.
An Outlook add-in that has the following features has as many as four runtimes.
Shared runtimes aren't supported in Outlook.
A task pane
A function command
An event-based task or integrated spam reporting feature
A dialog (A dialog can be launched from either the task pane or the function
command, but not from an event-based task.)
7 Note
If you know that your add-in will only be used in Office on the web and that it
won't open any dialogs with the displayInIFrame option set to true , then
you can ignore this section. Since everything in your add-in runs in the same
runtime process, you can just use global variables to share data between
features.
As noted above in Types of runtimes, the type of runtime used by a feature
varies partly by platform. It's a good practice to avoid having add-in code that
branches based on platform, so the guidance in this section recommends
techniques that will work cross-platform. There is only one case, noted below,
in which branching code is required.
For Excel, PowerPoint, and Word add-ins, use a Shared runtime when any two or more
features, except dialogs, need to share data. In Outlook, or scenarios where sharing a
runtime isn't feasible, you need alternative methods. The parts of the add-in that are in
separate runtime processes don't share global data automatically and are treated by the
add-in's web application server as separate sessions, so Window.sessionStorage can't
be used to share data between them. The following guidance assumes that you're not
using a shared runtime.
Pass data between a dialog and its parent task pane, function command, or custom
function by using the Office.ui.messageParent and Dialog.messageChild methods.
7 Note
To share data between a task pane and a function command, store data in
Window.localStorage , which is shared across all runtimes that access the same
specific origin .
7 Note
Tip
To share data between an Excel custom function and any other runtime, use
OfficeRuntime.storage.
To share data between an Outlook event-based task and a task pane or function
command, you must branch your code by the value of the Office.context.platform
property.
When the value is PC (Windows), store and retrieve data using the
Office.sessionData APIs.
When the value is Mac , use Window.localStorage as described earlier in this list.
For more information, see Persist add-in state and settings and Get and set add-in
metadata for an Outlook add-in.
JavaScript-only runtime
The JavaScript-only runtime that is used in Office Add-ins is a modification of an open
source runtime originally created for React Native . It contains a JavaScript engine
supplemented with support for WebSockets , Full CORS (Cross-Origin Resource
Sharing) , and OfficeRuntime.storage. It doesn't have a rendering engine, and it
doesn't support cookies or local storage .
When used for an Excel custom function, the runtime starts up when either the
worksheet recalculates or the custom function calculates. It doesn't shut down until
the workbook is closed.
7 Note
A JavaScript-runtime uses less memory and starts up faster than a browser runtime, but
has fewer features.
Browser runtime
Office Add-ins use a different browser type runtime depending on the platform in which
Office is running (web, Mac, or Windows), and on the version and build of Windows and
Office. For example, if the user is running Office on the web in a FireFox browser, then
the Firefox runtime is used. If the user is running Office on Mac, then the Safari runtime
is used. If the user is running Office on Windows, then either an Edge or Internet
Explorer provides the runtime, depending on the version of Windows and Office. Details
can be found in Browsers and webview controls used by Office Add-ins.
All of these runtimes include an HTML rendering engine and provide support for
WebSockets , Full CORS (Cross-Origin Resource Sharing) , and local storage , and
cookies.
A browser runtime lifespan varies depending on the feature that it implements and on
whether it's being shared or not.
When an add-in with a task pane is launched, a browser runtime starts, unless it's a
shared runtime that is already running. If it's a shared runtime, it shuts down when
the document is closed. If it isn't a shared runtime, it shuts down when the task
pane is closed.
When a dialog is opened, a browser runtime starts. It shuts down when the dialog
is closed.
When a function command is executed (which happens when a user selects its
button or menu item), a browser runtime starts, unless it's a shared runtime that is
already running. If it's a shared runtime, it shuts down when the document is
closed. If it isn't a shared runtime, it shuts down when the first of the following
occurs.
The function command calls the completed method of its event parameter.
Five minutes have elapsed since the triggering event. (If a dialog was opened in
the function command and it's still open when the parent runtime times out, the
dialog runtime stays running until the dialog is closed.)
7 Note
When a runtime is being shared, it's possible for your code to close the task pane
without shutting down the add-in. See Show or hide the task pane of your Office
Add-in for more information.
A browser runtime has more features than a JavaScript-only runtime, but starts up
slower and uses more memory.
Shared runtime
A "shared runtime" isn't a type of runtime. It refers to a browser-type runtime that's
being shared by features of the add-in that would otherwise each have their own
runtime. Specifically, you have the option of configuring the add-in's task pane and
function commands to share a runtime. In an Excel add-in, you can also configure
custom functions to share the runtime of a task pane or function command or both.
When you do this, the custom functions are running in a browser-type runtime, instead
of a JavaScript-only runtime as it otherwise would. See Configure your add-in to use a
shared runtime for information about the benefits and limitations of sharing runtimes
and instructions for configuring the add-in to use a shared runtime. In brief, the
JavaScript-only runtime uses less memory and starts up faster, but has fewer features.
7 Note
Office Add-ins are web applications that are displayed inside iframes when running on
Office on the web. Office Add-ins are displayed using an embedded browser control
(also known as a webview) when running in Office on Windows or Office on the Mac.
The embedded browser controls are supplied by the operating system or by a browser
installed on the user's computer.
) Important
Webviews from Internet Explorer and Microsoft Edge Legacy are still used in
Office Add-ins
We recommend (but don't require) that you support these combinations, at least in
a minimal way, by providing users of your add-in a graceful failure message when
your add-in is launched in these webviews. Keep these additional points in mind:
If you plan to support older versions of Windows and Office, your add-in must work in
the embeddable browser controls used by these versions. For example, browser controls
based on Internet Explorer 11 (IE11) or Microsoft Edge Legacy (EdgeHTML-based). For
information about which combinations of Windows and Office use these browser
controls, see Browsers and webview controls used by Office Add-ins.
JavaScript
7 Note
Microsoft Edge (Chromium) returns edg/ followed by one or more version digits
and zero or more . separators as the user agent; for example, edg/76.0.167.1 .
Note that the e isn't present at the end of name! It's "edg", not "edge".
This JavaScript should be as early in the add-in startup process as possible. The
following is an example of an add-in home page that advises users to upgrade Office
when Trident is detected.
HTML
<!doctype html>
<html lang="en" data-framework="typescript">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Contoso Task Pane Add-in</title>
<body>
<div id="main">
<!--
The add-in UI is here.
-->
</div>
<!--
The script below makes the following div display if the
webview is Trident, and hides the regular div.
-->
<div id="tridentmessage" style="display: none; padding: 10;">
This add-in will not run in your version of Office. Please upgrade
either to
perpetual Office 2021 (or later) or to a Microsoft 365 account.
</div>
<script>
if (navigator.userAgent.indexOf("Trident") !== -1) {
var tridentMessage = document.getElementById("tridentmessage");
var normalUI = document.getElementById("main");
tridentMessage.style.display = "block";
normalUI.style.display = "none";
}
</script>
</body>
</html>
) Important
It's not always a good practice to read the userAgent property. Be sure you're
familiar with the article, Browser detection using the user agent , including the
recommendations and alternatives to reading userAgent . In particular, if you're
providing an alternate add-in experience to support the use of Trident, consider
using feature detection instead of testing for the user agent. But if you're just
providing a notification that the add-in doesn't work in Trident, as in this case,
using userAgent is appropriate.
As of July 24th, 2023, the non-English versions of the article are all out-of-date to
varying degrees; some are over 12 years out-of-date.
As of the same date, the text and tables in the section Which part of the user
agent contains the information you are looking for? of the English version of
the article no longer mention Trident or Internet Explorer 11. In the table for
Browser Name and version, the row for Internet Explorer 11 was the following:
In the table for Rendering engine, the row for Trident was the following:
Tride Trident/xy Internet Explorer places this fragment in the comments section of the
nt z User-Agent string.
) Important
Trident doesn't support some HTML5 features such as media, recording, and
location. If your add-in must support Trident, then you must either design the
add-in to avoid these unsupported features or the add-in must detect when
Trident is being used and provide an alternate experience that doesn't use the
unsupported features. For more information, see Determine the webview the
add-in is running in at runtime.
Use a transpiler
You can write your code in either TypeScript or modern JavaScript and then
transpile it at build-time into ES5 JavaScript. The resulting ES5 files are what you
upload to your add-in's web application.
There are two popular transpilers. Both of them can work with source files that are
TypeScript or post-ES5 JavaScript. They also work with React files (.jsx and .tsx).
babel
tsc
See the documentation for either of them for information about installing and
configuring the transpiler in your add-in project. We recommend that you use a
task runner, such as Grunt or WebPack to automate the transpilation. For a
sample add-in that uses tsc, see Office Add-in Microsoft Graph React . For a
sample that uses babel, see Offline Storage Add-in .
7 Note
If you're using Visual Studio (not Visual Studio Code), tsc is probably easiest to
use. You can install support for it with a nuget package. For more information,
see JavaScript and TypeScript in Visual Studio 2019. To use babel with Visual
Studio, create a build script or use the Task Runner Explorer in Visual Studio
with tools like the WebPack Task Runner or NPM Task Runner .
Use a polyfill
A polyfill is earlier-version JavaScript that duplicates functionality from more
recent versions of JavaScript. The polyfill works in webviews that don't support the
later JavaScript versions. For example, the string method startsWith wasn't part of
the ES5 version of JavaScript, and so it won't run in Trident (Internet Explorer 11).
There are polyfill libraries, written in ES5, that define and implement a startsWith
method. We recommend the core-js polyfill library.
To use a polyfill library, load it like any other JavaScript file or module. For example,
you can use a <script> tag in the add-in's home page HTML file (for example
<script src="/js/core-js.js"></script> ), or you can use an import statement in a
JavaScript file (for example, import 'core-js'; ). When the JavaScript engine sees a
method like startsWith , it will first look to see if there's a method of that name
built into the language. If there is, it will call the native method. If, and only if, the
method isn't built-in, the engine will look in all loaded files for it. So, the polyfilled
version isn't used in browsers that support the native version.
Importing the entire core-js library will import all core-js features. You can also
import only the polyfills that your Office Add-in requires. For instructions about
how to do this, see CommonJS APIs . The core-js library has most of the polyfills
that you need. There are a few exceptions detailed in the Missing Polyfills section
of the core-js documentation. For example, it doesn't support fetch , but you can
use the fetch polyfill.
For a sample add-in that uses core.js, see Word Add-in Angular2 StyleChecker .
See also
Browsers and webview controls used by Office Add-ins
ECMAScript 6 compatibility table
Can I use... Support tables for HTML5, CSS3, etc
Develop Office Add-ins
Article • 05/30/2023
Tip
Please review Office Add-ins platform overview before reading this article.
All Office Add-ins are built upon the Office Add-ins platform. For any add-in you build,
you'll need to understand important concepts like application and platform availability,
Office JavaScript API programming patterns, how to specify an add-in's settings and
capabilities in the manifest file, how to design the UI and user experience, and more.
Core development concepts like these are covered here in the Development lifecycle >
Develop section of the documentation. Review the information here before exploring
the application-specific documentation that corresponds to the add-in you're building
(for example, Excel).
Yeoman generator
The Yeoman generator for Office Add-ins can be used to create a Node.js Office Add-in
project that can be managed with Visual Studio Code or any other editor. The generator
can create Office Add-ins for any of the following:
Excel
OneNote
Outlook
PowerPoint
Project
Word
Excel custom functions
Create your project using HTML, CSS and JavaScript (or TypeScript), or using React. If
you choose React, you can choose between JavaScript and Typescript as well. For more
information about creating add-ins with the generator, see Yeoman generator for Office
Add-ins.
Visual Studio
Visual Studio can be used to create Office Add-ins for Excel, Outlook, Word, and
PowerPoint. An Office Add-in project gets created as part of a Visual Studio solution and
uses HTML, CSS, and JavaScript. For more information about creating add-ins with
Visual Studio, see Develop Office Add-ins with Visual Studio.
7 Note
Although it's possible to create Office Add-ins using Visual Studio, using the
Yeoman generator provides a better developer experience in some notable ways.
The Yeoman generator provides a wider range of options for project types,
frameworks, and languages than Visual Studio does for Office Add-in projects.
Project templates in the Yeoman generator are updated more frequently than
project templates in Visual Studio.
Teams Toolkit
The Teams Toolkit can be used to create almost any kind of Teams App, a term which
includes all extensions of Microsoft 365, including those that don't extend the Teams
application. For details about creating an add-in, see Create Office Add-in projects with
Teams Toolkit.
The add-in manifest that defines the settings and capabilities of the add-in.
The web application that defines the UI and functionality of add-in components
such as task panes, content add-ins, and dialog boxes.
The web application uses the Office JavaScript API to interact with content in the Office
document where the add-in is running. Your add-in can also do other things that web
applications typically do, like call external web services, facilitate user authentication,
and more.
Metadata that describes the add-in (for example, ID, version, description, display
name, default locale).
Office applications where the add-in will run.
Permissions that the add-in requires.
How the add-in integrates with Office, including any custom UI that the add-in
creates (for example, a custom tab or custom ribbon buttons).
Location of images that the add-in uses for branding and command iconography.
Dimensions of the add-in (for example, dimensions for content add-ins, requested
height for Outlook add-ins).
Rules that specify when the add-in activates in the context of a message or
appointment (for Outlook add-ins only).
Keyboard shortcuts (for Excel only).
For detailed information about the manifest, see Office Add-ins manifest.
HTML
<head>
...
<script src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js"
type="text/javascript"></script>
</head>
7 Note
To use preview APIs, reference the preview version of the Office JavaScript API
library on the CDN:
https://appsforoffice.microsoft.com/lib/beta/hosted/office.js .
For more information about accessing the Office JavaScript API library, including how to
get IntelliSense, see Referencing the Office JavaScript API library from its content
delivery network (CDN).
API models
This API model uses promises and allows you to specify multiple operations in
each request you send to the Office application. Batching operations in this
manner can significantly improve add-in performance in Office applications on the
web. Application-specific APIs were introduced with Office 2016.
7 Note
There's also an application-specific API for Visio, but you can use it only in
SharePoint Online pages to interact with Visio diagrams that have been
embedded in the page. Office Web Add-ins are not supported in Visio.
See Using the application-specific API model to learn more about this API model.
Common APIs can be used to access features such as UI, dialogs, and client
settings that are common across multiple types of Office applications. This API
model uses callbacks , which allow you to specify only one operation in each
request sent to the Office application. Common APIs were introduced with Office
2013 and can be used to interact with any supported Office applications. For
details about the Common API object model, which includes APIs for interacting
with Outlook, PowerPoint, and Project, see Common JavaScript API object model.
7 Note
Requirement sets are named groups of API members. Requirement sets can be specific
to Office applications, such as the ExcelApi 1.7 requirement set (a set of APIs that can
only be used in Excel), or common to multiple applications, such as the DialogApi 1.1
requirement set (a set of APIs that can be used in any Office application that supports
the Dialog API).
Your add-in can use requirement sets to determine whether the Office application
supports the API members that it needs to use. For more information about this, see
Specify Office applications and API requirements.
Requirement set support varies by Office application, version, and platform. For detailed
information about the platforms, requirement sets, and Common APIs that each Office
application supports, see Office client application and platform availability for Office
Add-ins.
Add-in commands can be used to add a custom tab, custom buttons and menus
to the default ribbon in Office, or to extend the default context menu that appears
when users right-click text in an Office document or an object in Excel. When users
select an add-in command, they initiate the task that the add-in command
specifies, such as running JavaScript code, opening a task pane, or launching a
dialog box.
HTML containers like task panes, content add-ins, and dialog boxes can be used to
display custom UI and expose additional functionality within an Office application.
The content and functionality of each task pane, content add-in, or dialog box
derives from a web page that you specify. Those web pages can use the Office
JavaScript API to interact with content in the Office document where the add-in is
running, and can also do other things that web pages typically do, like call external
web services, facilitate user authentication, and more.
The following image shows an add-in command on the ribbon, a task pane to the right
of the document, and a dialog box or content add-in over the document.
For more information about extending the Office UI and designing the add-in's UX, see
Office UI elements for Office Add-ins.
Next steps
This article has outlined the different ways to create Office Add-ins, introduced the ways
that an add-in can extend the Office UI, described the API sets, and introduced Script
Lab as a valuable tool for exploring Office JavaScript APIs and prototyping add-in
functionality. Now that you've explored this introductory information, consider
continuing your Office Add-ins journey along the following paths.
Tip
For any add-in that you build, you'll use information in the Development lifecycle
section of this documentation, along with information in the application-specific
section that corresponds to the type of add-in you're building (for example, Excel).
See also
Office Add-ins platform overview
Learn about the Microsoft 365 Developer Program
Design Office Add-ins
Test and debug Office Add-ins
Publish Office Add-ins
Understanding the Office JavaScript API
Article • 05/18/2023
An Office Add-in can use the Office JavaScript APIs to interact with content in the Office
document where the add-in is running.
HTML
<head>
...
<script src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js"
type="text/javascript"></script>
</head>
7 Note
To use preview APIs, reference the preview version of the Office JavaScript API
library on the CDN:
https://appsforoffice.microsoft.com/lib/beta/hosted/office.js .
For more information about accessing the Office JavaScript API library, including how to
get IntelliSense, see Referencing the Office JavaScript API library from its content
delivery network (CDN).
API models
The Office JavaScript API includes two distinct models:
This API model uses promises and allows you to specify multiple operations in
each request you send to the Office application. Batching operations in this
manner can significantly improve add-in performance in Office applications on the
web. Application-specific APIs were introduced with Office 2016.
7 Note
There's also an application-specific API for Visio, but you can use it only in
SharePoint Online pages to interact with Visio diagrams that have been
embedded in the page. Office Web Add-ins are not supported in Visio.
See Using the application-specific API model to learn more about this API model.
Common APIs can be used to access features such as UI, dialogs, and client
settings that are common across multiple types of Office applications. This API
model uses callbacks , which allow you to specify only one operation in each
request sent to the Office application. Common APIs were introduced with Office
2013 and can be used to interact with any supported Office applications. For
details about the Common API object model, which includes APIs for interacting
with Outlook, PowerPoint, and Project, see Common JavaScript API object model.
7 Note
Requirement set support varies by Office application, version, and platform. For detailed
information about the platforms, requirement sets, and Common APIs that each Office
application supports, see Office client application and platform availability for Office
Add-ins.
7 Note
If you plan to publish your add-in to AppSource and make it available within the
Office experience, make sure that you conform to the Commercial marketplace
certification policies. For example, to pass validation, your add-in must work across
all platforms that support the methods that you define (for more information, see
section 1120.3 and the Office Add-in application and availability page).
See also
Office JavaScript API reference
Loading the DOM and runtime environment
Referencing the Office JavaScript API library
Initialize your Office Add-in
Runtimes in Office Add-ins
Application-specific API model
Article • 06/27/2023
This article describes how to use the API model for building add-ins in Excel, OneNote,
PowerPoint, Visio, and Word. It introduces core concepts that are fundamental to using
the promise-based APIs.
7 Note
This model isn't supported by Outlook or Project clients. Use the Common API
model to work with those applications. For full platform availability notes, see
Office client application and platform availability for Office Add-ins.
Tip
The examples in this page use the Excel JavaScript APIs, but the concepts also apply
to OneNote, PowerPoint, Visio, and Word JavaScript APIs. For complete code
samples that show how you could use these and other concepts in various Office
applications, see Office Add-in code samples.
*.run function
Excel.run , OneNote.run , PowerPoint.run , and Word.run execute a function that specifies
the actions to perform against Excel, Word, and OneNote. *.run automatically creates a
request context that you can use to interact with Office objects. When *.run completes,
a promise is resolved, and any objects that were allocated at runtime are automatically
released.
The following example shows how to use Excel.run . The same pattern is also used with
OneNote, PowerPoint, Visio, and Word.
JavaScript
Excel.run(function (context) {
// Add your Excel JS API calls here that will be batched and sent to the
workbook.
console.log('Your code goes here.');
}).catch(function (error) {
// Catch and log any errors that occur within `Excel.run`.
console.log('error: ' + error);
if (error instanceof OfficeExtension.Error) {
console.log('Debug info: ' + JSON.stringify(error.debugInfo));
}
});
Request context
The Office application and your add-in run in different processes. Since they use
different runtime environments, add-ins require a RequestContext object in order to
connect your add-in to objects in Office such as worksheets, ranges, paragraphs, and
tables. This RequestContext object is provided as an argument when calling *.run .
Proxy objects
The Office JavaScript objects that you declare and use with the promise-based APIs are
proxy objects. Any methods that you invoke or properties that you set or load on proxy
objects are simply added to a queue of pending commands. When you call the sync()
method on the request context (for example, context.sync() ), the queued commands
are dispatched to the Office application and run. These APIs are fundamentally batch-
centric. You can queue up as many changes as you wish on the request context, and
then call the sync() method to run the batch of queued commands.
For example, the following code snippet declares the local JavaScript Excel.Range object,
selectedRange , to reference a selected range in the Excel workbook, and then sets some
properties on that object. The selectedRange object is a proxy object, so the properties
that are set and the method that is invoked on that object will not be reflected in the
Excel document until your add-in calls context.sync() .
JavaScript
JavaScript
// GOOD: Create the range proxy object once and assign to a variable.
const range = worksheet.getRange("A1");
range.format.fill.color = "red";
range.numberFormat = "0.00%";
range.values = [[1]];
// ALSO GOOD: Use a "set" method to immediately set all the properties
// without even needing to create a variable!
worksheet.getRange("A1").set({
numberFormat: [["0.00%"]],
values: [[1]],
format: {
fill: {
color: "red"
}
}
});
sync()
Calling the sync() method on the request context synchronizes the state between proxy
objects and objects in the Office document. The sync() method runs any commands
that are queued on the request context and retrieves values for any properties that
should be loaded on the proxy objects. The sync() method executes asynchronously
and returns a Promise , which is resolved when the sync() method completes.
The following example shows a batch function that defines a local JavaScript proxy
object ( selectedRange ), loads a property of that object, and then uses the JavaScript
promises pattern to call context.sync() to synchronize the state between proxy objects
and objects in the Excel document.
JavaScript
In the previous example, selectedRange is set and its address property is loaded when
context.sync() is called.
Since sync() is an asynchronous operation, you should always return the Promise
object to ensure the sync() operation completes before the script continues to run. If
you're using TypeScript or ES6+ JavaScript, you can await the context.sync() call
instead of returning the promise.
load()
Before you can read the properties of a proxy object, you must explicitly load the
properties to populate the proxy object with data from the Office document, and then
call context.sync() . For example, if you create a proxy object to reference a selected
range, and then want to read the selected range's address property, you need to load
the address property before you can read it. To request properties of a proxy object be
loaded, call the load() method on the object and specify the properties to load. The
following example shows the Range.address property being loaded for myRange .
JavaScript
myRange.load('address');
await context.sync();
console.log (myRange.address); // ok
//console.log (myRange.values); // not ok as it was not loaded
console.log('done');
});
7 Note
If you're only calling methods or setting properties on a proxy object, you don't
need to call the load() method. The load() method is only required when you
want to read properties on a proxy object.
Just like requests to set properties or invoke methods on proxy objects, requests to load
properties on proxy objects get added to the queue of pending commands on the
request context, which will run the next time you call the sync() method. You can queue
up as many load() calls on the request context as necessary.
There are two categories of properties: scalar and navigational. Scalar properties are
assignable types such as strings, integers, and JSON structs. Navigation properties are
read-only objects and collections of objects that have their fields assigned, instead of
directly assigning the property. For example, name and position members on the
Excel.Worksheet object are scalar properties, whereas protection and tables are
navigation properties.
Your add-in can use navigational properties as a path to load specific scalar properties.
The following code queues up a load command for the name of the font used by an
Excel.Range object, without loading any other information.
JavaScript
someRange.load("format/font/name")
You can also set the scalar properties of a navigation property by traversing the path.
For example, you could set the font size for an Excel.Range by using
someRange.format.font.size = 10; . You don't need to load the property before you set
it.
Please be aware that some of the properties under an object may have the same name
as another object. For example, format is a property under the Excel.Range object, but
format itself is an object as well. So, if you make a call such as range.load("format") ,
) Important
The amount of data returned by a parameter-less load statement can exceed the
size limits of the service. To reduce the risks to older add-ins, some properties are
not returned by load without explicitly requesting them. The following properties
are excluded from such load operations.
Excel.Range.numberFormatCategories
ClientResult
Methods in the promise-based APIs that return primitive types have a similar pattern to
the load / sync paradigm. As an example, Excel.TableCollection.getCount gets the
number of tables in the collection. getCount returns a ClientResult<number> , meaning
the value property in the returned ClientResult is a number. Your script can't access that
value until context.sync() is called.
The following code gets the total number of tables in an Excel workbook and logs that
number to the console.
JavaScript
// Trying to log the value before calling sync would throw an error.
console.log (tableCount.value);
set()
Setting properties on an object with nested navigation properties can be cumbersome.
As an alternative to setting individual properties using navigation paths as described
above, you can use the object.set() method that is available on objects in the
promise-based JavaScript APIs. With this method, you can set multiple properties of an
object at once by passing either another object of the same Office.js type or a JavaScript
object with properties that are structured like the properties of the object on which the
method is called.
The following code sample sets several format properties of a range by calling the
set() method and passing in a JavaScript object with property names and types that
mirror the structure of properties in the Range object. This example assumes that there
is data in range B2:E2.
JavaScript
JavaScript
In the previous example, you would not be able to directly assign zoom a value:
sheet.pageLayout.zoom.scale = 200; . That statement throws an error because zoom is
not loaded. Even if zoom were to be loaded, the set of scale will not take effect. All
context operations happen on zoom , refreshing the proxy object in the add-in and
overwriting locally set values.
JavaScript
// This will set the font size on the range during the next
`content.sync()`.
range.format.font.size = 10;
You can identify a property that cannot have its subproperties directly set by checking
its read-only modifier. All read-only properties can have their non-read-only
subproperties directly set. Writeable properties like PageLayout.zoom must be set with an
object at that level. In summary:
test for the existence of document entities without requiring exception handling code.
This is accomplished by using the *OrNullObject variations of methods and properties.
These variations return an object whose isNullObject property is set to true , if the
specified item doesn't exist, rather than throwing an exception.
For example, you can call the getItemOrNullObject() method on a collection such as
Worksheets to retrieve an item from the collection. The getItemOrNullObject() method
returns the specified item if it exists; otherwise, it returns an object whose isNullObject
property is set to true . Your code can then evaluate this property to determine whether
the object exists.
7 Note
The *OrNullObject variations do not ever return the JavaScript value null . They
return ordinary Office proxy objects. If the the entity that the object represents
does not exist then the isNullObject property of the object is set to true . Do not
test the returned object for nullity or falsity. It is never null , false , or undefined .
The following code sample attempts to retrieve an Excel worksheet named "Data" by
using the getItemOrNullObject() method. If a worksheet with that name does not exist,
a new sheet is created. Note that the code does not load the isNullObject property.
Office automatically loads this property when context.sync is called, so you do not
need to explicitly load it with something like dataSheet.load('isNullObject') .
JavaScript
await context.sync();
if (dataSheet.isNullObject) {
dataSheet = context.workbook.worksheets.add("Data");
}
See also
Common JavaScript API object model
Resource limits and performance optimization for Office Add-ins
Common JavaScript API object model
Article • 03/21/2023
) Important
This article applies to the Common APIs, the Office JavaScript API model that was
introduced with Office 2013. These APIs include features such as UI, dialogs, and
client settings that are common across multiple types of Office applications.
Outlook add-ins exclusively use Common APIs, especially the subset of APIs
exposed through the Mailbox object.
You should only use Common APIs for scenarios that aren't supported by
application-specific APIs. To learn when to use Common APIs instead of
application-specific APIs, see Understanding the Office JavaScript API.
Office JavaScript APIs give access to the Office client application's underlying
functionality. Most of this access goes through a few important objects. The Context
object gives access to the runtime environment after initialization. The Document object
gives the user control over an Excel, PowerPoint, or Word document. The Mailbox object
gives an Outlook add-in access to messages, appointments, and user profiles.
Understanding the relationships between these high-level objects is the foundation of
an Office Add-in.
Context object
Applies to: All add-in types
When an add-in is initialized, it has many different objects that it can interact with in the
runtime environment. The add-in's runtime context is reflected in the API by the Context
object. The Context is the main object that provides access to the most important
objects of the API, such as the Document and Mailbox objects, which in turn provide
access to document and mailbox content.
For example, in task pane or content add-ins, you can use the document property of the
Context object to access the properties and methods of the Document object to
interact with the content of Word documents, Excel worksheets, or Project schedules.
Similarly, in Outlook add-ins, you can use the mailbox property of the Context object to
access the properties and methods of the Mailbox object to interact with the message,
meeting request, or appointment content.
The Context object also provides access to the contentLanguage and displayLanguage
properties that let you determine the locale (language) used in the document or item, or
by the Office application. The roamingSettings property lets you access the members of
the RoamingSettings object, which stores settings specific to your add-in for individual
users' mailboxes. Finally, the Context object provides a ui property that enables your
add-in to launch pop-up dialogs.
Document object
Applies to: Content and task pane add-in types
To interact with document data in Excel, PowerPoint, and Word, the API provides the
Document object. You can use Document object members to access data from the
following ways.
Read and write to active selections in the form of text, contiguous cells (matrices),
or tables.
You can also use the Document object to interact with data in Project documents. The
Project-specific functionality of the API is documented in the members
ProjectDocument abstract class. For more information about creating task pane add-ins
for Project, see Task pane add-ins for Project.
All these forms of data access start from an instance of the abstract Document object.
You can access an instance of the Document object when the task pane or content add-in
is initialized by using the document property of the Context object. The Document object
defines common data access methods shared across Word and Excel documents, and
also provides access to the CustomXmlParts object for Word documents.
The Document object supports four ways for developers to access document contents.
Selection-based access
Binding-based access
Custom XML part-based access (Word only)
To help you understand how selection- and binding-based data access methods work,
we will first explain how the data-access APIs provide consistent data access across
different Office applications.
To create extensions that seamlessly work across different Office documents, the Office
JavaScript API abstracts away the particularities of each Office application through
common data types and the ability to coerce different document contents into three
common data types.
Text Provides a string In Excel, Project, and PowerPoint, only plain text is
representation of the data in supported. In Word, three text formats are supported:
the selection or binding. plain text, HTML, and Office Open XML (OOXML). When
text is selected in a cell in Excel, selection-based
methods read and write to the entire contents of the
cell, even if only a portion of the text is selected in the
cell. When text is selected in Word and PowerPoint,
selection-based methods read and write only to the run
of characters that are selected. Project and PowerPoint
support only selection-based data access.
Data Description Host application support
type
Matrix Provides the data in the Matrix data access is supported only in Excel and Word.
selection or binding as a two
dimensional Array, which in
JavaScript is implemented as
an array of arrays. For
example, two rows of string
values in two columns would
be [['a', 'b'], ['c', 'd']] ,
and a single column of three
rows would be [['a'],
['b'], ['c']] .
Table Provides the data in the Table data access is supported only in Excel and Word.
selection or binding as a
TableData object. The
TableData object exposes the
data through the headers
and rows properties.
The data access methods on the Document and Binding objects support specifying the
desired data type using the coercionType parameter of these methods, and
corresponding CoercionType enumeration values. Regardless of the actual shape of the
binding, the different Office applications support the common data types by trying to
coerce the data into the requested data type. For example, if a Word table or paragraph
is selected, the developer can specify to read it as plain text, HTML, Office Open XML, or
a table, and the API implementation handles the necessary transformations and data
conversions.
Tip
When should you use the matrix versus table coercionType for data access? If
you need your tabular data to grow dynamically when rows and columns are
added, and you must work with table headers, you should use the table data type
(by specifying the coercionType parameter of a Document or Binding object data
access method as "table" or Office.CoercionType.Table ). Adding rows and
columns within the data structure is supported in both table and matrix data, but
appending rows and columns is supported only for table data. If you aren't
planning on adding rows and columns, and your data doesn't require header
functionality, then you should use the matrix data type (by specifying the
coercionType parameter of the data access method as "matrix" or
Office.CoercionType.Matrix ), which provides a simpler model of interacting with
the data.
If the data can't be coerced to the specified type, the AsyncResult.status property in the
callback returns "failed" , and you can use the AsyncResult.error property to access an
Error object with information about why the method call failed.
For code examples that demonstrate how to perform tasks with selections, see Read and
write data to the active selection in a document or spreadsheet.
Establishes a relationship between the add-in and the data in the document.
Bindings are persisted in the document, and can be accessed at a later time.
Establishing a binding also allows you to subscribe to data and selection change events
that are scoped to that particular region of the document or spreadsheet. This means
that the add-in is only notified of changes that happen within the bound region as
opposed to general changes across the whole document or spreadsheet.
The Bindings object exposes a getAllAsync method that gives access to the set of all
bindings established on the document or spreadsheet. An individual binding can be
accessed by its ID using either the Bindings.getBindingByIdAsync method or
Office.select function. You can establish new bindings as well as remove existing ones by
using one of the following methods of the Bindings object: addFromSelectionAsync,
addFromPromptAsync, addFromNamedItemAsync, or releaseByIdAsync.
There are three different types of bindings that you specify with the bindingType
parameter when you create a binding with the addFromSelectionAsync ,
addFromPromptAsync or addFromNamedItemAsync methods.
Text Binds to a region of the document that can be In Word, most contiguous
binding represented as text. selections are valid, while in
Excel only single cell selections
can be the target of a text
binding. In Excel, only plain
text is supported. In Word,
three formats are supported:
plain text, HTML, and Open
XML for Office.
Matrix Binds to a fixed region of a document that contains In Excel, any contiguous
binding tabular data without headers. Data in a matrix selection of cells can be used
binding is written or read as a two dimensional Array, to establish a matrix binding. In
which in JavaScript is implemented as an array of Word, only tables support
arrays. For example, two rows of string values in two matrix binding.
columns can be written or read as [['a', 'b'],
['c', 'd']] , and a single column of three rows can
be written or read as [['a'], ['b'], ['c']] .
Table Binds to a region of a document that contains a table Any Excel or Word table can be
binding with headers. Data in a table binding is written or the basis for a table binding.
read as a TableData object. The TableData object After you establish a table
exposes the data through the headers and rows binding, each new row or
properties. column a user adds to the
table is automatically included
in the binding.
After a binding is created by using one of the three "add" methods of the Bindings
object, you can work with the binding's data and properties by using the methods of the
corresponding object: MatrixBinding, TableBinding, or TextBinding. All three of these
objects inherit the getDataAsync and setDataAsync methods of the Binding object that
enable to you interact with the bound data.
For code examples that demonstrate how to perform tasks with bindings, see Bind to
regions in a document or spreadsheet.
The CustomXmlParts and CustomXmlPart objects of the API provide access to custom
XML parts in Word documents, which enable XML-driven manipulation of the contents
of the document. For demonstrations of working with the CustomXmlParts and
CustomXmlPart objects, see the Word-add-in-Work-with-custom-XML-parts code
sample.
The Document.getFileAsync method and members of the File and Slice objects to
provide functionality for getting entire Word and PowerPoint document files in slices
(chunks) of up to 4 MB at a time. For more information, see Get the whole document
from an add-in for PowerPoint or Word.
Mailbox object
Applies to: Outlook add-ins
Outlook add-ins primarily use a subset of the API exposed through the Mailbox object.
To access the objects and members specifically for use in Outlook add-ins, such as the
Item object, use the mailbox property of the Context object to access the Mailbox
object, as shown in the following line of code.
JavaScript
// Access the Item object.
const item = Office.context.mailbox.item;
For information about using JavaScript in Outlook add-ins, see Outlook add-ins.
Asynchronous programming in Office
Add-ins
Article • 04/11/2023
) Important
This article applies to the Common APIs, the Office JavaScript API model that was
introduced with Office 2013. These APIs include features such as UI, dialogs, and
client settings that are common across multiple types of Office applications.
Outlook add-ins exclusively use Common APIs, especially the subset of APIs
exposed through the Mailbox object.
You should only use Common APIs for scenarios that aren't supported by
application-specific APIs. To learn when to use Common APIs instead of
application-specific APIs, see Understanding the Office JavaScript API.
Why does the Office Add-ins API use asynchronous programming? Because JavaScript is
a single-threaded language, if script invokes a long-running synchronous process, all
subsequent script execution will be blocked until that process completes. Because
certain operations against Office web clients (but rich clients as well) could block
execution if they are run synchronously, most of the Office JavaScript APIs are designed
to execute asynchronously. This makes sure that Office Add-ins are responsive and fast.
It also frequently requires you to write callback functions when working with these
asynchronous methods.
The names of all asynchronous methods in the API end with "Async", such as the
Document.getSelectedDataAsync , Binding.getDataAsync , or
Item.loadCustomPropertiesAsync methods. When an "Async" method is called, it
executes immediately and any subsequent script execution can continue. The optional
callback function you pass to an "Async" method executes as soon as the data or
requested operation is ready. This generally occurs promptly, but there can be a slight
delay before it returns.
The following diagram shows the flow of execution for a call to an "Async" method that
reads the data the user selected in a document open in the server-based Word or Excel.
At the point when the "Async" call is made, the JavaScript execution thread is free to
perform any additional client-side processing (although none are shown in the
diagram). When the "Async" method returns, the callback resumes execution on the
thread, and the add-in can the access data, do something with it, and display the result.
The same asynchronous execution pattern holds when working with Office client
applications on Windows or Mac.
Support for this asynchronous design in both rich and web clients is part of the "write
once-run cross-platform" design goals of the Office Add-ins development model. For
example, you can create a content or task pane add-in with a single code base that will
run in both Excel on Windows and Excel on the web.
An anonymous function that must be written and passed directly in line with the
call to the "Async" method as the callback parameter of the "Async" method.
A named function, passing the name of that function as the callback parameter of
an "Async" method.
An anonymous function is useful if you are only going to use its code once - because it
has no name, you can't reference it in another part of your code. A named function is
useful if you want to reuse the callback function for more than one "Async" method.
Write an anonymous callback function
The following anonymous callback function declares a single parameter named result
that retrieves data from the AsyncResult.value property when the callback returns.
JavaScript
function (result) {
write('Selected data: ' + result.value);
}
The following example shows how to pass this anonymous callback function in line in
the context of a full "Async" method call to the Document.getSelectedDataAsync method.
The second callback argument is the anonymous function passed in-line to the
method. When the function executes, it uses the result parameter to access the
value property of the AsyncResult object to display the data selected by the user
in the document.
JavaScript
Office.context.document.getSelectedDataAsync(Office.CoercionType.Text,
function (result) {
write('Selected data: ' + result.value);
}
});
You can also use the parameter of your callback function to access other properties of
the AsyncResult object. Use the AsyncResult.status property to determine if the call
succeeded or failed. If your call fails you can use the AsyncResult.error property to
access an Error object for error information.
For more information about using the getSelectedDataAsync method, see Read and
write data to the active selection in a document or spreadsheet.
JavaScript
Office.context.document.getSelectedDataAsync(Office.CoercionType.Text,
writeDataCallback);
For example, the addHandlerAsync methods (of the Binding, CustomXmlPart, Document,
RoamingSettings, and Settings objects) are used to add event handler functions to the
items represented by these objects. You can access the AsyncResult.value property
from the callback function you pass to any of the addHandlerAsync methods, but since
no data or object is being accessed when you add an event handler, the value property
always returns undefined if you attempt to access it.
On the other hand, if you call the Document.getSelectedDataAsync method, it returns the
data the user selected in the document to the AsyncResult.value property in the
callback. Or, if you call the Bindings.getAllAsync method, it returns an array of all of the
Binding objects in the document. And, if you call the Bindings.getByIdAsync method, it
Asynchronous programming with callback functions frequently requires you to nest the
returned result of one callback within two or more callbacks. If you need to do so, you
can use nested callbacks from all "Async" methods of the API.
7 Note
In the current version of the Office JavaScript API, built-in support for the promises
pattern only works with code for bindings in Excel spreadsheets and Word
documents. However, you can wrap other functions that have callbacks inside your
own custom Promise-returning function. For more information, see Wrap Common
APIs in Promise-returning functions.
Then, the binding object accessed from the first result parameter is used to call
the Binding.getDataAsync method.
Finally, the result2 parameter of the callback passed to the Binding.getDataAsync
method is used to display the data in the binding.
JavaScript
function readData() {
Office.context.document.bindings.getByIdAsync("MyBinding", function
(result) {
result.value.getDataAsync({ coercionType: 'text' }, function
(result2) {
write(result2.value);
});
});
}
This basic nested callback pattern can be used for all asynchronous methods in the
Office JavaScript API.
The following sections show how to use either anonymous or named functions for
nested callbacks in asynchronous methods.
In the following example, two anonymous functions are declared inline and passed into
the getByIdAsync and getDataAsync methods as nested callbacks. Because the functions
are simple and inline, the intent of the implementation is immediately clear.
JavaScript
Office.context.document.bindings.getByIdAsync('myBinding', function
(bindingResult) {
bindingResult.value.getDataAsync(function (getResult) {
if (getResult.status == Office.AsyncResultStatus.Failed) {
write('Action failed. Error: ' + asyncResult.error.message);
} else {
write('Data has been read successfully.');
}
});
});
JavaScript
Office.context.document.bindings.getByIdAsync('myBinding', deleteAllData);
function deleteAllData(asyncResult) {
asyncResult.value.deleteAllDataValuesAsync(showResult);
}
function showResult(asyncResult) {
if (asyncResult.status == Office.AsyncResultStatus.Failed) {
write('Action failed. Error: ' + asyncResult.error.message);
} else {
write('Data has been deleted successfully.');
}
}
The Office JavaScript API provides the Office.select function to support the promises
pattern for working with existing binding objects. The promise object returned to the
Office.select function supports only the four methods that you can access directly
from the Binding object: getDataAsync, setDataAsync, addHandlerAsync, and
removeHandlerAsync.
The promises pattern for working with bindings takes this form.
Office.select(selectorExpression, onError).BindingObjectAsyncMethod
the selector expression bindings#cities specifies that you want to access the binding
with an id of 'cities'.
The onError parameter is an error handling function which takes a single parameter of
type AsyncResult that can be used to access an Error object, if the select function fails
to access the specified binding. The following example shows a basic error handler
function that can be passed to the onError parameter.
JavaScript
function onError(result){
const err = result.error;
write(err.name + ": " + err.message);
}
additional promises. You must call them using the nested callback function pattern.
After a Binding object promise is fulfilled, it can be reused in the chained method call as
if it were a binding (the add-in runtime won't asynchronously retry fulfilling the
promise). If the Binding object promise can't be fulfilled, the add-in runtime will try
again to access the binding object the next time one of its asynchronous methods is
invoked.
The following code example uses the select function to retrieve a binding with the id
" cities " from the Bindings collection, and then calls the addHandlerAsync method to
add an event handler for the dataChanged event of the binding.
JavaScript
function addBindingDataChangedEventHandler() {
Office.select("bindings#cities", function onError(){/* error handling
code */}).addHandlerAsync(Office.EventType.BindingDataChanged,
function (eventArgs) {
doSomethingWithBinding(eventArgs.binding);
});
}
) Important
You can create the object that contains optional parameters inline, or by creating an
options object and passing that in as the options parameter.
Pass optional parameters inline
For example, the syntax for calling the Document.setSelectedDataAsync method with
optional parameters inline looks like this:
JavaScript
Office.context.document.setSelectedDataAsync(data, {coercionType:
'coercionType', asyncContext: 'asyncContext'},callback);
In this form of the calling syntax, the two optional parameters, coercionType and
asyncContext, are defined as an anonymous JavaScript object inline enclosed in braces.
JavaScript
Office.context.document.setSelectedDataAsync(
"<html><body>hello world</body></html>",
{coercionType: "html", asyncContext: 42},
function(asyncResult) {
write(asyncResult.status + " " + asyncResult.asyncContext);
}
)
7 Note
You can specify optional parameters in any order in the parameter object as long as
their names are specified correctly.
JavaScript
const options = {
parameter1: value1,
parameter2: value2,
...
parameterN: valueN
};
Which looks like the following example when used to specify the ValueFormat and
FilterType parameters.
JavaScript
const options = {
valueFormat: "unformatted",
filterType: "all"
};
JavaScript
Which looks like the following example when used to specify the ValueFormat and
FilterType parameters:
JavaScript
7 Note
When using either method of creating the options object, you can specify optional
parameters in any order as long as their names are specified correctly.
JavaScript
const options = {
coercionType: "html",
asyncContext: 42
};
document.setSelectedDataAsync(
"<html><body>hello world</body></html>",
options,
function(asyncResult) {
write(asyncResult.status + " " + asyncResult.asyncContext);
}
)
In both optional parameter examples, the callback parameter is specified as the last
parameter (following the inline optional parameters, or following the options argument
object). Alternatively, you can specify the callback parameter inside either the inline
JavaScript object, or in the options object. However, you can pass the callback
parameter in only one location: either in the options object (inline or created
externally), or as the last parameter, but not both.
The basic pattern is to create an asynchronous method that returns a Promise object
immediately and resolves that Promise object when the inner method completes, or
rejects the object if the method fails. The following is a simple example.
JavaScript
function getDocumentFilePath() {
return new OfficeExtension.Promise(function (resolve, reject) {
try {
Office.context.document.getFilePropertiesAsync(function
(asyncResult) {
resolve(asyncResult.value.url);
});
}
catch (error) {
reject(WordMarkdownConversion.errorHandler(error));
}
})
}
When this function needs to be awaited, it can be either called with the await keyword
or passed to a then function.
7 Note
This technique is especially useful when you need to call a Common API inside a
call of the run function in an application-specific object model. For an example of
the getDocumentFilePath function being used in this way, see the file Home.js in
the sample Word-Add-in-JavaScript-MDConversion .
TypeScript
readDocumentFileAsync(): Promise<any> {
return new Promise((resolve, reject) => {
const chunkSize = 65536;
const self = this;
Office.context.document.getFileAsync(Office.FileType.Compressed, {
sliceSize: chunkSize }, (asyncResult) => {
if (asyncResult.status === Office.AsyncResultStatus.Failed) {
reject(asyncResult.error);
} else {
// `getAllSlices` is a Promise-wrapped implementation of
File.getSliceAsync.
self.getAllSlices(asyncResult.value).then(result => {
if (result.IsSuccess) {
resolve(result.Data);
} else {
reject(asyncResult.error);
}
});
}
});
});
}
See also
Understanding the Office JavaScript API
Office JavaScript API
Runtimes in Office Add-ins
Office JavaScript API support for
content and task pane add-ins
Article • 04/11/2023
) Important
This article applies to the Common APIs, the Office JavaScript API model that was
introduced with Office 2013. These APIs include features such as UI, dialogs, and
client settings that are common across multiple types of Office applications.
Outlook add-ins exclusively use Common APIs, especially the subset of APIs
exposed through the Mailbox object.
You should only use Common APIs for scenarios that aren't supported by
application-specific APIs. To learn when to use Common APIs instead of
application-specific APIs, see Understanding the Office JavaScript API.
You can use the Office JavaScript API to create task pane or content add-ins for Office
client applications. The objects and methods that content and task pane add-ins
support are categorized as follows:
1. Common objects shared with other Office Add-ins. These objects include Office,
Context, and AsyncResult. The Office object is the root object of the Office
JavaScript API. The Context object represents the add-in's runtime environment.
Both Office and Context are the fundamental objects for any Office Add-in. The
AsyncResult object represents the results of an asynchronous operation, such as
the data returned to the getSelectedDataAsync method, which reads what a user
has selected in a document.
2. The Document object. The majority of the API available to content and task pane
add-ins is exposed through the methods, properties, and events of the Document
object. A content or task pane add-in can use the Office.context.document
property to access the Document object, and through it, can access the key
members of the API for working with data in documents, such as the Bindings and
CustomXmlParts objects, and the getSelectedDataAsync, setSelectedDataAsync,
and getFileAsync methods. The Document object also provides the mode property
for determining whether a document is read-only or in edit mode, the url property
to get the URL of the current document, and access to the Settings object. The
Document object also supports adding event handlers for the SelectionChanged
event, so you can detect when a user changes their selection in the document.
A content or task pane add-in can access the Document object only after the DOM
and runtime environment has been loaded, typically in the event handler for the
Office.initialize event. For information about the flow of events when an add-in is
initialized, and how to check that the DOM and runtime and loaded successfully,
see Loading the DOM and runtime environment.
3. Objects for working with specific features. To work with specific features of the
API, use the following objects and methods.
The methods of the Bindings object to create or get bindings, and the
methods and properties of the Binding object to work with data.
The File and Slice objects to create a copy of the entire document, break it
into chunks or "slices", and then read or transmit the data in those slices.
The Settings object to save custom data, such as user preferences, and add-in
state.
) Important
Some of the API members aren't supported across all Office applications that can
host content and task pane add-ins. To determine which members are supported,
see any of the following:
For a summary of Office JavaScript API support across Office client applications, see
Understanding the Office JavaScript API.
Office.context.document.getSelectedDataAsync(
Office.CoercionType.Text, function (asyncResult) {
if (asyncResult.status == Office.AsyncResultStatus.Failed) {
write('Action failed. Error: ' + asyncResult.error.message);
}
else {
write('Selected data: ' + asyncResult.value);
}
});
For more details and examples, see Read and write data to the active selection in a
document or spreadsheet.
The following is an example that adds a binding to the currently selected text in a
document, by using the Bindings.addFromSelectionAsync method.
JavaScript
Office.context.document.bindings.addFromSelectionAsync(
Office.BindingType.Text, { id: 'myBinding' }, function (asyncResult) {
if (asyncResult.status == Office.AsyncResultStatus.Failed) {
write('Action failed. Error: ' + asyncResult.error.message);
} else {
write('Added new binding with type: ' +
asyncResult.value.type + ' and id: ' + asyncResult.value.id);
}
});
For more details and examples, see Bind to regions in a document or spreadsheet.
When you call Document.getFileAsync you get a copy of the document in a File object.
The File object provides access to the document in "chunks" represented as Slice
objects. When you call getFileAsync , you can specify the file type (text or compressed
Open Office XML format), and size of the slices (up to 4MB). To access the contents of
the File object, you then call File.getSliceAsync which returns the raw data in the
Slice.data property. If you specified compressed format, you will get the file data as a
byte array. If you are transmitting the file to a web service, you can transform the
compressed raw data to a base64-encoded string before submission. Finally, when you
are finished getting slices of the file, use the File.closeAsync method to close the
document.
For more details, see how to get the whole document from an add-in for PowerPoint or
Word.
You can also use the CustomXmlParts.getByIdAsync method to access custom XML parts
by their GUIDs. After getting a custom XML part, use the CustomXmlPart.getXmlAsync
method to get the XML data.
For detailed information about how to manage custom XML parts with a task pane add-
in, see Understand when and how to use Office Open XML in your Word add-in.
To avoid roundtrips to the server where the document is stored, data created with the
Settings object is managed in memory at run time. Previously saved settings data is
loaded into memory when the add-in is initialized, and changes to that data are only
saved back to the document when you call the Settings.saveAsync method. Internally,
the data is stored in a serialized JSON object as name/value pairs. You use the get, set,
and remove methods of the Settings object, to read, write, and delete items from the in-
memory copy of the data. The following line of code shows how to create a setting
named themeColor and set its value to 'green'.
JavaScript
Office.context.document.settings.set('themeColor', 'green');
Because settings data created or deleted with the set and remove methods is acting on
an in-memory copy of the data, you must call saveAsync to persist changes to settings
data into the document your add-in is working with.
For more details about working with custom data using the methods of the Settings
object, see Persisting add-in state and settings.
For examples of reading Project data, see Create your first task pane add-in for Project.
exist to protect a user's privacy and security, as a best practice you should request the
minimum level of permissions it needs for its features. The following example shows
how to request the ReadDocument permission in a task pane's manifest.
XML
For more information, see Requesting permissions for API use in add-ins.
See also
Office JavaScript API
Schema reference for Office Add-ins manifests
Troubleshoot user errors with Office Add-ins
Runtimes in Office Add-ins
Persist add-in state and settings
Article • 06/08/2023
) Important
This article applies to the Common APIs, the Office JavaScript API model that was
introduced with Office 2013. These APIs include features such as UI, dialogs, and
client settings that are common across multiple types of Office applications.
Outlook add-ins exclusively use Common APIs, especially the subset of APIs
exposed through the Mailbox object.
You should only use Common APIs for scenarios that aren't supported by
application-specific APIs. To learn when to use Common APIs instead of
application-specific APIs, see Understanding the Office JavaScript API.
Office Add-ins are essentially web applications running in the stateless environment of a
browser iframe or a webview control. (For brevity hereafter, this article uses "browser
control" to mean "browser or webview control".) When in use, your add-in may need to
persist data to maintain the continuity of certain operations or features across sessions.
For example, your add-in may have custom settings or other values that it needs to save
and reload the next time it's initialized, such as a user's preferred view or default
location. To do that, you can:
Use members of the Office JavaScript API that store data as either:
Name/value pairs in a property bag stored in a location that depends on add-in
type.
Custom XML stored in the document.
7 Note
This article focuses on how to use the Office JavaScript API to persist add-in state to the
current document. It's recommended that you use the application-specific object if it's
available for your selected Office client instead of the Common Office JavaScript version.
If you need to persist state across documents, such as tracking user preferences across
any documents they open, you'll need to use a different approach. For example, you
could use SSO to obtain the user identity, and then save the user ID and their settings to
an online database.
Outlook add-in
roaming settings are
available only to the
add-in that created
them, and only from
the mailbox where
the add-in is
installed.
Important: Don't
store passwords and
other sensitive
personally
identifiable
information (PII) in a
custom XML part.
The data saved isn't
visible to end users,
but it's stored as
part of the
document, which is
accessible by
reading the
document's file
format directly. You
should limit your
add-in's use of PII
and store any PII
required by your
add-in only on the
server hosting your
add-in as a user-
secured resource.
Settings data is managed in memory at
runtime
The following two sections discuss settings in the context of the Office Common
JavaScript API. The application-specific JavaScript APIs for Excel and for Word also
provide access to the custom settings. The application-specific APIs and programming
patterns are somewhat different from the Common version. For more information, see
Excel.SettingCollection and Word.SettingCollection.
Internally, the data in the property bag accessed with the Settings , CustomProperties ,
or RoamingSettings objects is stored as a serialized JavaScript Object Notation (JSON)
object that contains name/value pairs. The name (key) for each value must be a string ,
and the stored value can be a JavaScript string , number , date , or object , but not a
function.
This example of the property bag structure contains three defined string values named
firstName , location , and defaultView .
JSON
{
"firstName":"Erik",
"location":"98052",
"defaultView":"basic"
}
After the settings property bag is saved during the previous add-in session, it can be
loaded when the add-in is initialized or at any point after that during the add-in's
current session. During the session, the settings are managed in entirely in memory
using the get , set , and remove methods of the object that corresponds to the kind of
settings you're creating (Settings, CustomProperties, or RoamingSettings).
) Important
To persist any additions, updates, or deletions made during the add-in's current
session to the storage location, you must call the saveAsync method of the
corresponding object used to work with that kind of settings. The get , set , and
remove methods operate only on the in-memory copy of the settings property bag.
If your add-in is closed without calling saveAsync , any changes made to settings
during that session will be lost.
How to save add-in state and settings per
document for content and task pane add-ins
To persist state or custom settings of a content or task pane add-in for Word, Excel, or
PowerPoint, use the Settings object and its methods. The property bag created with the
methods of the Settings object are available only to the instance of the content or task
pane add-in that created it, and only from the document in which it is saved.
The Settings object is automatically loaded as part of the Document object, and is
available when the task pane or content add-in is activated. After the Document object is
instantiated, you can access the Settings object with the settings property of the
Document object. During the lifetime of the session, you can use the Settings.get ,
Because the set and remove methods operate against only the in-memory copy of the
settings property bag, to save new or changed settings back to the document the add-
in is associated with, you must call the Settings.saveAsync method.
JavaScript
Office.context.document.settings.set('themeColor', 'green');
The setting with the specified name is created if it doesn't already exist, or its value is
updated if it does exist. Use the Settings.saveAsync method to persist the new or
updated settings to the document.
The get method returns the value that was previously saved for the setting name that
was passed in. If the setting doesn't exist, the method returns null.
Remove a setting
The following example shows how to use the Settings.remove method to remove a
setting with the name "themeColor". The only parameter of the remove method is the
case-sensitive name of the setting.
JavaScript
Office.context.document.settings.remove('themeColor');
Nothing will happen if the setting doesn't exist. Use the Settings.saveAsync method to
persist removal of the setting from the document.
JavaScript
Office.context.document.settings.saveAsync(function (asyncResult) {
if (asyncResult.status == Office.AsyncResultStatus.Failed) {
write('Settings save failed. Error: ' + asyncResult.error.message);
} else {
write('Settings saved.');
}
});
// Function that writes to a div with id='message' on the page.
function write(message){
document.getElementById('message').innerText += message;
}
The anonymous function passed into the saveAsync method as the callback parameter is
executed when the operation is completed. The asyncResult parameter of the callback
provides access to an AsyncResult object that contains the status of the operation. In
the example, the function checks the AsyncResult.status property to see if the save
operation succeeded or failed, and then displays the result in the add-in's page.
A custom XML part is an available storage option for when you want to store
information that has a structured character or need the data to be accessible across
instances of your add-in. Note that data stored this way can also be accessed by other
add-ins. You can persist custom XML markup in a task pane add-in for Word (and for
Excel and Word using application-specific API as mentioned in the previous paragraph).
In Word, you can use the CustomXmlPart object and its methods. The following code
creates a custom XML part and displays its ID and then its content in divs on the page.
Note that there must be an xmlns attribute in the XML string.
JavaScript
function createCustomXmlPart() {
const xmlString = "<Reviewers
xmlns='http://schemas.contoso.com/review/1.0'><Reviewer>Juan</Reviewer>
<Reviewer>Hong</Reviewer><Reviewer>Sally</Reviewer></Reviewers>";
Office.context.document.customXmlParts.addAsync(xmlString,
(asyncResult) => {
$("#xml-id").text("Your new XML part's ID: " +
asyncResult.value.id);
asyncResult.value.getXmlAsync(
(asyncResult) => {
$("#xml-blob").text(asyncResult.value);
}
);
}
);
}
To retrieve a custom XML part, use the getByIdAsync method, but the ID is a GUID that
is generated when the XML part is created, so you can't know when coding what the ID
is. For that reason, it's a good practice when creating an XML part to immediately store
the ID of the XML part as a setting and give it a memorable key. The following method
shows how to do this.
JavaScript
function createCustomXmlPartAndStoreId() {
const xmlString = "<Reviewers
xmlns='http://schemas.contoso.com/review/1.0'><Reviewer>Juan</Reviewer>
<Reviewer>Hong</Reviewer><Reviewer>Sally</Reviewer></Reviewers>";
Office.context.document.customXmlParts.addAsync(xmlString,
(asyncResult) => {
Office.context.document.settings.set('ReviewersID',
asyncResult.id);
Office.context.document.settings.saveAsync();
}
);
}
The following code shows how to retrieve the XML part by first getting its ID from a
setting.
JavaScript
function getReviewers() {
const reviewersXmlId =
Office.context.document.settings.get('ReviewersID');
Office.context.document.customXmlParts.getByIdAsync(reviewersXmlId,
(asyncResult) => {
asyncResult.value.getXmlAsync(
(asyncResult) => {
$("#xml-blob").text(asyncResult.value);
}
);
}
);
}
Binding-based data access enables content and task pane add-ins to consistently access
a particular region of a document or spreadsheet through an identifier. The add-in first
needs to establish the binding by calling one of the methods that associates a portion of
the document with a unique identifier: addFromPromptAsync, addFromSelectionAsync,
or addFromNamedItemAsync. After the binding is established, the add-in can use the
provided identifier to access the data contained in the associated region of the
document or spreadsheet. Creating bindings provides the following value to your add-
in.
Establishing a binding also allows you to subscribe to data and selection change events
that are scoped to that particular region of the document or spreadsheet. This means
that the add-in is only notified of changes that happen within the bound region as
opposed to general changes across the whole document or spreadsheet.
The Bindings object exposes a getAllAsync method that gives access to the set of all
bindings established on the document or spreadsheet. An individual binding can be
accessed by its ID using either the Bindings.getByIdAsync method or Office.select
function. You can establish new bindings as well as remove existing ones by using one
of the following methods of the Bindings object: addFromSelectionAsync,
addFromPromptAsync, addFromNamedItemAsync, or releaseByIdAsync.
Binding types
There are three different types of bindings that you specify with the bindingType
parameter when you create a binding with the addFromSelectionAsync,
addFromPromptAsync or addFromNamedItemAsync methods.
1. Text Binding - Binds to a region of the document that can be represented as text.
In Word, most contiguous selections are valid, while in Excel only single cell
selections can be the target of a text binding. In Excel, only plain text is supported.
In Word, three formats are supported: plain text, HTML, and Open XML for Office.
2. Matrix Binding - Binds to a fixed region of a document that contains tabular data
without headers.Data in a matrix binding is written or read as a two dimensional
Array, which in JavaScript is implemented as an array of arrays. For example, two
rows of string values in two columns can be written or read as [['a', 'b'], ['c',
'd']] , and a single column of three rows can be written or read as [['a'], ['b'],
['c']] .
Any Excel or Word table can be the basis for a table binding. After you establish a
table binding, each new row or column a user adds to the table is automatically
included in the binding.
After a binding is created by using one of the three "addFrom" methods of the Bindings
object, you can work with the binding's data and properties by using the methods of the
corresponding object: MatrixBinding, TableBinding, or TextBinding. All three of these
objects inherit the getDataAsync and setDataAsync methods of the Binding object that
enable you to interact with the bound data.
7 Note
When should you use matrix versus table bindings? When the tabular data you
are working with contains a total row, you must use a matrix binding if your add-
in's script needs to access values in the total row or detect that the user's selection
is in the total row. If you establish a table binding for tabular data that contains a
total row, the TableBinding.rowCount property and the rowCount and startRow
properties of the BindingSelectionChangedEventArgs object in event handlers
won't reflect the total row in their values. To work around this limitation, you must
use establish a matrix binding to work with the total row.
JavaScript
Office.context.document.bindings.addFromSelectionAsync(Office.BindingType.Te
xt, { id: 'myBinding' }, function (asyncResult) {
if (asyncResult.status == Office.AsyncResultStatus.Failed) {
write('Action failed. Error: ' + asyncResult.error.message);
} else {
write('Added new binding with type: ' + asyncResult.value.type + '
and id: ' + asyncResult.value.id);
}
});
In this example, the specified binding type is text. This means that a TextBinding will be
created for the selection. Different binding types expose different data and operations.
Office.BindingType is an enumeration of available binding type values.
The second optional parameter is an object that specifies the ID of the new binding
being created. If an ID is not specified, one is generated automatically.
The anonymous function that is passed into the method as the final callback parameter
is executed when the creation of the binding is complete. The function is called with a
single parameter, asyncResult , which provides access to an AsyncResult object that
provides the status of the call. The AsyncResult.value property contains a reference to a
Binding object of the type that is specified for the newly created binding. You can use
this Binding object to get and set data.
JavaScript
function bindFromPrompt() {
Office.context.document.bindings.addFromPromptAsync(Office.BindingType.Text,
{ id: 'myBinding' }, function (asyncResult) {
if (asyncResult.status == Office.AsyncResultStatus.Failed) {
write('Action failed. Error: ' + asyncResult.error.message);
} else {
write('Added new binding with type: ' + asyncResult.value.type +
' and id: ' + asyncResult.value.id);
}
});
}
In this example, the specified binding type is text. This means that a TextBinding will be
created for the selection that the user specifies in the prompt.
The second parameter is an object that contains the ID of the new binding being
created. If an ID is not specified, one is generated automatically.
The anonymous function passed into the method as the third callback parameter is
executed when the creation of the binding is complete. When the callback function
executes, the AsyncResult object contains the status of the call and the newly created
binding.
JavaScript
function bindNamedItem() {
Office.context.document.bindings.addFromNamedItemAsync("myRange",
"matrix", {id:'myMatrix'}, function (result) {
if (result.status == 'succeeded'){
write('Added new binding with type: ' + result.value.type + '
and id: ' + result.value.id);
}
else
write('Error: ' + result.error.message);
});
}
For Excel, the itemName parameter of the addFromNamedItemAsync method can refer
to an existing named range, a range specified with the A1 reference style ("A1:A3") , or
a table. By default, adding a table in Excel assigns the name "Table1" for the first table
you add, "Table2" for the second table you add, and so on. To assign a meaningful name
for a table in the Excel UI, use the Table Name property on the Table Tools | Design tab
of the ribbon.
7 Note
In Excel, when specifying a table as a named item, you must fully qualify the name
to include the worksheet name in the name of the table in this format:
"Sheet1!Table1"
The following example creates a binding in Excel to the first three cells in column A (
"A1:A3" ), assigns the id "MyCities" , and then writes three city names to that binding.
JavaScript
function bindingFromA1Range() {
Office.context.document.bindings.addFromNamedItemAsync("A1:A3",
"matrix", {id: "MyCities" },
function (asyncResult) {
if (asyncResult.status == "failed") {
write('Error: ' + asyncResult.error.message);
}
else {
// Write data to the new binding.
Office.select("bindings#MyCities").setDataAsync([['Berlin'],
['Munich'], ['Duisburg']], { coercionType: "matrix" },
function (asyncResult) {
if (asyncResult.status == "failed") {
write('Error: ' + asyncResult.error.message);
}
});
}
});
}
// Function that writes to a div with id='message' on the page.
function write(message){
document.getElementById('message').innerText += message;
}
By default, a content control has no Title* value assigned. To assign a meaningful name
in the Word UI, after inserting a Rich Text content control from the Controls group on
the Developer tab of the ribbon, use the Properties command in the Controls group to
display the Content Control Properties dialog box. Then set the Title property of the
content control to the name you want to reference from your code.
The following example creates a text binding in Word to a rich text content control
named "FirstName" , assigns the id "firstName" , and then displays that information.
JavaScript
function bindContentControl() {
Office.context.document.bindings.addFromNamedItemAsync('FirstName',
Office.BindingType.Text, {id:'firstName'},
function (result) {
if (result.status === Office.AsyncResultStatus.Succeeded) {
write('Control bound. Binding.id: '
+ result.value.id + ' Binding.type: ' +
result.value.type);
} else {
write('Error:', result.error.message);
}
});
}
// Function that writes to a div with id='message' on the page.
function write(message){
document.getElementById('message').innerText += message;
}
Office.context.document.bindings.getAllAsync(function (asyncResult) {
let bindingString = '';
for (let i in asyncResult.value) {
bindingString += asyncResult.value[i].id + '\n';
}
write('Existing bindings: ' + bindingString);
});
The anonymous function that is passed into the method as the callback parameter is
executed when the operation is complete. The function is called with a single parameter,
asyncResult , which contains an array of the bindings in the document. The array is
iterated to build a string that contains the IDs of the bindings. The string is then
displayed in a message box.
JavaScript
Office.context.document.bindings.getByIdAsync('myBinding', function
(asyncResult) {
if (asyncResult.status == Office.AsyncResultStatus.Failed) {
write('Action failed. Error: ' + asyncResult.error.message);
}
else {
write('Retrieved binding with type: ' + asyncResult.value.type + '
and id: ' + asyncResult.value.id);
}
});
The anonymous function that is passed into the method as the second callback
parameter is executed when the operation is completed. The function is called with a
single parameter, asyncResult, which contains the status of the call and the binding with
the ID "myBinding".
JavaScript
7 Note
If the select function promise successfully returns a Binding object, that object
exposes only the following four methods of the object: getDataAsync,
setDataAsync, addHandlerAsync, and removeHandlerAsync. If the promise cannot
return a Binding object, the onError callback can be used to access an
asyncResult.error object to get more information. If you need to call a member of
the Binding object other than the four methods exposed by the Binding object
promise returned by the select function, instead use the getByIdAsync method by
using the Document.bindings property and Bindings.getByIdAsync method to
retrieve the Binding object.
Release a binding by ID
The following example shows how use the releaseByIdAsync method to release a
binding in a document by specifying its ID.
JavaScript
Office.context.document.bindings.releaseByIdAsync('myBinding', function
(asyncResult) {
write('Released myBinding!');
});
The anonymous function that is passed into the method as the second parameter is a
callback that is executed when the operation is complete. The function is called with a
single parameter, asyncResult, which contains the status of the call.
JavaScript
myBinding.getDataAsync(function (asyncResult) {
if (asyncResult.status == Office.AsyncResultStatus.Failed) {
write('Action failed. Error: ' + asyncResult.error.message);
} else {
write(asyncResult.value);
}
});
Alternatively, you could use the Office.select to access the binding by its ID, and start
your call to the getDataAsync method, like this:
JavaScript
Office.select("bindings#myBindingID").getDataAsync
The anonymous function that is passed into the method is a callback that is executed
when the operation is complete. The AsyncResult.value property contains the data
within myBinding . The type of the value depends on the binding type. The binding in
this example is a text binding. Therefore, the value will contain a string. For additional
examples of working with matrix and table bindings, see the getDataAsync method
topic.
JavaScript
In the example, the first parameter is the value to set on myBinding . Because this is a
text binding, the value is a string . Different binding types accept different types of
data.
The anonymous function that is passed into the method is a callback that is executed
when the operation is complete. The function is called with a single parameter,
asyncResult , which contains the status of the result.
JavaScript
function addHandler() {
Office.select("bindings#MyBinding").addHandlerAsync(
Office.EventType.BindingDataChanged, dataChanged);
}
function dataChanged(eventArgs) {
write('Bound data changed in binding: ' + eventArgs.binding.id);
}
// Function that writes to a div with id='message' on the page.
function write(message){
document.getElementById('message').innerText += message;
}
The myBinding is a variable that contains an existing text binding in the document.
The first eventType parameter of the addHandlerAsync method specifies the name of the
event to subscribe to. Office.EventType is an enumeration of available event type values.
Office.EventType.BindingDataChanged evaluates to the string "bindingDataChanged".
The dataChanged function that is passed into the method as the second handler
parameter is an event handler that is executed when the data in the binding is changed.
The function is called with a single parameter, eventArgs, which contains a reference to
the binding. This binding can be used to retrieve the updated data.
Similarly, you can detect when a user changes selection in a binding by attaching an
event handler to the SelectionChanged event of a binding. To do that, specify the
eventType parameter of the addHandlerAsync method as
Office.EventType.BindingSelectionChanged or "bindingSelectionChanged" .
You can add multiple event handlers for a given event by calling the addHandlerAsync
method again and passing in an additional event handler function for the handler
parameter. This will work correctly as long as the name of each event handler function is
unique.
JavaScript
function removeEventHandlerFromBinding() {
Office.select("bindings#MyBinding").removeHandlerAsync(
Office.EventType.BindingDataChanged, {handler:dataChanged});
}
) Important
See also
Understanding the Office JavaScript API
Asynchronous programming in Office Add-ins
Read and write data to the active selection in a document or spreadsheet
Referencing the Office JavaScript API
library
Article • 05/04/2023
The Office JavaScript API library provides the APIs that your add-in can use to interact
with the Office application. The simplest way to reference the library is to use the
content delivery network (CDN) by adding the following <script> tag within the <head>
section of your HTML page.
HTML
<head>
...
<script src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js"
type="text/javascript"></script>
</head>
This will download and cache the Office JavaScript API files the first time your add-in
loads to make sure that it is using the most up-to-date implementation of Office.js and
its associated files for the specified version.
) Important
You must reference the Office JavaScript API from inside the <head> section of the
page to ensure that the API is fully initialized prior to any body elements.
If you plan to publish your Office Add-in from AppSource, you must use this CDN
reference. Local references are only appropriate for internal, development, and
debugging scenarios.
7 Note
To use preview APIs, reference the preview version of the Office JavaScript API
library on the CDN:
https://appsforoffice.microsoft.com/lib/beta/hosted/office.js .
command line
Preview APIs
New JavaScript APIs are first introduced in "preview" and later become part of a specific
numbered requirement set after sufficient testing occurs and user feedback is acquired.
7 Note
Preview APIs are subject to change and are not intended for use in a production
environment. We recommend that you try them out in test and development
environments only. Do not use preview APIs in a production environment or within
business-critical documents.
You must use the preview version of the Office JavaScript API library from the
Office.js content delivery network (CDN) . The type definition file for
TypeScript compilation and IntelliSense is found at the CDN and
DefinitelyTyped . You can install these types with npm install --save-dev
@types/office-js-preview .
You may need to join the Microsoft 365 Insider program for access to
more recent Office builds.
CDN references for other Microsoft 365
environments
21Vianet operates and manages an Office 365 service powered by licensed Microsoft
technologies to provide Office 365 services for China compliant with local laws and
regulations. Add-ins developed for use within this cloud environment should use
corresponding CDN. Use
https://appsforoffice.cdn.partner.office365.cn/appsforoffice/lib/1/hosted/office.j
s instead of the standard CDN reference. This ensures continued compliance and
See also
Understanding the Office JavaScript API
Office JavaScript API
Guidance for deploying Office Add-ins on government clouds
Microsoft software license terms for the Microsoft Office JavaScript (Office.js) API
library
Specify Office applications and API
requirements
Article • 03/21/2023
Your Office Add-in might depend on a specific Office application (also called an Office
host) or on specific members of the Office JavaScript API (office.js). For example, your
add-in might:
In these situations, you need to ensure that your add-in is never installed on Office
applications or Office versions in which it cannot run.
There are also scenarios in which you want to control which features of your add-in are
visible to users based on their Office application and Office version. Two examples are:
Your add-in has features that are useful in both Word and PowerPoint, such as text
manipulation, but it has some additional features that only make sense in
PowerPoint, such as slide management features. You need to hide the PowerPoint-
only features when the add-in is running in Word.
Your add-in has a feature that requires an Office JavaScript API method that is
supported in some versions of an Office application, such as Microsoft 365
subscription Excel, but is not supported in others, such as volume-licensed
perpetual Excel 2016. But your add-in has other features that require only Office
JavaScript API methods that are supported in volume-licensed perpetual Excel
2016. In this scenario, you need the add-in to be installable on that version of Excel
2016, but the feature that requires the unsupported method should be hidden
from those users.
This article helps you understand which options you should choose to ensure that your
add-in works as expected and reaches the broadest audience possible.
7 Note
For a high-level view of where Office Add-ins are currently supported, see the
Office client application and platform availability for Office Add-ins page.
Tip
Many of the tasks described in this article are done for you, in whole or in part,
when you create your add-in project with a tool, such as the Yeoman generator for
Office Add-ins or one of the Office Add-in templates in Visual Studio. In such
cases, please interpret the task as meaning that you should verify that it has been
done.
HTML
<script src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js"
type="text/javascript"></script>
To ensure that your add-in is installable in a subset of Office applications, use the Hosts
and Host elements in the manifest.
For example, the following <Hosts> and <Host> declaration specifies that the add-in
can install on any release of Excel, which includes Excel on the web, Windows, and iPad,
but cannot be installed on any other Office application.
XML
<Hosts>
<Host Name="Workbook" />
</Hosts>
The <Hosts> element can contain one or more <Host> elements. There should be a
separate <Host> element for each Office application on which the add-in should be
installable. The Name attribute is required and can be set to one of the following values.
Presentation PowerPoint on the web, Windows, Mac, iPad Task pane, Content
Workbook Excel on the web, Windows, Mac, iPad Task pane, Content
7 Note
Office applications are supported on different platforms and run on desktops, web
browsers, tablets, and mobile devices. You usually can't specify which platform can
be used to run your add-in. For example, if you specify Workbook , both Excel on the
web and on Windows can be used to run your add-in. However, if you specify
Mailbox , your add-in won't run on Outlook mobile clients unless you define the
mobile extension point.
7 Note
It isn't possible for an add-in manifest to apply to more than one type: Mail, Task
pane, or Content. This means that if you want your add-in to be installable on
Outlook and on one of the other Office applications, you must create two add-ins,
one with a Mail type manifest and the other with a Task pane or Content type
manifest.
) Important
We no longer recommend that you create and use Access web apps and databases
in SharePoint. As an alternative, we recommend that you use Microsoft
PowerApps to build no-code business solutions for web and mobile devices.
Specify which Office versions and platforms
can host your add-in
You can't explicitly specify the Office versions and builds or the platforms on which your
add-in should be installable, and you wouldn't want to because you would have to
revise your manifest whenever support for the add-in features that your add-in uses is
extended to a new version or platform. Instead, specify in the manifest the APIs that
your add-in needs. Office prevents the add-in from being installed on combinations of
Office version and platform that don't support the APIs and ensures that the add-in
won't appear in My Add-ins.
) Important
Only use the base manifest to specify the API members that your add-in must have
to be of any significant value at all. If your add-in uses an API for some features but
has other useful features that don't require the API, you should design the add-in
so that it's installable on platform and Office version combinations that don't
support the API but provides a diminished experience on those combinations. For
more information, see Design for alternate experiences.
Requirement sets
To simplify the process of specifying the APIs that your add-in needs, Office groups
most APIs together in requirement sets. The APIs in the Common API Object Model are
grouped by the development feature that they support. For example, all the APIs
connected to table bindings are in the requirement set called "TableBindings 1.1". The
APIs in the Application specific object models are grouped by when they were released
for use in production add-ins.
Requirement sets are versioned. For example, the APIs that support Dialog Boxes are in
the requirement set DialogApi 1.1. When additional APIs that enable messaging from a
task pane to a dialog were released, they were grouped into DialogApi 1.2, along with
all the APIs in DialogApi 1.1. Each version of a requirement set is a superset of all earlier
versions.
Requirement set support varies by Office application, the version of the Office
application, and the platform on which it is running. For example, DialogApi 1.2 is not
supported on volume-licensed perpetual versions of Office before Office 2021, but
DialogApi 1.1 is supported on all perpetual versions back to Office 2013. You want your
add-in to be installable on every combination of platform and Office version that
supports the APIs that it uses, so you should always specify in the manifest the minimum
version of each requirement set that your add-in requires. Details about how to do this
are later in this article.
Tip
For more information about requirement set versioning, see Office requirement
sets availability, and for the complete lists of requirement sets and information
about the APIs in each, start with Office Add-in requirement sets. The reference
topics for most Office.js APIs also specify the requirement set they belong to (if
any).
7 Note
Some requirement sets also have manifest elements associated with them. See
Specifying requirements in a VersionOverrides element for information about
when this fact is relevant to your add-in design.
Requirements element
Use the Requirements element and its child elements Sets and Methods to specify the
minimum requirement sets or API members that must be supported by the Office
application to install your add-in.
If the Office application or platform doesn't support the requirement sets or API
members specified in the <Requirements> element, the add-in won't run in that
application or platform, and won't display in My Add-ins.
7 Note
The <Requirements> element is optional for all add-ins, except for Outlook add-
ins. When the xsi:type attribute of the root OfficeApp element is MailApp , there
must be a <Requirements> element that specifies the minimum version of the
Mailbox requirement set that the add-in requires. For more information, see
Outlook JavaScript API requirement sets.
The following code example shows how to configure an add-in that is installable in all
Office applications that support the following:
Document.getSelectedDataAsync method.
XML
Extensibility features that are available immediately after the add-in is installed.
You can make use of this kind of feature by configuring a VersionOverrides
element in the manifest. An example of this kind of feature is Add-in Commands,
which are custom ribbon buttons and menus.
Extensibility features that are available only when the add-in is running and that
are implemented with Office.js JavaScript APIs; for example, Dialog Boxes.
Extensibility features that are available only at runtime but are implemented with a
combination of Office.js JavaScript and configuration in a <VersionOverrides>
element. Examples of these are Excel custom functions, single sign-on, and custom
contextual tabs.
If your add-in uses a specific extensibility feature for some of its functionality but has
other useful functionality that doesn't require the extensibility feature, you should
design the add-in so that it's installable on platform and Office version combinations
that don't support the extensibility feature. It can provide a valuable, albeit diminished,
experience on those combinations.
You implement this design differently depending on how the extensibility feature is
implemented:
For features implemented entirely with JavaScript, see Runtime checks for method
and requirement set support.
For features that require you to configure a <VersionOverrides> element, see
Specifying requirements in a VersionOverrides element.
JavaScript
if (Office.context.requirements.isSetSupported('WordApi', '1.2'))
{
// Code that uses API members from the WordApi 1.2 requirement set.
} else {
// Provide diminished experience here. E.g., run alternate code when the
user's Word is volume-licensed perpetual Word 2016 (which doesn't support
WordApi 1.2).
}
The first parameter is required. It's a string that represents the name of the
requirement set. For more information about available requirement sets, see Office
Add-in requirement sets.
The second parameter is optional. It's a string that specifies the minimum
requirement set version that the Office application must support in order for the
code within the if statement to run (e.g., "1.9"). If not used, version "1.1" is
assumed.
2 Warning
When calling the isSetSupported method, the value of the second parameter (if
specified) should be a string not a number. The JavaScript parser cannot
differentiate between numeric values such as 1.1 and 1.10, whereas it can for string
values such as "1.1" and "1.10".
The following table shows the requirement set names for the application specific API
models.
Excel ExcelApi
OneNote OneNoteApi
Outlook Mailbox
PowerPoint PowerPointApi
Word WordApi
The following is an example of using the method with one of the Common API model
requirement sets.
JavaScript
if (Office.context.requirements.isSetSupported('CustomXmlParts'))
{
// Run code that uses API members from the CustomXmlParts requirement
set.
}
else
{
// Run alternate code when the user's Office application doesn't support
the CustomXmlParts requirement set.
}
7 Note
The isSetSupported method and the requirement sets for these applications are
available in the latest Office.js file on the CDN. If you don't use Office.js from the
CDN, your add-in might generate exceptions if you are using an old version of the
library in which isSetSupported is undefined. For more information, see Use the
latest Office JavaScript API library.
When your add-in depends on a method that isn't part of a requirement set, use the
runtime check to determine whether the method is supported by the Office application,
as shown in the following code example. For a complete list of methods that don't
belong to a requirement set, see Office Add-in requirement sets.
7 Note
We recommend that you limit the use of this type of runtime check in your add-in's
code.
The following code example checks whether the Office application supports
document.setSelectedDataAsync .
JavaScript
if (Office.context.document.setSelectedDataAsync)
{
// Run code that uses `document.setSelectedDataAsync`.
}
Specifically, the child elements of the <VersionOverrides> that override elements in the
base manifest, such as a <Hosts> element, are ignored and the corresponding elements
of the base manifest are used instead. However, there can be child elements in a
<VersionOverrides> that actually implement additional features rather than override
settings in the base manifest. Two examples are the WebApplicationInfo and
EquivalentAddins . These parts of the <VersionOverrides> will not be ignored, assuming
For information about the descendent elements of the <Requirements> element, see
Requirements element earlier in this article.
XML
<!-- ALL MARKUP INSIDE THE HOSTS ELEMENT IS IGNORED WHEREVER WordApi
1.2 IS NOT SUPPORTED -->
<Host xsi:type="Workbook">
<!-- markup for custom add-in commands -->
</Host>
</Hosts>
</VersionOverrides>
2 Warning
Tip
See also
Office Add-ins manifest
Office Add-in requirement sets
Word-Add-in-Get-Set-EditOpen-XML
Load the DOM and runtime
environment
Article • 05/20/2023
Before running its own custom logic, an add-in must ensure that both the DOM and the
Office Add-ins runtime environment are loaded.
The following events occur when a content or task pane add-in starts.
1. The user opens a document that already contains an add-in or inserts an add-in in
the document.
2. The Office client application reads the add-in's XML manifest from AppSource, an
app catalog on SharePoint, or the shared folder catalog it originates from.
3. The Office client application opens the add-in's HTML page in a webview control.
The next two steps, steps 4 and 5, occur asynchronously and in parallel. For this
reason, your add-in's code must make sure that both the DOM and the add-in
runtime environment have finished loading before proceeding.
4. The webview control loads the DOM and HTML body, and calls the event handler
for the window.onload event.
5. The Office client application loads the runtime environment, which downloads and
caches the Office JavaScript API library files from the content distribution network
(CDN) server, and then calls the add-in's event handler for the initialize event of
the Office object, if a handler has been assigned to it. At this time it also checks to
see if any callbacks (or chained then() method) have been passed (or chained) to
the Office.onReady handler. For more information about the distinction between
Office.initialize and Office.onReady , see Initialize your add-in.
6. When the DOM and HTML body finish loading and the add-in finishes initializing,
the main function of the add-in can proceed.
1. When Outlook starts, Outlook reads the XML manifests for Outlook add-ins that
have been installed for the user's email account.
4. If the user clicks the button to start the Outlook add-in, Outlook opens the HTML
page in a webview control. The next two steps, steps 5 and 6, occur in parallel.
5. The webview control loads the DOM and HTML body, and calls the event handler
for the onload event.
6. Outlook loads the runtime environment, which downloads and caches the
JavaScript API for JavaScript library files from the content distribution network
(CDN) server, and then calls the event handler for the initialize event of the Office
object of the add-in, if a handler has been assigned to it. At this time it also checks
to see if any callbacks (or chained then() methods) have been passed (or chained)
to the Office.onReady handler. For more information about the distinction
between Office.initialize and Office.onReady , see Initialize your add-in.
7. When the DOM and HTML body finish loading and the add-in finishes initializing,
the main function of the add-in can proceed.
See also
Understanding the Office JavaScript API
Initialize your Office Add-in
Runtimes in Office Add-ins
Initialize your Office Add-in
Article • 07/21/2022
Check that the user's version of Office supports all the Office APIs that your code
calls.
Ensure the existence of certain artifacts, such as a worksheet with a specific name.
Prompt the user to select some cells in Excel, and then insert a chart initialized with
those selected values.
Establish bindings.
Use the Office Dialog API to prompt the user for default add-in settings values.
However, an Office Add-in cannot successfully call any Office JavaScript APIs until the
library has been loaded. This article describes the two ways your code can ensure that
the library has been loaded.
Tip
For information about the differences in these techniques, see Major differences
between Office.initialize and Office.onReady().
For more details about the sequence of events when an add-in is initialized, see Loading
the DOM and runtime environment.
JavaScript
Office.onReady(function(info) {
if (info.host === Office.HostType.Excel) {
// Do Excel-specific initialization (for example, make add-in task
pane's
// appearance compatible with Excel "green").
}
if (info.platform === Office.PlatformType.PC) {
// Make minor layout changes in the task pane.
}
console.log(`Office.js is now ready in ${info.host} on
${info.platform}`);
});
Alternatively, you can chain a then() method to the call of Office.onReady() , instead of
passing a callback. For example, the following code checks to see that the user's version
of Excel supports all the APIs that the add-in might call.
JavaScript
Office.onReady()
.then(function() {
if (!Office.context.requirements.isSetSupported('ExcelApi', '1.7'))
{
console.log("Sorry, this add-in only works with newer versions
of Excel.");
}
});
Here is the same example using the async and await keywords in TypeScript.
TypeScript
(async () => {
await Office.onReady();
if (!Office.context.requirements.isSetSupported('ExcelApi', '1.7')) {
console.log("Sorry, this add-in only works with newer versions of
Excel.");
}
})();
If you are using additional JavaScript frameworks that include their own initialization
handler or tests, these should usually be placed within the response to
Office.onReady() . For example, JQuery's $(document).ready() method would be
referenced as follows:
JavaScript
Office.onReady(function() {
// Office is ready
$(document).ready(function () {
// The document is ready
});
});
However, there are exceptions to this practice. For example, suppose you want to open
your add-in in a browser (instead of sideload it in an Office application) in order to
debug your UI with browser tools. In this scenario, once Office.js determines that it is
running outside of an Office host application, it will call the callback and resolve the
promise with null for both the host and platform.
Another exception would be if you want a progress indicator to appear in the task pane
while the add-in is loading. In this scenario, your code should call the jQuery ready and
use its callback to render the progress indicator. Then the Office.onReady callback can
replace the progress indicator with the final UI.
JavaScript
Office.initialize = function () {
if (!Office.context.requirements.isSetSupported('ExcelApi', '1.7')) {
console.log("Sorry, this add-in only works with newer versions of
Excel.");
}
};
If you are using additional JavaScript frameworks that include their own initialization
handler or tests, these should usually be placed within the Office.initialize event (the
exceptions described in the Initialize with Office.onReady() section earlier apply in this
case also). For example, JQuery's $(document).ready() method would be referenced
as follows:
JavaScript
Office.initialize = function () {
// Office is ready
$(document).ready(function () {
// The document is ready
});
};
For task pane and content add-ins, Office.initialize provides an additional reason
parameter. This parameter specifies how an add-in was added to the current document.
You can use this to provide different logic for when an add-in is first inserted versus
when it already existed within the document.
JavaScript
initialization logic; and your code could also have a button in the task pane, whose
script calls Office.onReady() with a different callback. If so, the second callback
runs when the button is clicked.
The Office.initialize event fires at the end of the internal process in which
Office.js initializes itself. And it fires immediately after the internal process ends. If
the code in which you assign a handler to the event executes too long after the
event fires, then your handler doesn't run. For example, if you are using the
WebPack task manager, it might configure the add-in's home page to load polyfill
files after it loads Office.js but before it loads your custom JavaScript. By the time
your script loads and assigns the handler, the initialize event has already
happened. But it is never "too late" to call Office.onReady() . If the initialize event
has already happened, the callback runs immediately.
7 Note
Even if you have no start-up logic, you should either call Office.onReady() or
assign an empty function to Office.initialize when your add-in JavaScript loads.
Some Office application and platform combinations won't load the task pane until
one of these happens. The following examples show these two approaches.
JavaScript
Office.onReady();
JavaScript
Debug initialization
For information about debugging the Office.initialize and Office.onReady()
functions, see Debug the initialize and onReady functions.
See also
Understanding the Office JavaScript API
Loading the DOM and runtime environment
Automatically open a task pane with a
document
Article • 05/05/2023
You can use add-in commands in your Office Add-in to extend the Office UI by adding
buttons to the Office app ribbon. When users click your command button, an action
occurs, such as opening a task pane.
Some scenarios require that a task pane open automatically when a document opens,
without explicit user interaction. You can use the autoopen task pane feature, introduced
in the AddInCommands 1.1 requirement set, to automatically open a task pane when
your scenario requires it.
7 Note
To configure a task pane to open immediately when the add-in is installed, but not
necessarily whenever the document is opened later, see Automatically open a task
pane when an add-in is installed.
With the autoopen feature, you can explicitly define or allow the user to define whether
a specific task pane add-in persists in a specific document.
Products Platforms
Products Platforms
Best practices
Apply the following best practices when you use the autoopen feature.
Use the autoopen feature when it will help make your add-in users more efficient,
such as:
When the document needs the add-in in order to function properly. For
example, a spreadsheet that includes stock values that are periodically refreshed
by an add-in. The add-in should open automatically when the spreadsheet is
opened to keep the values up to date.
When the user will most likely always use the add-in with a particular document.
For example, an add-in that helps users fill in or change data in a document by
pulling information from a backend system.
Allow users to turn on or turn off the autoopen feature. Include an option in your
UI for users to choose to no longer automatically open the add-in task pane.
Don't use the autoopen feature to artificially increase usage of your add-in. If it
doesn't make sense for your add-in to open automatically with certain documents,
this feature can annoy users.
7 Note
Don't use this feature to pin multiple task panes. You can only set one pane of your
add-in to open automatically with a document.
) Important
The pane that you designate to open automatically will only open if the add-in is
already installed on the user's device. If the user does not have the add-in installed
when they open a document, the autoopen feature will not work and the setting
will be ignored. If you also require the add-in to be distributed with the document
you need to set the visibility property to 1; this can only be done using OpenXML,
an example is provided later in this article.
XML
<Action xsi:type="ShowTaskpane">
<TaskpaneId>Office.AutoShowTaskpaneWithDocument</TaskpaneId>
<SourceLocation resid="Contoso.Taskpane.Url" />
</Action>
JavaScript
Office.context.document.settings.set("Office.AutoShowTaskpaneWithDocument",
true);
Office.context.document.settings.saveAsync();
Use this method if you need to tag the document as part of your add-in interaction (for
example, as soon as the user creates a binding, or chooses an option to indicate that
they want the pane to open automatically).
A webextension part
A taskpane part
XML
<we:webextension
xmlns:we="http://schemas.microsoft.com/office/webextensions/webextension/201
0/11" id="[ADD-IN ID PER MANIFEST]">
<we:reference id="[GUID or AppSource asset ID]" version="[your add-in
version]" store="[Pointer to store or catalog]" storeType="[Store or catalog
type]"/>
<we:alternateReferences/>
<we:properties>
<we:property name="Office.AutoShowTaskpaneWithDocument" value="true"/>
</we:properties>
<we:bindings/>
<we:snapshot
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships
"/>
</we:webextension>
The webextension part also includes a reference to the store or catalog with attributes
for id , storeType , store , and version . Of the storeType values, only four are relevant
to the autoopen feature. The values for the other three attributes depend on the value
for storeType , as shown in the following table.
OMEX The The locale of AppSource; for example, "en-us". The version
(AppSource) AppSource in the
asset ID of AppSource
the add-in catalog (see
(see Note). Note).
WOPICatalog The "wopicatalog". Use this value for add-ins that are The version
(partner AppSource published in App Source and are installed in in the add-in
WOPI hosts) asset ID of WOPI hosts. For more information, see manifest.
the add-in Integrating with Office Online.
(see Note).
FileSystem (a The GUID of The path of the network share; for example, The version
network the add-in in "\\MyComputer\MySharedFolder". in the add-in
share) the add-in manifest.
manifest.
EXCatalog The GUID of "EXCatalog". EXCatalog row is the row to use with The version
(deployment the add-in in add-ins that use Centralized Deployment in the in the add-in
via the the add-in Microsoft 365 admin center. manifest.
Exchange manifest.
server)
7 Note
For more information about the webextension markup, see [MS-OWEXML] 2.2.5.
WebExtensionReference.
XML
<wetp:taskpane dockstate="right" visibility="0" width="350" row="4"
xmlns:wetp="http://schemas.microsoft.com/office/webextensions/taskpanes/2010
/11">
<wetp:webextensionref
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships
" r:id="rId1" />
</wetp:taskpane>
Note that in this example, the visibility attribute is set to "0". This means that after
the webextension and taskpane parts are added, the first time the document is opened,
the user has to install the add-in from the Add-in button on the ribbon. Thereafter, the
add-in task pane opens automatically when the file is opened. Also, when you set
visibility to "0", you can use Office.js to enable users to turn on or turn off the
If visibility is set to "1", the task pane opens automatically the first time the
document is opened. The user is prompted to trust the add-in, and when trust is
granted, the add-in opens. Thereafter, the add-in task pane opens automatically when
the file is opened. However, when visibility is set to "1", you can't use Office.js to
enable users to turn on or turn off the autoopen feature.
Setting visibility to "1" is a good choice when the add-in and the template or content
of the document are so closely integrated that the user would not opt out of the
autoopen feature.
7 Note
If you want to distribute your add-in with the document, so that users are
prompted to install it, you must set the visibility property to 1. You can only do this
via Open XML.
An easy way to write the XML is to first run your add-in and tag the document on the
client side to write the value, and then save the document and inspect the XML that is
generated.Office will detect and provide the appropriate attribute values. You can also
use the Open XML SDK Productivity Tool to generate C# code to programmatically
add the markup based on the XML you generate.
XML
<we:webextension
xmlns:we="http://schemas.microsoft.com/office/webextensions/webextension/201
0/11" id="{52811C31-4593-43B8-A697-EB873422D156}">
<we:reference id="af8fa5ba-4010-4bcc-9e03-a91ddadf6dd3"
version="1.0.0.0" store="EXCatalog" storeType="EXCatalog"/>
<we:alternateReferences/>
<we:properties/>
<we:bindings/>
<we:snapshot
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships
"/>
</we:webextension>
You can test the previous example by using your Microsoft 365 subscription to try out
Centralized Deployment and verify that your add-in works as expected. If you don't
already have a Microsoft 365 subscription, you can get a free, 90-day renewable
Microsoft 365 subscription by joining the Microsoft 365 developer program .
See also
For a sample that shows you how to use the autoopen feature, see Auto-open a
task pane with a document .
Automatically open a task pane when an add-in is installed
Join the Microsoft 365 developer program.
Automatically open a task pane when an
add-in is installed
Article • 03/14/2023
You can configure your add-in's task pane to launch immediately after it's installed. This
feature increases usage.
By default, task pane add-ins that do not include any add-in commands open the task
pane immediately upon installation. However, when an add-in has one or more add-in
commands, then the user is notified of new add-in, but the add-in doesn't launch
automatically. This historic default behavior is changing so add-ins that do have add-in
commands will launch automatically in some situations. In addition, if the add-in has
more than one task pane page, it's possible for you to control whether the add-in
launches upon installation and, if so, which page opens in the task pane.
7 Note
This feature is currently available only in Office on the web. We're working to
bring this behavior to other platforms, but currently they still exhibit the
historic default behavior described previously.
This feature applies only to add-ins installed by an end-user, not to centrally
deployed add-ins.
This feature doesn't apply to Content add-ins or Mail (Outlook) add-ins.
This feature applies only to add-ins that have at least one add-in command of
the type "task pane command".
New behavior
The new behavior is as follows:
If the add-in has just one task pane command, then the add-in's ribbon tab is
selected and the task pane opens automatically upon installation. You don't need
to configure anything.
If the add-in has multiple task pane commands, and one is configured to be the
default (see Configure default task pane), then the add-in's ribbon tab is selected
and the default task pane opens automatically upon installation.
If the add-in has multiple task pane commands, but none is configured to be the
default, then the add-in's ribbon tab is selected automatically upon installation and
a callout appears near it notifying the user of the new add-in, but no task pane is
opened. This is the same as the historic default behavior.
7 Note
If for any reason, the add-in command that launches the task pane cannot be
manually selected by a user at start up, such as when it's configured to be disabled
at start up, then it won't be automatically opened regardless of configuration.
XML
<Action xsi:type="ShowTaskpane">
<TaskpaneId>Office.AutoShowTaskpaneWithDocument</TaskpaneId>
<SourceLocation resid="Contoso.Taskpane.Url" />
</Action>
Tip
If you want your add-in to automatically launch whenever the user reopens the
document, you need to take further configuration steps. For details and advice
about when to use this feature, see Automatically open a task pane with a
document.
See also
Automatically open a task pane with a document
Configure your Office Add-in to use a
shared runtime
Article • 05/20/2023
) Important
The shared runtime is only supported in some Office applications. For more
information, see Shared runtime requirement sets.
You can configure your Office Add-in to run all of its code in a single shared runtime.
This enables better coordination across your add-in and access to the DOM and CORS
from all parts of your add-in. It also enables additional features such as running code
when the document opens, or enabling or disabling ribbon buttons. To configure your
add-in to use a shared runtime, follow the instructions in this article.
Run the command yo office --projectType taskpane --name "my office add in" --host
<host> --js true , where <host> is one of the following values.
excel
powerpoint
word
) Important
The --name argument value must be in double quotation marks, even if it has no
spaces.
You can use different options for the --projecttype, --name, and --js command-line
options. For the full list of options, see Yeoman generator for Office Add-ins .
The generator will create the project and install supporting Node components. You can
also use the steps in this article to update a Visual Studio project to use the shared
runtime. However, you may need to update the XML schemas for the manifest. For more
information, see Troubleshoot development errors with Office Add-ins.
Configure the manifest
Follow these steps for a new or existing project to configure it to use a shared runtime.
These steps assume you have generated your project using the Yeoman generator for
Office Add-ins.
3. For an Excel or PowerPoint add-in, update the requirements section to include the
shared runtime. Be sure to remove the CustomFunctionsRuntime requirement if it is
present. The XML should appear as follows.
XML
<Hosts>
<Host Name="Workbook"/>
</Hosts>
<Requirements>
<Sets DefaultMinVersion="1.1">
<Set Name="SharedRuntime" MinVersion="1.1"/>
</Sets>
</Requirements>
<DefaultSettings>
4. Find the <VersionOverrides> section and add the following <Runtimes> section.
The lifetime needs to be long so that your add-in code can run even when the task
pane is closed. The resid value is Taskpane.Url, which references the
taskpane.html file location specified in the <bt:Urls> section near the bottom of
the manifest.xml file.
) Important
The shared runtime won't load if the resid uses different values in the
manifest. If you change the value to something other than Taskpane.Url, be
sure to also change the value in all locations shown in the following steps in
this article.
Also, the <Runtimes> section must be entered after the <Host> element in
the exact order shown in the following XML.
XML
<VersionOverrides ...>
<Hosts>
<Host ...>
<Runtimes>
<Runtime resid="Taskpane.Url" lifetime="long" />
</Runtimes>
...
</Host>
5. If you generated an Excel add-in with custom functions, find the <Page> element.
Then change the source location from Functions.Page.Url to Taskpane.Url.
XML
<AllFormFactors>
...
<Page>
<SourceLocation resid="Taskpane.Url"/>
</Page>
...
6. Find the <FunctionFile> tag and change the resid from Commands.Url to
Taskpane.Url. Note that if you don't have action commands, you won't have a
<FunctionFile> entry, and can skip this step.
XML
</GetStarted>
...
<FunctionFile resid="Taskpane.Url"/>
...
1. Start Visual Studio Code and open the add-in project you generated.
new HtmlWebpackPlugin({
filename: "functions.html",
template: "./src/functions/functions.html",
chunks: ["polyfill", "functions"]
})
JavaScript
new HtmlWebpackPlugin({
filename: "commands.html",
template: "./src/commands/commands.html",
chunks: ["polyfill", "commands"]
})
5. If your project used either the functions or commands chunks, add them to the
chunks list as shown next (the following code is for if your project used both
chunks).
JavaScript
new HtmlWebpackPlugin({
filename: "taskpane.html",
template: "./src/taskpane/taskpane.html",
chunks: ["polyfill", "taskpane", "commands", "functions"]
})
command line
7 Note
2. Replace the entire contents of the file with the following code. This will display a
count of how many times the task pane has been opened. Adding the
onVisibilityModeChanged event is only supported in a shared runtime.
JavaScript
let _count = 0;
Office.onReady(() => {
document.getElementById("sideload-msg").style.display = "none";
document.getElementById("app-body").style.display = "flex";
function updateCount() {
_count++;
document.getElementById("run").textContent = "Task pane opened " +
_count + " times.";
}
command line
npm start
Each time you open the task pane, the count of how many times it has been opened will
be incremented. The value of _count will not be lost because the shared runtime keeps
your code running even when the task pane is closed.
Runtime lifetime
When you add the <Runtime> element, you also specify a lifetime with a value of long
or short . Set this value to long to take advantage of features such as starting your add-
in when the document opens, continuing to run code after the task pane is closed, or
using CORS and DOM from custom functions.
7 Note
The default lifetime value is short , but we recommend using long in Excel,
PowerPoint, and Word add-ins. If you set your runtime to short in this example,
your add-in will start when one of your ribbon buttons is pressed, but it may shut
down after your ribbon handler is done running. Similarly, your add-in will start
when the task pane is opened, but it may shut down when the task pane is closed.
XML
<Runtimes>
<Runtime resid="Taskpane.Url" lifetime="long" />
</Runtimes>
7 Note
If your add-in includes the <Runtimes> element in the manifest (required for a
shared runtime) and the conditions for using WebView2 (Microsoft Edge
Chromium-based) are met, it uses that control. If the conditions are not met, then it
uses the Trident (Internet Explorer 11) webview control regardless of the Windows
or Microsoft 365 version. For more information, see Runtimes and Browsers and
webview controls used by Office Add-ins.
However, you can configure your Office Add-in to share code in the same runtime (also
referred to as a shared runtime). This enables better coordination across your add-in
and access to the task pane DOM and CORS from all parts of your add-in.
For Office on Windows, the shared runtime uses WebView2 (Microsoft Edge Chromium-
based) if the conditions for using it are met as explained in Browsers and webview
controls used by Office Add-ins. Otherwise, it uses Trident (Internet Explorer 11).
Additionally, any buttons that your add-in displays on the ribbon will run in the same
shared runtime. The following image shows how custom functions, the ribbon UI, and
the task pane code will all run in the same runtime.
Debug
When using a shared runtime, you can't use Visual Studio Code to debug custom
functions in Excel on Windows at this time. You'll need to use developer tools instead.
For more information, see Debug add-ins using developer tools for Internet Explorer or
Debug add-ins using developer tools in Microsoft Edge (Chromium-based).
See also
Call Excel APIs from a custom function
Add custom keyboard shortcuts to your Office Add-ins (preview)
Create custom contextual tabs in Office Add-ins (preview)
Enable and Disable Add-in Commands
Run code in your Office Add-in when the document opens
Show or hide the task pane of your Office Add-in
Tutorial: Share data and events between Excel custom functions and the task pane
Runtimes in Office Add-ins
Run code in your Office Add-in when
the document opens
Article • 07/11/2023
) Important
The shared runtime is only supported in some Office applications. For more
information, see Shared runtime requirement sets.
You can configure your Office Add-in to load and run code as soon as the document is
opened. This is useful if you need to register event handlers, pre-load data for the task
pane, synchronize UI, or perform other tasks before the add-in is visible.
7 Note
The configuration is implemented with a method that your code calls at runtime.
This means that the add-in won't run the first time a user opens the document. The
add-in must be opened manually for the first time on any document. After the
method runs, either in Office.initialize, Office.onReady, or because the user takes a
code path that runs it; then whenever the document is reopened, the add-in loads
immediately and any code in the Office.initialize or Office.onReady method
runs.
7 Note
This article requires that your Office Add-in is configured to use a shared runtime.
For more information, see Configure your Office Add-in to use a shared runtime.
JavaScript
Office.addin.setStartupBehavior(Office.StartupBehavior.load);
7 Note
The following Excel add-in code shows how to register an event handler for change
events from the active worksheet. If you configure your add-in to load on document
open, this code will register the event handler when the document is opened. You can
handle change events before the task pane is opened.
JavaScript
await context.sync();
console.log("A handler has been registered for the onChanged event.");
});
};
/**
* Handle the changed event from the worksheet.
*
* @param event The event information from Excel
*/
async function onChange(event) {
await Excel.run(async (context) => {
await context.sync();
console.log("Change type of event: " + event.changeType);
console.log("Address of event: " + event.address);
console.log("Source of event: " + event.source);
});
}
The following PowerPoint add-in code shows how to register an event handler for
selection change events from the PowerPoint document. If you configure your add-in to
load on document open, this code will register the event handler when the document is
opened. You can handle change events before the task pane is opened.
JavaScript
Office.context.document.addHandlerAsync(Office.EventType.DocumentSelectionCh
anged, onChange);
console.log("A handler has been registered for the onChanged event.");
}
});
/**
* Handle the changed event from the PowerPoint document.
*
* @param event The event information from PowerPoint
*/
async function onChange(event) {
console.log("Change type of event: " + event.type);
}
7 Note
JavaScript
Office.addin.setStartupBehavior(Office.StartupBehavior.none);
JavaScript
See also
Configure your Office Add-in to use a shared runtime
Share data and events between Excel custom functions and task pane tutorial
Work with Events using the Excel JavaScript API
Runtimes in Office Add-ins
Office Add-ins manifest
Article • 07/27/2023
Every Office add-in has a manifest. There are two types of manifests:
XML manifest: This is the only type of manifest that is currently supported for
production add-ins. As the name indicates, it is XML format. This type of manifest
can't be used for an app that combines an add-in with some other kind of Teams
App; that is, some other kind of extension of the Microsoft 365 platform.
unified manifest for Microsoft 365: This is a JSON-formatted manifest that has
been used for years as the manifest for Teams Apps. It is supported for add-ins
only as a preview currently, and only on Outlook for Windows. It shouldn't be used
with a production add-in. When it releases to general availability, add-ins that use
this manifest can be combined with other kinds of Teams Apps in a single app that
is installable as a unit whole.
Tip
For an overview that is specific to the XML manifest, see Office Add-ins XML
manifest.
For an overview that is specific to the unified manifest, see Office Add-ins
with the unified manifest for Microsoft 365 (preview).
If you have some familiarity with the XML manifest, the article Compare the
XML manifest with the unified manifest for Microsoft 365 explains the
unified manifest by comparing it with the XML manifest.
The manifest file of an Office Add-in describes how your add-in should be activated
when an end user installs and uses it with Office documents and applications.
Describe itself by providing an ID, version, description, display name, and default
locale.
Specify the images used for branding the add-in and iconography used for add-in
commands in the Office app ribbon.
Specify how the add-in integrates with Office, including any custom UI, such as
ribbon buttons the add-in creates.
Specify the requested default dimensions for content add-ins, and requested
height for Outlook add-ins.
Declare permissions that the Office Add-in requires, such as reading or writing to
the document.
7 Note
If you plan to publish your add-in to AppSource and make it available within the
Office experience, make sure that you conform to the Commercial marketplace
certification policies. For example, to pass validation, your add-in must work across
all platforms that support the methods that you define (for more information, see
section 1120.3 and the Office Add-in application and availability page).
Hosting requirements
All image URIs, such as those used for add-in commands, must support caching in
production. The server hosting the image shouldn't return a Cache-Control header
specifying no-cache , no-store , or similar options in the HTTP response. However, when
you're developing the add-in and making changes to image files, the caching can
prevent you from seeing your changes, so using Cache-Control headers is advisable in
development.
All URLs to code or content files in the add-in should be SSL-secured (HTTPS). While
not strictly required in all add-in scenarios, using an HTTPS endpoint for your add-in is
strongly recommended. Add-ins that are not SSL-secured (HTTPS) generate unsecure
content warnings and errors during use. If you plan to run your add-in in Office on the
web or publish your add-in to AppSource, it must be SSL-secured. If your add-in
accesses external data and services, it should be SSL-secured to protect data in transit.
Self-signed certificates can be used for development and testing, so long as the
certificate is trusted on the local machine.
Add-ins submitted to AppSource must also include a support URL in the manifest. For
more information, see Validation policies for apps and add-ins submitted to AppSource.
Specify domains you want to open in the add-
in window
When running in Office on the web, your task pane can be navigated to any URL.
However, in desktop platforms, if your add-in tries to go to a URL in a domain other
than the domain that hosts the start page (as specified in the manifest file), that URL
opens in a new browser window outside the add-in pane of the Office application.
To override this (desktop Office) behavior, specify each domain you want to open in the
add-in window in the manifest. If the add-in tries to go to a URL in a domain that is in
the list, then it opens in the task pane in both Office on the web and desktop. If it tries
to go to a URL that isn't in the list, then, in desktop Office, that URL opens in a new
browser window (outside the add-in pane).
7 Note
It applies only to the root pane of the add-in. If there is an iframe embedded
in the add-in page, the iframe can be directed to any URL regardless of
whether it is listed in the manifest, even in desktop Office.
When a dialog is opened with the displayDialogAsync API, the URL that is
passed to the method must be in the same domain as the add-in, but the
dialog can then be directed to any URL regardless of whether it is listed in the
manifest, even in desktop Office.
See also
Specify Office applications and API requirements
Localization for Office Add-ins
Office Add-ins XML manifest
Article • 06/06/2023
This article introduces the XML-formatted manifest for Office Add-ins. It assumes that
you're familiar with Office Add-ins manifest. In addition to the purposes described in
that article, the XML-formatted manifest also supports certain Outlook Add-in features
that aren't supported in the unified manifest for Microsoft 365. For example, an XML
manifest for Outlook add-ins, can define the rule or rules that specify the context in
which the add-in is activated.
Tip
For an overview of the unified manifest for Microsoft 365, see Office Add-ins with
the unified manifest for Microsoft 365 (preview).
Schema versions
Not all Office clients support the latest features, and some Office users will have an
older version of Office. Having schema versions lets developers build add-ins that are
backwards compatible, using the newest features where they are available but still
functioning on older versions.
This approach means that developers don't have to create multiple individual manifests,
but rather keep everything defined in one file.
Version Description
v1.0 Supports version 1.0 of the Office JavaScript API. For example, in Outlook
add-ins, this supports the read form.
v1.1 Supports version 1.1 of the Office JavaScript API and <VersionOverrides>.
For example, in Outlook add-ins, this adds support for the compose form.
Version Description
<VersionOverrides> Supports later versions of the Office JavaScript API. This supports add-in
1.0 commands.
Even if your add-in manifest uses the <VersionOverrides> element, it is still important
to include the v1.1 manifest elements to allow your add-in to work with older clients
that do not support <VersionOverrides>.
7 Note
Office uses a schema to validate manifests. The schema requires that elements in
the manifest appear in a specific order. If you include elements out of the required
order, you may get errors when sideloading your add-in. See How to find the
proper order of manifest elements elements in the required order.
Required elements
The following table specifies the elements that are required for the three types of Office
Add-ins.
7 Note
There is also a mandatory order in which elements must appear within their parent
element. For more information see How to find the proper order of XML manifest
elements.
** SupportUrl is only required for add-ins that are distributed through AppSource.
Root element
The root element for the Office add-in manifest is <OfficeApp>. This element also
declares the default namespace, schema version and the type of add-in. Place all other
elements in the manifest within its open and close tags. The following is an example of
the root element.
XML
<OfficeApp
xmlns="http://schemas.microsoft.com/office/appforoffice/1.1"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xmlns:bt="http://schemas.microsoft.com/office/officeappbasictypes/1.0"
xmlns:mailappor="http://schemas.microsoft.com/office/mailappversionoverrides
/1.0"
xsi:type="MailApp">
</OfficeApp>
Version
This is the version of the specific add-in. If a developer updates something in the
manifest, the version must be incremented as well. This way, when the new manifest is
installed, it will overwrite the existing one and the user will get the new functionality. If
this add-in was submitted to the store, the new manifest will have to be re-submitted
and re-validated. Then, users of this add-in will get the new updated manifest
automatically in a few hours, after it is approved.
If the add-in's requested permissions change, users will be prompted to upgrade and
re-consent to the add-in. If the admin installed this add-in for the entire organization,
the admin will have to re-consent first. Users will be unable to use the add-in until
consent is granted.
Hosts
Office add-ins specify the <Hosts> element like the following:
XML
<OfficeApp>
...
<Hosts>
<Host Name="Mailbox" />
</Hosts>
...
</OfficeApp>
This is separate from the <Hosts> element inside the <VersionOverrides> element,
which is discussed in Create add-in commands with the XML manifest.
To override this (desktop Office) behavior, add each domain you want to open in the
add-in window in the list of domains specified in the <AppDomains> element. If the
add-in tries to go to a URL in a domain that is in the list, then it opens in the task pane
in both Office on the web and desktop. If it tries to go to a URL that isn't in the list, then
in desktop Office that URL opens in a new browser window (outside the add-in pane).
The following table describes browser behavior when your add-in attempts to navigate
to a URL outside of the add-in's default domain.
The following XML manifest example hosts its main add-in page in the
https://www.contoso.com domain as specified in the <SourceLocation> element. It also
Some descendant elements of VersionOverrides have values that override values of the
parent OfficeApp element. For example, the Hosts element in VersionOverrides
overrides the Hosts element in OfficeApp .
The VersionOverrides element has its own schema, actually four of them, depending on
the type of add-in and the features it uses. The schemas are:
http://schemas.microsoft.com/office/taskpaneappversionoverrides
http://schemas.microsoft.com/office/contentappversionoverrides
http://schemas.microsoft.com/office/mailappversionoverrides
The VersionOverrides element itself must also have an xmlns attribute specifying the
schema. The possible values are the three above and the following:
http://schemas.microsoft.com/office/mailappversionoverrides/1.1
The VersionOverrides element also must have an xsi:type attribute that specifies the
schema version. The possible values are the following:
VersionOverridesV1_0
VersionOverridesV1_1
The following are examples of VersionOverrides used, respectively, in a task pane add-
in and a mail add-in. Note that when a mail VersionOverrides with version 1.1 is used, it
must be the last child of a parent VersionOverrides of type 1.0. The values of child
elements in the inner VersionOverrides override the values of the same-named
elements in the parent VersionOverrides and the grandparent OfficeApp element.
XML
<VersionOverrides
xmlns="http://schemas.microsoft.com/office/taskpaneappversionoverrides"
xsi:type="VersionOverridesV1_0">
<!-- child elements omitted -->
</VersionOverrides>
XML
<VersionOverrides
xmlns="http://schemas.microsoft.com/office/mailappversionoverrides"
xsi:type="VersionOverridesV1_0">
<!-- other child elements omitted -->
<VersionOverrides
xmlns="http://schemas.microsoft.com/office/mailappversionoverrides/1.1"
xsi:type="VersionOverridesV1_1">
<!-- child elements omitted -->
</VersionOverrides>
</VersionOverrides>
For an example of a manifest that includes a VersionOverrides element, see Manifest
v1.1 XML file examples and schemas.
Requirements
The <Requirements> element specifies the set of APIs available to the add-in. For
detailed information about requirement sets, see Office requirement sets availability. For
example, for an Outlook add-in, the requirement set must be Mailbox and a value of 1.1
or above.
The following example uses the DefaultMinVersion attribute of the <Sets> element to
require office.js version 1.1 or higher, and the MinVersion attribute of the <Set>
element to require the Mailbox requirement set version 1.1.
XML
<OfficeApp>
...
<Requirements>
<Sets DefaultMinVersion="1.1">
<Set Name="MailBox" MinVersion="1.1" />
</Sets>
</Requirements>
...
</OfficeApp>
Localization
Some aspects of the add-in need to be localized for different locales, such as the name,
description and the URL that's loaded. These elements can easily be localized by
specifying the default value and then locale overrides in the <Resources> element
within the <VersionOverrides> element. The following shows how to override an image,
a URL, and a string.
XML
<Resources>
<bt:Images>
<bt:Image id="icon1_16x16"
DefaultValue="https://contoso.com/images/app_icon_small.png" >
<bt:Override Locale="ar-sa"
Value="https://contoso.com/images/app_icon_small_arsa.png" />
<!-- add information for other locales -->
</bt:Image>
</bt:Images>
<bt:Urls>
<bt:Url id="residDesktopFuncUrl"
DefaultValue="https://contoso.com/urls/page_appcmdcode.html" >
<bt:Override Locale="ar-sa"
Value="https://contoso.com/urls/page_appcmdcode.html?lcid=ar-sa" />
<!-- add information for other locales -->
</bt:Url>
</bt:Urls>
<bt:ShortStrings>
<bt:String id="residViewTemplates" DefaultValue="Launch My Add-in">
<bt:Override Locale="ar-sa" Value="<add localized value here>" />
<!-- add information for other locales -->
</bt:String>
</bt:ShortStrings>
</Resources>
The schema reference contains full information on which elements can be localized.
Task pane
XML
<Permissions>ReadWriteDocument</Permissions>
<!--BeginAddinCommandsMode integration-->
<VersionOverrides
xmlns="http://schemas.microsoft.com/office/taskpaneappversionoverrides"
xsi:type="VersionOverridesV1_0">
<Hosts>
<!--Each host can have a different set of commands. Cool huh!? -->
<!-- Workbook=Excel Document=Word Presentation=PowerPoint -->
<!-- Make sure the hosts you override match the hosts declared in
the top section of the manifest -->
<Host xsi:type="Document">
<!-- Form factor. Currently only DesktopFormFactor is supported.
We will add TabletFormFactor and PhoneFormFactor in the future-->
<DesktopFormFactor>
<!--Function file is an html page that includes the javascript
where functions for ExecuteAction will be called.
Think of the FunctionFile as the "code behind"
ExecuteFunction-->
<FunctionFile resid="Contoso.FunctionFile.Url" />
<Item id="Contoso.Menu.Item2">
<Label resid="Contoso.Item2.Label"/>
<Supertip>
<Title resid="Contoso.Item2.Label" />
<Description resid="Contoso.Item2.Tooltip" />
</Supertip>
<Icon>
<bt:Image size="16"
resid="Contoso.TaskpaneButton.Icon16" />
<bt:Image size="32"
resid="Contoso.TaskpaneButton.Icon32" />
<bt:Image size="80"
resid="Contoso.TaskpaneButton.Icon80" />
</Icon>
<Action xsi:type="ShowTaskpane">
<TaskpaneId>MyTaskPaneID2</TaskpaneId>
<SourceLocation resid="Contoso.Taskpane2.Url" />
</Action>
</Item>
</Items>
</Control>
</Group>
See also
How to find the proper order of XML manifest elements
Create add-in commands with the XML manifest
Specify Office applications and API requirements
Localization for Office Add-ins
Schema reference for XML Office Add-ins manifests
Update API and manifest version
Identify an equivalent COM add-in
Requesting permissions for API use in add-ins
Validate an Office Add-in's manifest
Office Add-ins with the unified manifest
for Microsoft 365 (preview)
Article • 05/25/2023
This article introduces the unified manifest for Microsoft 365 in preview. It assumes that
you're familiar with Office Add-ins manifest.
Tip
For an overview of the XML manifest, see Office Add-ins XML manifest.
If you're familiar with the XML manifest, you might get a grasp on the JSON-
formatted unified manifest easier by reading Compare the XML manifest with
the unified manifest for Microsoft 365.
One important improvement we're working on is the ability to create a single unit of
distribution for all your Microsoft 365 extensions (Teams Apps) by using the same
manifest format and schema, based on the JSON-formatted unified manifest for
Microsoft 365.
7 Note
Any extension of any part of the Microsoft 365 platform is now called a "Teams
App" even if it doesn't extend the Teams application itself.
We've taken an important first step toward these goals by making it possible for you to
create Outlook add-ins, running on Windows only, with a unified manifest for Microsoft
365.
7 Note
The unified manifest is available for preview and is subject to change based
on feedback. We encourage experienced add-in developers to experiment
with it. The unified manifest shouldn't be used in production add-ins.
The preview version of the unified manifest only supports Outlook add-ins
and only in Office downloaded from a Microsoft 365 subscription and
installed on Windows. We're working on extending support to Excel,
PowerPoint, and Word, as well as other platforms.
The unified manifest requires Office Version 2304 (Build 16320.00000) or later.
Your Microsoft 365 subscription channel must be "Beta".
Tip
Ready to get started with the preview unified manifest? Begin with Build an
Outlook add-in with the unified manifest for Microsoft 365 (preview).
Base properties
Each of the base properties listed in the following table has more extensive
documentation at Public developer preview manifest schema for Teams. Base properties
not included in this table have no meaning for Office Add-ins.
"name" Public short and long names of the Teams app/add-in. The short name
appears at the top of an add-in's task pane.
JSON property Purpose
"webApplicationInfo" Identifies the Teams app/add-in's web app as it is known in Azure Active
Directory.
"authorization" Identifies any Microsoft Graph permissions that the add-in needs.
"extensions" property
We're working hard to complete reference documentation for the "extensions" property
and its descendent properties. In the meantime, the following provides some basic
documentation. Most, but not all, of the properties have an equivalent element (or
attribute) in the XML manifest for add-ins. For the most part, the description, and
restrictions, that apply to the XML element or attribute also apply to its JSON property
equivalent in the unified manifest. The tables in the '"extensions" property' section of
Compare the XML manifest with the unified manifest for Microsoft 365 can help you
determine the XML equivalent of a JSON property.
"requirements.scopes" Identifies the Office applications in which the add-in can be installed.
For example, "mail" means the add-in can be installed in Outlook.
"ribbons.contexts" Specifies the command surfaces that the add-in customizes. For
example, "mailRead" or "mailCompose".
"runtimes" Configures the embedded runtimes that the add-in uses, including
various kinds of add-ins that have little or no UI, such as custom
function-only add-ins and function commands.
JSON property Purpose
To override this behavior in desktop platforms, add each domain you want to open in
the add-in window to the list of domains specified in the "validDomains" array. If the
add-in tries to go to a URL in a domain that is in the list, then it opens in the task pane
in both Office on the web and desktop. If it tries to go to a URL that isn't in the list, then
in Office on desktop, that URL opens in a new browser window (outside the add-in task
pane).
JSON
{
"$schema": "https://raw.githubusercontent.com/OfficeDev/microsoft-teams-
app-schema/op/extensions/MicrosoftTeams.schema.json",
"id": "00000000-0000-0000-0000-000000000000",
"version": "1.0.0",
"manifestVersion": "devPreview",
"name": {
"short": "Name of your app (<=30 chars)",
"full": "Full name of app, if longer than 30 characters (<=100 chars)"
},
"description": {
"short": "Short description of your app (<= 80 chars)",
"full": "Full description of your app (<= 4000 chars)"
},
"icons": {
"outline": "outline.png",
"color": "color.png"
},
"accentColor": "#230201",
"developer": {
"name": "Contoso",
"websiteUrl": "https://www.contoso.com",
"privacyUrl": "https://www.contoso.com/privacy",
"termsOfUseUrl": "https://www.contoso.com/servicesagreement"
},
"localizationInfo": {
"defaultLanguageTag": "en-us",
"additionalLanguages": [
{
"languageTag": "es-es",
"file": "es-es.json"
}
]
},
"webApplicationInfo": {
"id": "00000000-0000-0000-0000-000000000000",
"resource": "api://www.contoso.com/prodapp"
},
"authorization": {
"permissions": {
"resourceSpecific": [
{
"name": "Mailbox.ReadWrite.User",
"type": "Delegated"
}
]
}
},
"extensions": [
{
"requirements": {
"scopes": [ "mail" ],
"capabilities": [
{
"name": "Mailbox", "minVersion": "1.1"
}
]
},
"runtimes": [
{
"requirements": {
"capabilities": [
{
"name": "MailBox", "minVersion": "1.10"
}
]
},
"id": "eventsRuntime",
"type": "general",
"code": {
"page": "https://contoso.com/events.html",
"script": "https://contoso.com/events.js"
},
"lifetime": "short",
"actions": [
{
"id": "onMessageSending",
"type": "executeFunction"
},
{
"id": "onNewMessageComposeCreated",
"type": "executeFunction"
}
]
},
{
"requirements": {
"capabilities": [
{
"name": "MailBox", "minVersion": "1.1"
}
]
},
"id": "commandsRuntime",
"type": "general",
"code": {
"page": "https://contoso.com/commands.html",
"script": "https://contoso.com/commands.js"
},
"lifetime": "short",
"actions": [
{
"id": "action1",
"type": "executeFunction"
},
{
"id": "action2",
"type": "executeFunction"
},
{
"id": "action3",
"type": "executeFunction"
}
]
}
],
"ribbons": [
{
"contexts": [
"mailCompose"
],
"tabs": [
{
"builtInTabId": "TabDefault",
"groups": [
{
"id": "dashboard",
"label": "Controls",
"controls": [
{
"id": "control1",
"type": "button",
"label": "Action 1",
"icons": [
{
"size": 16,
"file": "test_16.png"
},
{
"size": 32,
"file": "test_32.png"
},
{
"size": 80,
"file": "test_80.png"
}
],
"supertip": {
"title": "Action 1 Title",
"description": "Action 1 Description"
},
"actionId": "action1"
},
{
"id": "menu1",
"type": "menu",
"label": "My Menu",
"icons": [
{
"size": 16,
"file": "test_16.png"
},
{
"size": 32,
"file": "test_32.png"
},
{
"size": 80,
"file": "test_80.png"
}
],
"supertip": {
"title": "My Menu",
"description": "Menu with 2 actions"
},
"items": [
{
"id": "menuItem1",
"type": "menuItem",
"label": "Action 2",
"supertip": {
"title": "Action 2 Title",
"description": "Action 2 Description"
},
"actionId": "action2"
},
{
"id": "menuItem2",
"type": "menuItem",
"label": "Action 3",
"icons": [
{
"size": 16,
"file": "test_16.png"
},
{
"size": 32,
"file": "test_32.png"
},
{
"size": 80,
"file": "test_80.png"
}
],
"supertip": {
"title": "Action 3 Title",
"description": "Action 3 Description"
},
"actionId": "action3"
}
]
}
]
}
]
}
]
},
{
"contexts": [ "mailRead" ],
"tabs": [
{
"builtInTabId": "TabDefault",
"groups": [
{
"id": "dashboard",
"label": "Controls",
"controls": [
{
"id": "control1",
"type": "button",
"label": "Action 1",
"icons": [
{
"size": 16,
"file": "test_16.png"
},
{
"size": 32,
"file": "test_32.png"
},
{
"size": 80,
"file": "test_80.png"
}
],
"supertip": {
"title": "Action 1 Title",
"description": "Action 1 Description"
},
"actionId": "action1"
}
]
}
]
}
]
}
],
"autoRunEvents": [
{
"requirements": {
"capabilities": [
{
"name": "MailBox", "minVersion": "1.10"
}
]
},
"events": [
{
"type": "newMessageComposeCreated",
"actionId": "onNewMessageComposeCreated"
},
{
"type": "messageSending",
"actionId": "onMessageSending",
"options": {
"sendMode": "promptUser"
}
}
]
}
],
"alternates": [
{
"requirements": {
"scopes": [ "mail" ]
},
"prefer": {
"comAddin": {
"progId": "ContosoExtension"
}
},
"hide": {
"storeOfficeAddin": {
"officeAddinId": "00000000-0000-0000-0000-000000000000",
"assetId": "WA000000000"
}
}
}
]
}
]
}
See also
Create add-in commands with the unified manifest for Microsoft 365
Preview schema for the unified manifest
Compare the XML manifest with the
unified manifest for Microsoft 365
Article • 07/27/2023
This article is intended to help readers who are familiar with the XML manifest
understand the unified manifest by comparing the two. Readers should also see Office
Add-ins with the unified manifest for Microsoft 365 (preview).
7 Note
The unified manifest is a preview feature of Office Add-ins and is only supported
for Outlook on Windows.
JSON doesn't distinguish between attribute and element value like XML does.
Typically, the JSON that maps to an XML element makes both the element value
and each of the attributes a child property. The following example shows some
XML markup and its JSON equivalent.
XML
JSON
"myThing" : {
"color": "blue",
"text": "Some text"
}
There are many places in the current XML manifest where an element with a plural
name has children with the singular version of the same name. For example, the
markup to configure a custom menu includes an <Items> element which can have
multiple <Item> element children. The JSON equivalent of these plural elements is
a property with an array as its value. The members of the array are anonymous
objects, not properties named "item" or "item1", "item2", etc. The following is an
example.
JSON
"items": [
{
-- markup for a menu item is here --
},
{
-- markup for another menu item is here --
}
]
Top-level structure
The root level of the preview unified manifest, which roughly corresponds to the
<OfficeApp> element in the current XML manifest, is an anonymous object.
The children of <OfficeApp> are commonly divided into two notional categories. The
<VersionOverrides> element is one category. The other consists of all the other
children of <OfficeApp>, which are collectively referred to as the base manifest. So too,
the preview unified manifest has a similar division. There is a top-level "extensions"
property that roughly corresponds in its purposes and child properties to the
<VersionOverrides> element. The preview unified manifest also has over 10 other top-
level properties that collectively serve the same purposes as the base manifest of the
XML manifest. These other properties can be thought of collectively as the base
manifest of the unified manifest.
Base manifest
The base manifest properties specify characteristics of the add-in that any type of
extension of Microsoft 365 is expected to have. This includes Teams tabs and message
extensions, not just Office add-ins. These characteristics include a public name and a
unique ID. The following table shows a mapping of some critical top-level properties in
the preview unified manifest to the XML elements in the current manifest, where the
mapping principle is the purpose of the markup.
"extensions" property
The "extensions" property in the preview unified manifest primarily represents
characteristics of the add-in that wouldn't be relevant to other kinds of Microsoft 365
extensions. For example, the Office applications that the add-in extends (such as, Excel,
PowerPoint, Word, and Outlook) are specified inside the "extensions" property, as are
customizations of the Office application ribbon. The configuration purposes of the
"extensions" property closely match those of the <VersionOverrides> element in the
current XML manifest.
7 Note
The <VersionOverrides> section of the current XML manifest has a "double jump"
system for many string resources. Strings, including URLs, are specified and
assigned an ID in the <Resources> child of <VersionOverrides>. Elements that
require a string have a resid attribute that matches the ID of a string in the
<Resources> element. The "extensions" property of the preview unified manifest
simplifies things by defining strings directly as property values. There is nothing in
the unified manifest that is equivalent to the <Resources> element.
The following table shows a mapping of some high level child properties of the
"extensions" property in the preview unified manifest to XML elements in the current
manifest. Dot notation is used to reference child properties.
"ribbons" table
The following table maps the child properties of the anonymous child objects in the
"ribbons" array onto XML elements in the current manifest.
For a full sample unified manifest, see Sample preview unified manifest.
Next steps
Build an Outlook add-in with the unified manifest for Microsoft 365 (preview).
Convert an add-in to use the unified
manifest for Microsoft 365 (preview)
Article • 07/27/2023
To add Teams capabilities to an add-in that uses the XML manifest, or to just future
proof the add-in, you need to convert it to use the unified manifest for Microsoft 365.
There are three basic tasks to converting an add-in project from the XML manifest to the
unified manifest.
Ensure that you have 64x64 pixel and 128x128 pixel images files to serve as icons
for the add-in.
Convert the XML manifest itself to the JSON format of the unified manifest.
Package the new manifest and main icon and high resolution icon image files into
a zip file for sideloading or deployment.
7 Note
The unified manifest is a preview feature for Office Add-ins and is currently
supported only for Outlook on Windows.
Add-ins that use the unified manifest can be sideloaded only on Office
version 16.0.16501.10000 or later.
Projects created in Visual Studio, as distinct from Visual Studio Code, can't be
converted at this time.
If you created the project with Teams Toolkit or with the "unified manifest"
option in the Office Yeoman Generator, it already uses the unified manifest.
When you've added the files to the project, add <IconUrl> and
<HighResolutionIconUrl> (in that order) to the XML manifest just below the
<Description> element. The following is an example.
XML
<OfficeApp xmlns="http://schemas.microsoft.com/office/appforoffice/1.1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="MailApp">
<Id>01234567-89ab-cdef-0123-4567-89abcdef0123</Id>
<Version>1.0</Version>
<ProviderName>Contoso</ProviderName>
<DefaultLocale>en-us</DefaultLocale>
<DisplayName DefaultValue="Great Add-in"/>
<Description DefaultValue="A great add-in."/>
<IconUrl DefaultValue="https://localhost:3000/assets/icon-64.png" />
<HighResolutionIconUrl DefaultValue="https://localhost:300/assets/icon-
128.png" />
Prerequisites
1. Open Visual Studio Code and select the Teams Toolkit icon on the Activity Bar.
4. In the App Features Using an Outlook Add-in drop down, select Import an
Existing Outlook Add-in.
5. In the Existing add-in project folder drop down, browse to the root folder of the
add-in project.
6. In the Select import project manifest file drop down, browse to the XML manifest
file.
7. In the Workspace folder dialog, select the folder where you want to put the
converted project.
8. In the Application name dialog, give a name to the project (with no spaces). Teams
Toolkit creates the project with your source files and scaffolding. It then opens the
project in a second Visual Studio Code window. Close the original Visual Studio
Code window.
You can sideload the add-in using the Teams Toolkit or in a command prompt, bash
shell, or terminal.
Sideload with the Teams Toolkit
1. In the root of the project, open a command prompt or bash shell and run the
following command. This converts the manifest and updates the package.json to
specify current tooling packages. The new unified manifest is in the root of the
project and the old XML manifest is in a backup.zip file. For details about this
command, see Office-Addin-Project .
command line
In the root of the project, open a command prompt or bash shell and run the following
command. This command puts the unified manifest in a subfolder with the same name
as the filename stem of the original XML manifest. For example, if the manifest is named
MyManifest.xml, the unified manifest is created at .\MyManifest\MyManifest.json. For
more details about this command, see Office-Addin-Manifest-Converter .
command line
Once you have the unified manifest created, there are two ways to create the zip file and
sideload it. They are described in the next two subsections.
1. To sideload the add-in, run the following command. This command puts the
unified manifest and two default icon image files into a zip file and sideloads it to
the Office application. It also starts a server in a separate NodeJS window to host
the add-in files on localhost. Note that you pass the path to the unified manifest
that you created in the previous step. For more details about this command, see
Office-Addin-Debugging .
command line
2. When you use office-addin-debugging to start an add-in, always stop the session
with the following command. Closing the server window doesn't reliably stop the
server and closing the Office application doesn't reliably cause Office to unacquire
the add-in.
command line
2. In the root of the project, open a command prompt or bash shell and run the
following commands.
command line
This section contains information about every element used by an Office Add-in's XML
manifest. To learn more about how the manifest describes your add-in to an Office
application, visit Office Add-ins XML manifest.
Elements
Name Category
Action VersionOverrides
AllFormFactors VersionOverrides
AllowSnapshot General
AlternateId General
AppDomain General
AppDomains General
CitationText General
Control VersionOverrides
CustomTab VersionOverrides
DefaultLocale General
DefaultSettings General
Description General
DesktopFormFactor VersionOverrides
DesktopSettings General
Dictionary General
DictionaryHomePage General
Name Category
DisableEntityHighlighting General
DisplayName General
Enabled VersionOverrides
EquivalentAddin General
EquivalentAddins General
Event VersionOverrides
ExtendedPermission VersionOverrides
ExtendedPermissions VersionOverrides
ExtensionPoint VersionOverrides
ExtendedOverrides General
FileName General
Form General
FormSettings General
FunctionFile VersionOverrides
GetStarted VersionOverrides
Group VersionOverrides
HighResolutionIconUrl General
Host General
Hosts General
Icon VersionOverrides
IconUrl General
Id General
Image VersionOverrides
Images VersionOverrides
Item VersionOverrides
Items VersionOverrides
Name Category
LaunchEvent VersionOverrides
LaunchEvents VersionOverrides
LongStrings VersionOverrides
Metadata General
Method General
Methods General
MobileFormFactor VersionOverrides
Namespace General
OfficeApp General
OfficeMenu VersionOverrides
OfficeTab VersionOverrides
OverriddenByRibbonApi VersionOverrides
Override General
Page VersionOverrides
Permissions General
PhoneSettings General
ProgId General
ProviderName General
QueryUri General
RequestedHeight General
RequestedWidth General
Requirements General
Resources VersionOverrides
Rule General
Runtime VersionOverrides
Runtimes VersionOverrides
Name Category
Scopes VersionOverrides
Script VersionOverrides
Set General
Sets General
ShortStrings VersionOverrides
SourceLocation General
String VersionOverrides
Supertip VersionOverrides
SupportsSharedFolders VersionOverrides
SupportUrl General
TabletSettings General
TargetDialect General
TargetDialects General
Tokens General
Token General
Type General
Url VersionOverrides
Urls VersionOverrides
Version General
VersionOverrides General
WebApplicationInfo VersionOverrides
Work with Extended Overrides of the
manifest
Article • 03/14/2023
Some extensibility features of Office Add-ins are configured with JSON files that are
hosted on your server, instead of with the add-in's XML manifest.
7 Note
This article assumes that you're familiar with Office Add-in manifests and their role
in add-ins. Please read Office Add-ins manifest, if you haven't recently.
The following table specifies the extensibility features that require an extended override
along with links to documentation of the feature.
Tip
This article is somewhat abstract. Consider reading one of the articles in the table
to add clarity to the concepts.
XML
...
</VersionOverrides>
<ExtendedOverrides Url="https://contoso.com/addin/extended-
overrides.json"></ExtendedOverrides>
</OfficeApp>
The following is an example of a very simple extended overrides JSON file. It assigns
keyboard shortcut CTRL+SHIFT+A to a function (defined elsewhere) that opens the add-
in's task pane.
JSON
{
"actions": [
{
"id": "SHOWTASKPANE",
"type": "ExecuteFunction",
"name": "Show task pane for add-in"
}
],
"shortcuts": [
{
"action": "SHOWTASKPANE",
"key": {
"default": "CTRL+SHIFT+A"
}
}
]
}
XML
...
</VersionOverrides>
<ExtendedOverrides Url="https://contoso.com/addin/extended-
overrides.json"
ResourceUrl="https://contoso.com/addin/my-
resources.json">
</ExtendedOverrides>
</OfficeApp>
For more details about how to create and use the resources file, how to refer to its
resources in the extended overrides file, and for additional options not discussed here,
see Localize extended overrides.
How to find the proper order of
manifest elements
Article • 03/23/2023
The XML elements in the manifest of an Office Add-in must be under the proper parent
element and in a specific order, relative to each other, under the parent.
The required ordering is specified in the XSD files in the Schemas folder. The XSD files
are categorized into subfolders for taskpane, content, and mail add-ins.
7 Note
The validator within office-addin-manifest uses the same error message when an
element is out-of-order as it does when an element is under the wrong parent. The
error says the child element is not a valid child of the parent element. If you get
such an error but the reference documentation for the child element indicates that
it is valid for the parent, then the problem is likely that the child has been placed in
the wrong order.
The following sections show the manifest elements in the order in which they must
appear. There are differences depending on whether the type attribute of the
<OfficeApp> element is TaskPaneApp , ContentApp , or MailApp . To keep these sections
from becoming too unwieldy, the highly complex <VersionOverrides> element is
broken out into separate sections.
7 Note
Not all of the elements shown are mandatory. If the minOccurs value for a element
is 0 in the schema, the element is optional.
*See Task pane add-in element ordering within VersionOverrides for the ordering of
children elements of VersionOverrides.
<OfficeApp xsi:type="MailApp">
<Id>
<AlternateId>
<Version>
<ProviderName>
<DefaultLocale>
<DisplayName>
<Override>
<Description>
<Override>
<IconUrl>
<Override>
<HighResolutionIconUrl>
<Override>
<SupportUrl>
<AppDomains>
<AppDomain>
<Hosts>
<Host>
<Requirements>
<Sets>
<Set>
<FormSettings>
<Form>
<DesktopSettings>
<SourceLocation>
<RequestedHeight>
<TabletSettings>
<SourceLocation>
<RequestedHeight>
<PhoneSettings>
<SourceLocation>
<Permissions>
<Rule>
<DisableEntityHighlighting>
<VersionOverrides>*
*See Mail add-in element ordering within VersionOverrides Ver. 1.0 and Mail add-in
element ordering within VersionOverrides Ver. 1.1 for the ordering of children elements
of VersionOverrides.
<OfficeApp xsi:type="ContentApp">
<Id>
<AlternateId>
<Version>
<ProviderName>
<DefaultLocale>
<DisplayName>
<Override>
<Description>
<Override>
<IconUrl >
<Override>
<HighResolutionIconUrl>
<Override>
<SupportUrl>
<AppDomains>
<AppDomain>
<Hosts>
<Host>
<Requirements>
<Sets>
<Set>
<Methods>
<Method>
<DefaultSettings>
<SourceLocation>
<Override>
<RequestedWidth>
<RequestedHeight>
<Permissions>
<AllowSnapshot>
<VersionOverrides>*
*See Content add-in element ordering within VersionOverrides for the ordering of
children elements of VersionOverrides.
<VersionOverrides>
<Description>
<Requirements>
<Sets>
<Set>
<Hosts>
<Host>
<Runtimes>
<Runtime>
<AllFormFactors>
<ExtensionPoint>
<Script>
<SourceLocation>
<Page>
<SourceLocation>
<Metadata>
<SourceLocation>
<Namespace>
<DesktopFormFactor>
<GetStarted>
<Title>
<Description>
<LearnMoreUrl>
<FunctionFile>
<ExtensionPoint>
<OfficeTab>
<Group>
<Label>
<Icon>
<Image>
<Control>
<Label>
<Supertip>
<Title>
<Description>
<Icon>
<Image>
<Action>
<TaskpaneId>
<SourceLocation>
<Title>
<FunctionName>
<Enabled>
<Items>
<Item>
<Label>
<Supertip>
<Title>
<Description>
<Action>
<TaskpaneId>
<SourceLocation>
<Title>
<FunctionName>
<CustomTab>
<Group> (can be below <ControlGroup>)
<OverriddenByRibbonApi>
<Label>
<Icon>
<Image>
<Control>
<OverriddenByRibbonApi>
<Label>
<Supertip>
<Title>
<Description>
<Icon>
<Image>
<Action>
<TaskpaneId>
<SourceLocation>
<Title>
<FunctionName>
<Enabled>
<Items>
<Item>
<OverriddenByRibbonApi>
<Label>
<Supertip>
<Title>
<Description>
<Action>
<TaskpaneId>
<SourceLocation>
<Title>
<FunctionName>
<ControlGroup> (can be above <Group>)
<Label>
<InsertAfter> (or <InsertBefore>)
<OfficeMenu>
<Control>
<Label>
<Supertip>
<Title>
<Description>
<Icon>
<Image>
<Action>
<TaskpaneId>
<SourceLocation>
<Title>
<FunctionName>
<Enabled>
<Items>
<Item>
<Label>
<Supertip>
<Title>
<Description>
<Action>
<TaskpaneId>
<SourceLocation>
<Title>
<FunctionName>
<Resources>
<Images>
<Image>
<Override>
<Urls>
<Url>
<Override>
<ShortStrings>
<String>
<Override>
<LongStrings>
<String>
<Override>
<WebApplicationInfo>
<Id>
<Resource>
<Scopes>
<Scope>
<EquivalentAddins>
<EquivalentAddin>
<ProgId>
<DisplayName>
<FileName>
<Type>
<VersionOverrides>
<Description>
<Requirements>
<Sets>
<Set>
<Hosts>
<Host>
<DesktopFormFactor>
<ExtensionPoint>
<OfficeTab>
<Group>
<Label>
<Control>
<Label>
<Supertip>
<Title>
<Description>
<Icon>
<Image>
<Action>
<SourceLocation>
<FunctionName>
<CustomTab>
<Group>
<Label>
<Icon>
<Image>
<Control>
<Label>
<Supertip>
<Title>
<Description>
<Icon>
<Image>
<Action>
<TaskpaneId>
<SourceLocation>
<Title>
<FunctionName>
<Items>
<Item>
<Label>
<Supertip>
<Title>
<Description>
<Action>
<TaskpaneId>
<SourceLocation>
<Title>
<FunctionName>
<Label>
<OfficeMenu>
<Control>
<Label>
<Supertip>
<Title>
<Description>
<Icon>
<Image>
<Action>
<TaskpaneId>
<SourceLocation>
<Title>
<FunctionName>
<Items>
<Item>
<Label>
<Supertip>
<Title>
<Description>
<Action>
<TaskpaneId>
<SourceLocation>
<Title>
<FunctionName>
<Resources>
<Images>
<Image>
<Override>
<Urls>
<Url>
<Override>
<ShortStrings>
<String>
<Override>
<LongStrings>
<String>
<Override>
<VersionOverrides>*
<VersionOverrides>
<Description>
<Requirements>
<Sets>
<Set>
<Hosts>
<Host>
<DesktopFormFactor>
<ExtensionPoint>
<OfficeTab>
<Group>
<Label>
<Control>
<Label>
<Supertip>
<Title>
<Description>
<Icon>
<Image>
<Action>
<SourceLocation>
<FunctionName>
<CustomTab>
<Group>
<Label>
<Icon>
<Image>
<Control>
<Label>
<Supertip>
<Title>
<Description>
<Icon>
<Image>
<Action>
<TaskpaneId>
<SourceLocation>
<Title>
<FunctionName>
<Items>
<Item>
<Label>
<Supertip>
<Title>
<Description>
<Action>
<TaskpaneId>
<SourceLocation>
<Title>
<FunctionName>
<Label>
<OfficeMenu>
<Control>
<Label>
<Supertip>
<Title>
<Description>
<Icon>
<Image>
<Action>
<TaskpaneId>
<SourceLocation>
<Title>
<FunctionName>
<Items>
<Item>
<Label>
<Supertip>
<Title>
<Description>
<Action>
<TaskpaneId>
<SourceLocation>
<Title>
<FunctionName>
<SourceLocation>
<Label>
<CommandSurface>
<MobileFormFactor>
<ExtensionPoint>
<Group>
<Label>
<Control>
<Label>
<Icon>
<Image>
<Action>
<SourceLocation>
<FunctionName>
<Control>
<Label>
<Icon>
<Image>
<Action>
<SourceLocation>
<FunctionName>
<Resources>
<Images>
<Image>
<Override>
<Urls>
<Url>
<Override>
<ShortStrings>
<String>
<Override>
<LongStrings>
<String>
<Override>
<WebApplicationInfo>
<Id>
<Resource>
<Scopes>
<Scope>
<VersionOverrides>
<WebApplicationInfo>
<Id>
<Resource>
<Scopes>
<Scope>
See also
Reference for Office Add-ins manifests (v1.1)
Official schema definitions
Update to the latest Office JavaScript
API library and version 1.1 add-in
manifest schema
Article • 04/11/2023
This article describes how to update your JavaScript files (Office.js and app-specific .js
files) and add-in manifest validation file in your Office Add-in project to version 1.1.
7 Note
Projects created in Visual Studio 2019 or later will already use version 1.1. However,
there are occasional minor updates to version 1.1 that you can apply by using the
techniques in this article.
If you use a text editor or IDE other than Visual Studio to develop your add-in, you need
to update the references to the content delivery network (CDN) for Office.js and the
version of schema referenced in your add-in's manifest.
Note that the update process is applied on a per-project basis - you'll need to repeat the
updating process for each add-in project in which you want to use v1.1 of Office.js and
add-in manifest schema.
Update the Office JavaScript API library files in your
project to the newest release
The following steps will update your Office.js library files to the latest version. The steps
use Visual Studio 2019, but they are similar for previous versions of Visual Studio.
You'll need to take a few additional steps to complete the update. In the head tag of
your add-in's HTML pages, comment out or delete any existing office.js script
references, and reference the updated Office JavaScript API library as follows:
HTML
<script src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js"
type="text/javascript"></script>
7 Note
The /1/ in the office.js in the CDN URL specifies to use the latest incremental
release within version 1 of Office.js.
XML
7 Note
After updating the version of the add-in manifest schema to 1.1, you will need to
remove the Capabilities and Capability elements, and replace them with either the
Hosts and Host elements or the Requirements and Requirement elements.
The update process is applied on a per-project basis - you'll need to repeat the updating
process for each add-in project in which you want to use v1.1 of Office.js and add-in
manifest schema.
You don't need local copies of the Office JavaScript API files (Office.js and app-specific
.js files) to develop anOffice Add-in (referencing the CDN for Office.js downloads the
necessary files at runtime), but if you want a local copy of the library files you can use
the NuGet Command-Line Utility and the Install-Package Microsoft.Office.js
command to download them.
7 Note
To get a copy of the XSD (XML Schema Definition) for the v1.1 add-in manifest, see
the listing in Schema reference for Office Add-ins manifests.
2. In the head tag of your add-in's HTML pages, comment out or delete any existing
office.js script references, and reference the updated Office JavaScript API library as
follows:
HTML
<script
src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js"
type="text/javascript"></script>
7 Note
The /1/ in front of office.js in the CDN URL specifies to use the latest
incremental release within version 1 of Office.js.
XML
</OfficeApp>
7 Note
After updating the version of the add-in manifest schema to 1.1, you will need to
remove the Capabilities and Capability elements, and replace them with either the
Hosts and Host elements or the Requirements and Requirement elements.
See also
Specify Office applications and API requirements ]
Understanding the Office JavaScript API
Office JavaScript API
Schema reference for Office Add-ins manifests
Privacy and security for Office Add-ins
Article • 04/11/2023
Process security
Office Add-ins are secured by an add-in runtime environment, a multiple-tier
permissions model, and performance governors. This framework protects the user's
experience in the following ways.
Modal interactions aren't allowed - for example, calls to JavaScript alert , confirm ,
and prompt methods aren't allowed because they're modal.
Further, the runtime framework provides the following benefits to ensure that an Office
Add-in can't damage the user's environment.
Also, the use of memory, CPU, and network resources by Office Add-ins is governable to
ensure that good performance and reliability are maintained.
7 Note
The following sections briefly describe how the runtime architecture supports running
add-ins in Office clients on Windows-based devices, on Mac OS X devices, and in web
browsers.
On Windows desktops, Protected Mode in Internet Explorer must be enabled for the
Restricted Site Zone. This is typically enabled by default. If it is disabled, an error will
occur when you try to launch an add-in.
Figure 1. Office Add-ins runtime environment in Windows-based desktop and tablet clients
As shown in the following figure, on a Mac OS X desktop, the add-in web page is hosted
inside a sandboxed WebKit runtime host process which helps provide similar level of
security and performance protection.
Web clients
In supported web clients, Office Add-ins are hosted in an iframe that runs using the
HTML5 sandbox attribute. ActiveX components or navigating the main page of the web
client are not allowed. Office Add-ins support is enabled in the web clients by the
integration of the JavaScript API for Office. In a similar way to the desktop client
applications, the JavaScript API manages the add-in lifecycle and interoperability
between the add-in and the web client. This interoperability is implemented by using a
special cross-frame post message communication infrastructure. The same JavaScript
library (Office.js) that is used on desktop clients is available to interact with the web
client. The following figure shows the infrastructure that supports add-ins in Office
running in the browser, and the relevant components (the web client, iframe, Office
Add-ins runtime, and JavaScript API for Office) that are required to support them.
Requires the host server of an Office Add-in to always use Secure Sockets Layer
(SSL) to communicate.
Note that if an IT admin disables the use of connected experiences in Office, it has the
same effect on add-ins as turning off just optional connected experiences.
7 Note
Users may see a security prompt to trust the domain the first time an add-in is
loaded. This will happen if the add-in's domain host is outside of the domain of
Exchange on-premise or Office Online Server.
The add-in platform addresses end users' privacy concerns in the following ways.
Data communicated with the web server that hosts a content, Outlook or task pane
add-in as well as communication between the add-in and any web services it uses
must be encrypted using the Secure Socket Layer (SSL) protocol.
Before a user installs an add-in from AppSource, the user can view the privacy
policy and requirements of that add-in. In addition, Outlook add-ins that interact
with users' mailboxes surface the specific permissions that they require; the user
can review the terms of use, requested permissions and privacy policy before
installing an Outlook add-in.
When sharing a document, users also share add-ins that have been inserted in or
associated with that document. If a user opens a document that contains an add-in
that the user hasn't used before, the Office client application prompts the user to
grant permission for the add-in to run in the document. In an organizational
environment, the Office client application also prompts the user if the document
comes from an external source.
Users can enable or disable the access to AppSource. For content and task pane
add-ins, users manage access to trusted add-ins and catalogs from the Trust
Center on the host Office client (opened from File > Options > Trust Center >
Trust Center Settings > Trusted Add-in Catalogs). In Outlook, access to manage
add-ins depends on the user's Outlook client.
For instructions on how to manage add-ins in Outlook on Windows or on Mac,
see Get an Office Add-in for Outlook .
In Outlook on the web, select Get Add-ins from the ribbon. To learn more, see
Using add-ins in Outlook on the web .
Administrators can also manage access to AppSource through the admin center.
The design of the add-in platform provides security and performance for end users
in the following ways.
Outlook add-ins provide additional security and performance features through Outlook
add-in specific resource usage monitoring. For more information, see Privacy,
permissions, and security for Outlook add-ins.
The Settings object is intended for persisting add-in settings and state data across
sessions for a content or task pane add-in, but don't store passwords and other
sensitive PII in the Settings object. The data in the Settings object isn't visible to
end users, but it is stored as part of the document's file format which is readily
accessible. You should limit your add-in's use of PII and store any PII required by
your add-in on the server hosting your add-in as a user-secured resource.
Using some applications can reveal PII. Make sure that you securely store data for
your users' identity, location, access times, and any other credentials so that data
won't become available to other users of the add-in.
If you store users' PII, make sure you reveal that fact, and provide a way for users
to inspect and delete it. If you submit your add-in to AppSource, you can outline
the data you collect and how it's used in the privacy statement.
Permissions choices
The add-in platform provides a permissions model that your add-in uses to declare the
level of access to a user's data that it requires for its features. Each permission level
corresponds to the subset of the JavaScript API for Office your add-in is allowed to use
for its features. For example, the WriteDocument permission for content and task pane
add-ins allows access to the Document.setSelectedDataAsync method that lets an add-
in write to the user's document, but doesn't allow access to any of the methods for
reading data from the document. This permission level makes sense for add-ins that
only need to write to a document, such as an add-in where the user can query for data
to insert into their document.
As a best practice, you should request permissions based on the principle of least
privilege. That is, you should request permission to access only the minimum subset of
the API that your add-in requires to function correctly. For example, if your add-in needs
only to read data in a user's document for its features, you should request no more than
the ReadDocument permission. (But, keep in mind that requesting insufficient
permissions will result in the add-in platform blocking your add-in's use of some APIs
and will generate errors at run time.)
You specify permissions in the manifest of your add-in, as shown in the example in this
section below, and end users can see the requested permission level of an add-in before
they decide to install or activate the add-in for the first time. Additionally, Outlook add-
ins that request the ReadWriteMailbox permission require explicit administrator
privilege to install.
The following example shows how a task pane add-in specifies the ReadDocument
permission in its manifest. To keep permissions as the focus, other elements in the
manifest aren't displayed.
XML
... <!-- To keep permissions as the focus, not displaying other elements. --
>
<Permissions>ReadDocument</Permissions>
...
</OfficeApp>
For more information about permissions for task pane and content add-ins, see
Requesting permissions for API use in add-ins.
For more information about permissions for Outlook add-ins, see the following topics.
One way to overcome this limitation is to use JSON/P -- provide a proxy for the web
service by including a script tag with a src attribute that points to some script hosted on
another domain. You can programmatically create the script tags, dynamically creating
the URL to which to point the src attribute, and passing parameters to the URL via URI
query parameters. Web service providers create and host JavaScript code at specific
URLs, and return different scripts depending on the URI query parameters. These scripts
then execute where they are inserted and work as expected.
JavaScript
// Dynamically create an HTML SCRIPT element that obtains the details for
the specified video.
function loadVideoDetails(videoIndex) {
// Dynamically create a new HTML SCRIPT element in the webpage.
const script = document.createElement("script");
// Specify the URL to retrieve the indicated video from a feed of a
current list of videos,
// as the value of the src attribute of the SCRIPT element.
script.setAttribute("src", "https://gdata.youtube.com/feeds/api/videos/"
+
videos[videoIndex].Id + "?alt=json-in-
script&callback=videoDetailsLoaded");
// Insert the SCRIPT element at the end of the HEAD section.
document.getElementsByTagName('head')[0].appendChild(script);
}
Instead of the DOM property innerHTML , use the innerText and textContent
properties where appropriate. Do the following for Internet Explorer and Firefox
cross-browser support.
JavaScript
If you must use innerHTML, make sure the user's input doesn't contain malicious
content before passing it to innerHTML. For more information and an example of
how to use innerHTML safely, see innerHTML property.
If you are using jQuery, use the .text() method instead of the .html() method.
Use the toStaticHTML method to remove any dynamic HTML elements and
attributes in users' input before passing it to innerHTML.
See Developing secure add-ins for more best practices to create more secure web
solutions.
First, identify sensitive actions that your add-in can perform. These include any actions
that an unauthorized user could use with malicious intent, such as initiating a financial
transaction or publishing sensitive data. For example, your add-in might let the user
send a payment to a user-defined recipient.
Second, for sensitive actions, your add-in should confirm with the user before it
executes the action. This confirmation should detail what effect the action will have. It
should also detail how the user can prevent the action, if necessary, whether by
choosing a specific button marked "Don't Allow" or by ignoring the confirmation.
Third, to ensure that no potential attacker can hide or mask the confirmation, you
should display it outside the context of the add-in (that is, not in an HTML dialog box).
The following are some examples of how you could get confirmation.
Send a text message to the user that includes a confirmation code that the user
can enter in the add-in.
Open a confirmation dialog in a new browser window to a page that cannot be
iframed. This is typically the pattern that is used by login pages. Use the dialog api
to create a new dialog.
Also, ensure that the address you use for contacting the user couldn't have been
provided by a potential attacker. For example, for payment confirmations use the
address on file for the authorized user's account.
Content and task pane add-ins assume the same SSL settings that the browser
uses by default, and allows most content to be delivered only by SSL. Outlook add-
ins require all content to be delivered by SSL. Developers must specify in the
<SourceLocation> element of the add-in manifest a URL that uses HTTPS, to
identify the location of the HTML file for the add-in.
To make sure add-ins aren't delivering content by using HTTP, when testing add-
ins, developers should make sure the following settings are selected in Internet
Options in Control Panel and no security warnings appear in their test scenarios.
Make sure the security setting, Display mixed content, for the Internet zone is
set to Prompt. You can do that by selecting the following in Internet Options:
on the Security tab, select the Internet zone, select Custom level, scroll to look
for Display mixed content, and select Prompt if it isn't already selected.
Make sure Warn if Changing between Secure and not secure mode is selected
in the Advanced tab of the Internet Options dialog box.
To make sure that add-ins don't use excessive CPU core or memory resources and
cause any denial of service on a client computer, the add-in platform establishes
resource usage limits. As part of testing, developers should verify whether an add-
in performs within the resource usage limits.
Before publishing an add-in, developers should make sure that any personal
identifiable information that they expose in their add-in files is secure.
Developers shouldn't embed keys that they use to access APIs or services from
Microsoft and others (such as Bing, Google, or Facebook) directly in the HTML
pages of their add-in. Instead, they should create a custom web service or store
the keys in some other form of secure web storage that they can then call to pass
the key value to their add-in.
Other than resource usage rules, developers for Outlook add-ins should also make sure
their add-ins observe limits for specifying activation rules and using the JavaScript API.
For more information, see Limits for activation and JavaScript API for Outlook add-ins.
IT administrators' control
In a corporate setting, IT administrators have ultimate authority over enabling or
disabling access to AppSource and any private catalogs.
The management and enforcement of Office settings is done with group policy settings.
These are configurable through the Office Deployment Tool, in conjunction with the
Office Customization Tool.
Allow Unsecure Allows users to run non-secure Office Add-ins, which are Office Add-ins that
web add-ins and have webpage or catalog locations that are not SSL-secured (https://) and are
Catalogs not in users' Internet zones.
Block Web Add- Allows you to prevent users from running Office Add-ins that use web
ins technologies.
Block the Office Allows you to prevent users from getting or running Office Add-ins that come
Store from the Office Store.
See also
Requesting permissions for API use in add-ins
Privacy, permissions, and security for Outlook add-ins
Understanding Outlook add-in permissions
Limits for activation and JavaScript API for Outlook add-ins
Addressing same-origin policy limitations in Office Add-ins
Same Origin Policy
Same Origin Policy Part 1: No Peeking
Same origin policy for JavaScript
IE Protect Mode
Privacy controls for Microsoft 365 Apps
Requesting permissions for API use in
add-ins
Article • 05/18/2023
This article describes the different permission levels that you can declare in your content
or task pane add-in's manifest to specify the level of JavaScript API access your add-in
requires for its features.
7 Note
To learn about permission levels for mail (Outlook) add-ins, see Outlook
permissions model.
Permissions model
A five-level JavaScript API access-permissions model provides the basis for privacy and
security for users of your content and task pane add-ins. Figure 1 shows the five levels
of API permissions you can declare in your add-in's manifest.
Figure 1. The five-level permission model for content and task pane add-ins
These permissions specify the subset of the API that the add-in runtime will allow your
content or task pane add-in to use when a user inserts, and then activates (trusts) your
add-in. To declare the permission level your content or task pane add-in requires,
specify one of the permission text values in the Permissions element of your add-in's
manifest. The following example requests the WriteDocument permission, which will
allow only methods that can write to (but not read) the document.
XML
<Permissions>WriteDocument</Permissions>
As a best practice, you should request permissions based on the principle of least
privilege. That is, you should request permission to access only the minimum subset of
the API that your add-in requires to function correctly. For example, if your add-in needs
only to read data in a user's document for its features, you should request no more than
the ReadDocument permission.
The following table describes the subset of the JavaScript API that is enabled by each
permission level.
ReadDocument In addition to the API allowed by the Restricted permission, adds access
to the API members necessary to read the document and manage
bindings. This includes the use of:
WriteDocument In addition to the API allowed by the Restricted permission, adds access
to the following API members.
See also
Privacy and security for Office Add-ins
Develop your Office Add-in to work
with ITP when using third-party cookies
Article • 08/23/2022
If your Office Add-in requires third-party cookies, those cookies are blocked if the
Runtime that loaded your add-in uses Intelligent Tracking Prevention (ITP). You may be
using third-party cookies to authenticate users, or for other scenarios, such as storing
settings.
If your Office Add-in and website must rely on third-party cookies, use the following
steps to work with ITP.
1. Set up OAuth 2.0 Authorization so that the authenticating domain (in your case,
the third-party that expects cookies) forwards an authorization token to your
website. Use the token to establish a first-party login session with a server-
set Secure and HttpOnly cookie .
2. Use the Storage Access API so that the third-party can request permission to get
access to its first-party cookies. Current versions of Office on Mac and Office on
the web both support this API.
7 Note
If you're using cookies for purposes other than authentication, then consider
using localStorage for your scenario.
The following code sample shows how to use the Storage Access API.
JavaScript
function displayLoginButton() {
const button = createLoginButton();
button.addEventListener("click", function(ev) {
document.requestStorageAccess().then(function() {
authenticateWithCookies();
}).catch(function() {
// User must have previously interacted with this domain loaded in a
top frame
// Also you should have previously written a cookie when domain was
loaded in the top frame
console.error("User cancelled or requirements were not met.");
});
});
}
if (document.hasStorageAccess) {
document.hasStorageAccess().then(function(hasStorageAccess) {
if (!hasStorageAccess) {
displayLoginButton();
} else {
authenticateWithCookies();
}
});
} else {
authenticateWithCookies();
}
When developing Office Add-ins on Mac, access to third-party cookies is blocked by the
MacOS Big Sur SDK. This is because WKWebView ITP is enabled by default on the Safari
browser, and WKWebView blocks all third-party cookies. Office on Mac version 16.44 or
later is integrated with the MacOS Big Sur SDK.
In the Safari browser, end users can toggle the Prevent cross-site tracking checkbox
under Preference > Privacy to turn off ITP. However, ITP cannot be turned off for the
embedded WKWebView control.
See also
Handle ITP in Safari and other browsers where third-party cookies are blocked
Tracking Prevention in WebKit
Chrome’s “Privacy Sandbox”
Introducing the Storage Access API
Addressing same-origin policy
limitations in Office Add-ins
Article • 08/02/2023
The same-origin policy enforced by the browser or webview control prevents a script
loaded from one domain from getting or manipulating properties of a webpage from
another domain. This means that, by default, the domain of a requested URL must be
the same as the domain of the current webpage. For example, this policy will prevent a
webpage in one domain from making XmlHttpRequest web-service calls to a domain
other than the one where it is hosted.
Because Office Add-ins are hosted in a webview control, the same-origin policy applies
to script running in their web pages as well.
The following is an example of JSONP that uses a technique that will work in any Office
Add-in.
JavaScript
// Dynamically create an HTML SCRIPT element that obtains the details for
the specified video.
function loadVideoDetails(videoIndex) {
// Dynamically create a new HTML SCRIPT element in the webpage.
const script = document.createElement("script");
// Specify the URL to retrieve the indicated video from a feed of a
current list of videos,
// as the value of the src attribute of the SCRIPT element.
script.setAttribute("src", "https://gdata.youtube.com/feeds/api/videos/"
+
videos[videoIndex].Id + "?alt=json-in-
script&callback=videoDetailsLoaded");
// Insert the SCRIPT element at the end of the HEAD section.
document.getElementsByTagName('head')[0].appendChild(script);
}
See also
Privacy and security for Office Add-ins
Overview of authentication and
authorization in Office Add-ins
Article • 06/23/2023
Office Add-ins allow anonymous access by default, but you can require users to sign in
to use your add-in with a Microsoft account, a Microsoft 365 Education or work account,
or other common account. This task is called user authentication because it enables the
add-in to know who the user is.
Your add-in can also get the user's consent to access their Microsoft Graph data (such as
their Microsoft 365 profile, OneDrive files, and SharePoint data) or data in other external
sources such as Google, Facebook, LinkedIn, SalesForce, and GitHub. This task is called
add-in (or app) authorization, because it's the add-in that is being authorized, not the
user.
SSO scenarios
Using Single Sign-on (SSO) is convenient for the user because they only have to sign in
once to Office. They don't need to sign in separately to your add-in. SSO isn't supported
on all versions of Office, so you'll still need to implement an alternative sign-in
approach, by using the Microsoft identity platform. For more information on supported
Office versions, see Identity API requirement sets
Get the user's identity through SSO
Often your add-in only needs the user's identity. For example, you may just want to
personalize your add-in and display the user's name on the task pane. Or you might
want a unique ID to associate the user with their data in your database. This can be
accomplished by just getting the access token for the user from Office.
To get the user's identity through SSO, call the getAccessToken method. The method
returns an access token that is also an identity token containing several claims that are
unique to the current signed in user, including preferred_username , name , sub , and oid .
For more information on these properties, see Microsoft identity platform ID tokens. For
an example of the token returned by getAccessToken, see Example access token.
If the user isn't signed in, Office will open a dialog box and use the Microsoft identity
platform to request the user to sign in. Then the method will return an access token, or
throw an error if unable to sign in the user.
In a scenario where you need to store data for the user, refer to Microsoft identity
platform ID tokens for information about how to get a value from the token to uniquely
identify the user. Use that value to look up the user in a user table or user database that
you maintain. Use the database to store user-relative information such as the user's
preferences or the state of the user's account. Since you're using SSO, your users don't
sign-in separately to your add-in, so you don't need to store a password for the user.
Before you begin implementing user authentication with SSO, be sure that you're
thoroughly familiar with the article Enable single sign-on for Office Add-ins.
The following code shows how to construct an HTTPS GET request to the add-in's web
server API to get some data. The code runs on the client side, such as in a task pane. It
first gets the access token by calling getAccessToken . Then it constructs an AJAX call
with the correct authorization header and URL for the server API.
JavaScript
function getOneDriveFileNames() {
let accessToken = await Office.auth.getAccessToken();
$.ajax({
url: "/api/data",
headers: { "Authorization": "Bearer " + accessToken },
type: "GET"
})
.done(function (result) {
//... work with data from the result...
});
}
The following code shows an example /api/data handler for the REST call from the
previous code example. The code is ASP.NET code running on a web server. The
[Authorize] attribute will require that a valid access token is passed from the client, or
C#
[Authorize]
// GET api/data
public async Task<HttpResponseMessage> Get()
{
//... obtain and return data to the client-side code...
}
1. Get the access token for the current user through SSO by calling getAccessToken. If
the user isn't signed in, Office will open a dialog box and sign in the user with the
Microsoft identity platform. After the user signs in, or if the user is already signed
in, the method returns an access token.
2. Pass the access token to your server-side code.
3. On the server-side, use the OAuth 2.0 On-Behalf-Of flow to exchange the access
token for a new access token containing the necessary delegated user identity and
permissions to call Microsoft Graph.
7 Note
For best security to avoid leaking the access token, always perform the On-Behalf-
Of flow on the server-side. Call Microsoft Graph APIs from your server, not the
client. Don't return the access token to the client-side code.
Before you begin implementing SSO to access Microsoft Graph in your add-in, be sure
that you're thoroughly familiar with the following articles.
You should also read at least one of the following articles that'll walk you through
building an Office Add-in to use SSO and access Microsoft Graph. Even if you don't
carry out the steps, they contain valuable information about how you implement SSO
and the On-Behalf-Of flow.
Create an ASP.NET Office Add-in that uses single sign-on which walks you through
the sample at Office Add-in ASP.NET SSO .
Create an Node.js Office Add-in that uses single sign-on which walks you through
the sample at Office Add-in NodeJS SSO .
Non-SSO scenarios
In some scenarios, you may not want to use SSO. For example, you may need to
authenticate using a different identity provider than the Microsoft identity platform.
Also, SSO isn't supported in all scenarios. For example, older versions of Office don't
support SSO. In this case, you'd need to fall back to an alternate authentication system
for your add-in.
It's important to note that the Microsoft identity platform doesn't allow its sign-in page
to open in an iframe. When an Office Add-in is running in Office on the web, the task
pane is an iframe. This means that you'll need to open the sign-in page by using a
dialog box opened with the Office dialog API. This affects how you use authentication
helper libraries. For more information, see Authentication with the Office dialog API.
For information about implementing authentication with the Microsoft identity platform,
see Microsoft identity platform (v2.0) overview. The documentation contains many
tutorials and guides, as well as links to relevant samples and libraries. As explained in
Authentication with the Office dialog API, you may need to adjust the code in the
samples to run in the Office dialog box.
) Important
Before you begin coding, find out if the data source allows its sign-in page to open
in an iframe. When an Office Add-in is running in Office on the web, the task pane is
an iframe. If the data source doesn't allow its sign-in page to open in an iframe,
then you'll need to open the sign-in page in a dialog box opened with the Office
dialog API. For more information, see Authentication with the Office dialog API.
See also
Microsoft identity platform documentation
Microsoft identity platform access tokens
OAuth 2.0 and OpenID Connect protocols on the Microsoft identity platform
Microsoft identity platform and OAuth 2.0 On-Behalf-Of flow
JSON web token (JWT)
JSON web token viewer
Enable single sign-on (SSO) in an Office
Add-in
Article • 08/14/2023
Users sign in to Office using either their personal Microsoft account or their Microsoft
365 Education or work account. Take advantage of this and use single sign-on (SSO) to
authenticate and authorize the user to your add-in without requiring them to sign in a
second time.
ken
t to d
ues rne
Open dialog
Req retu
en
Tok
Add-in client-side
Call getAccessToken
Token returned
1. In the add-in, your JavaScript code calls the Office.js API getAccessToken. If the
user is already signed in to Office, the Office host will return the access token with
the claims of the signed in user.
2. If the user is not signed in, the Office host application opens a dialog box for the
user to sign in. Office redirects to the Microsoft identity platform to complete the
sign-in process.
3. If this is the first time the current user has used your add-in, they are prompted to
consent.
4. The Office host application requests the access token from the Microsoft identity
platform for the current user.
5. The Microsoft identity platform returns the access token to Office. Office will cache
the token on your behalf so that future calls to getAccessToken simply return the
cached token.
6. The Office host application returns the access token to the add-in as part of the
result object returned by the getAccessToken call.
7. The token is both an access token and an identity token. You can use it as an
identity token to parse and examine claims about the user, such as the user's name
and email address.
8. Optionally, the add-in can use the token as an access token to make authenticated
HTTPS requests to APIs on the server-side. Because the access token contains
identity claims, the server can store information associated with the user's identity;
such as the user's preferences.
For Excel, Word, and PowerPoint add-ins you will typically want to fall back to using the
Microsoft identity platform. For more information, see Authenticate with the Microsoft
identity platform.
For Outlook add-ins, there is a recommended fallback system. For more information, see
Scenario: Implement single sign-on to your service in an Outlook add-in.
You can also use a system of user tables and authentication, or you can leverage one of
the social login providers. For more information about how to do this with an Office
Add-in, see Authorize external services in your Office Add-in.
For code samples that use the Microsoft identity platform as the fallback system, see
Office Add-in NodeJS SSO and Office Add-in ASP.NET SSO .
For more details about this process, see Register an Office Add-in that uses SSO with the
Microsoft identity platform.
For Word, Excel, and PowerPoint add-ins, add the markup to the end of the
<VersionOverrides ... xsi:type="VersionOverridesV1_0"> section. For Outlook add-ins,
XML
<WebApplicationInfo>
<Id>5661fed9-f33d-4e95-b6cf-624a34a2f51d</Id>
<Resource>api://addin.contoso.com/5661fed9-f33d-4e95-b6cf-
624a34a2f51d</Resource>
<Scopes>
<Scope>openid</Scope>
<Scope>user.read</Scope>
<Scope>files.read</Scope>
<Scope>profile</Scope>
</Scopes>
</WebApplicationInfo>
) Important
7 Note
If you don't follow the format requirements in the manifest for SSO, your add-in
will be rejected from AppSource until it meets the required format.
Call getAccessToken.
Parse the access token or pass it to the add-in’s server-side code.
The following code shows a simple example of calling getAccessToken and parsing the
token for the user name and other credentials.
7 Note
This example handles only one kind of error explicitly. For examples of more
elaborate error handling, see Office Add-in NodeJS SSO and Office Add-in
ASP.NET SSO .
JavaScript
If your add-in requires a signed in user, then you should call getAccessToken from inside
Office.initialize . You should also pass allowSignInPrompt: true in the options
parameter of getAccessToken . For example; OfficeRuntime.auth.getAccessToken( {
allowSignInPrompt: true }); This will ensure that if the user is not yet signed in, that
If the add-in has some functionality that doesn't require a signed in user, then you can
call getAccessToken when the user takes an action that requires a signed in user. There is
no significant performance degradation with redundant calls of getAccessToken because
Office caches the access token and will reuse it, until it expires, without making another
call to the Microsoft identity platform whenever getAccessToken is called. So you can
add calls of getAccessToken to all functions and handlers that initiate an action where
the token is needed.
) Important
As a best security practice, always call getAccessToken when you need an access
token. Office will cache it for you. Don't cache or store the access token using your
own code.
If you need to access Microsoft Graph data, your server-side code should do the
following:
Validate the access token (see Validate the access token below).
Initiate the OAuth 2.0 On-Behalf-Of flow with a call to the Microsoft identity
platform that includes the access token, some metadata about the user, and the
credentials of the add-in (its ID and secret). The Microsoft identity platform will
return a new access token that can be used to access Microsoft Graph.
Get data from Microsoft Graph by using the new token.
If you need to cache the new access token for multiple calls, we recommend using
Token cache serialization in MSAL.NET.
) Important
As a best security practice, always use the server-side code to make Microsoft
Graph calls, or other calls that require passing an access token. Never return the
OBO token to the client to enable the client to make direct calls to Microsoft Graph.
This helps protect the token from being intercepted or leaked. For more
information on the proper protocol flow, see the OAuth 2.0 protocol diagram
The following code shows an example of passing the access token to the server-side.
The token is passed in an Authorization header when sending a request to a server-side
web API. This example sends JSON data, so it uses the POST method, but GET is
sufficient to send the access token when you are not writing to the server.
JavaScript
$.ajax({
type: "POST",
url: "/api/DoSomething",
headers: {
"Authorization": "Bearer " + accessToken
},
data: { /* some JSON payload */ },
contentType: "application/json; charset=utf-8"
}).done(function (data) {
// Handle success
}).fail(function (error) {
// Handle error
}).always(function () {
// Cleanup
});
For more details about getting authorized access to the user's Microsoft Graph data, see
Authorize to Microsoft Graph in your Office Add-in.
this value.
The token's aud parameter will be set to the application ID of the add-in's Azure
app registration.
The token's scp parameter will be set to access_as_user .
For more information on token validation, see Microsoft identity platform access tokens.
oid - A GUID representing the ID of the user in the Microsoft identity system.
tid - A GUID representing the tenant tha the user is signing in to.
For more details on these and other claims, see Microsoft identity platform ID tokens. If
you need to construct a unique ID to represent the user in your system, refer to Using
claims to reliably identify a user for more information.
JavaScript
{
aud: "2c3caa80-93f9-425e-8b85-0745f50c0d24",
iss: "https://login.microsoftonline.com/fec4f964-8bc9-4fac-b972-
1c1da35adbcd/v2.0",
iat: 1521143967,
nbf: 1521143967,
exp: 1521147867,
aio:
"ATQAy/8GAAAA0agfnU4DTJUlEqGLisMtBk5q6z+6DB+sgiRjB/Ni73q83y0B86yBHU/WFJnlMQJ
8",
azp: "e4590ed6-62b3-5102-beff-bad2292ab01c",
azpacr: "0",
e_exp: 262800,
name: "Mila Nikolova",
oid: "6467882c-fdfd-4354-a1ed-4e13f064be25",
preferred_username: "milan@contoso.com",
scp: "access_as_user",
sub: "XkjgWjdmaZ-_xDmhgN1BMP2vL2YOfeVxfPT_o8GRWaw",
tid: "fec4f964-8bc9-4fac-b972-1c1da35adbcd",
uti: "MICAQyhrH02ov54bCtIDAA",
ver: "2.0"
}
See also
Microsoft identity platform documentation
Requirement sets
IdentityAPI
Single sign-on (SSO) quick start
Article • 05/02/2023
In this article, you'll use the Yeoman generator for Office Add-ins to create an Office
Add-in for Excel, Outlook, Word, or PowerPoint that uses single sign-on (SSO).
7 Note
The SSO template provided by the Yeoman generator for Office Add-ins only runs
on localhost and cannot be deployed. If you're building a new Office Add-in with
SSO for production purposes, follow the instructions in Create a Node.js Office
Add-in that uses single sign-on.
Prerequisites
Node.js (the latest LTS version).
The latest version of Yeoman and the Yeoman generator for Office Add-ins. To
install these tools globally, run the following command via the command prompt.
command line
7 Note
If you're using a Mac and don't have the Azure CLI installed on your machine, you
must install Homebrew . The SSO configuration script that you'll run during this
quick start will use Homebrew to install the Azure CLI, and will then use the Azure
CLI to configure SSO within Azure.
Tip
The Yeoman generator can create an SSO-enabled Office Add-in for Excel, Outlook,
Word, or PowerPoint with script type of JavaScript or TypeScript. The following
instructions specify JavaScript and Excel , but you should choose the script type
and Office client application that best suits your scenario.
Run the following command to create an add-in project using the Yeoman generator.
command line
yo office
7 Note
When you run the yo office command, you may receive prompts about the data
collection policies of Yeoman and the Office Add-in CLI tools. Use the information
that's provided to respond to the prompts as you see fit.
When prompted, provide the following information to create your add-in project.
Choose a project type: Office Add-in Task Pane project supporting single sign-
on (localhost)
Choose a script type: JavaScript
What do you want to name your add-in? My Office Add-in
Which Office client application would you like to support? Choose Excel ,
Outlook , Word , or Powerpoint .
After you complete the wizard, the generator creates the project and installs supporting
Node components.
Tip
You can ignore the next steps guidance that the Yeoman generator provides after
the add-in project's been created. The step-by-step instructions within this article
provide all of the guidance you'll need to complete this tutorial.
Configuration
The following files specify configuration settings for the add-in.
The ./manifest.xml file in the root directory of the project defines the settings and
capabilities of the add-in.
The ./.ENV file in the root directory of the project defines constants that are used
by the add-in project.
Task pane
The following files define the add-in's task pane UI and functionality.
The ./src/taskpane/taskpane.html file contains the HTML markup for the task
pane.
Authentication
The following files facilitate the SSO process and write data to the Office document.
Configure SSO
Now that your add-in project is created and contains the code that's necessary to
facilitate the SSO process, complete the following steps to configure SSO for your add-
in.
command line
command line
2 Warning
7 Note
4. After you enter your credentials, close the browser window and return to the
command prompt. As the SSO configuration process continues, you'll see status
messages being written to the console. As described in the console messages, files
within the add-in project that the Yeoman generator created are automatically
updated with data that's required by the SSO process.
1. When the SSO configuration process completes, run the following command to
build the project, start the local web server, and sideload your add-in in the
previously selected Office client application.
7 Note
Office Add-ins should use HTTPS, not HTTP, even when you are developing. If
you are prompted to install a certificate after you run one of the following
commands, accept the prompt to install the certificate that the Yeoman
generator provides. You may also have to run your command prompt or
terminal as an administrator for the changes to be made.
command line
npm start
2. When Excel, Word, or PowerPoint opens when you run the previous command,
make sure you're signed in with a user account that's a member of the same
Microsoft 365 organization as the Microsoft 365 administrator account that you
used to connect to Azure while configuring SSO in step 3 of the previous section.
Doing so establishes the appropriate conditions for SSO to succeed.
3. In the Office client application, choose the Home tab, and then choose Show
Taskpane to open the add-in task pane.
4. At the bottom of the task pane, choose the Get My User Profile Information
button to initiate the SSO process.
After a user accepts this permissions request, they won't be prompted again
in the future.
6. The add-in retrieves profile information for the signed-in user and writes it to the
document. The following image shows an example of profile information written to
an Excel worksheet.
Outlook
Complete the following steps to try out an Outlook add-in.
1. When the SSO configuration process completes, run the following command to
build the project and start the local web server.
7 Note
Office Add-ins should use HTTPS, not HTTP, even when you are developing. If
you are prompted to install a certificate after you run one of the following
commands, accept the prompt to install the certificate that the Yeoman
generator provides. You may also have to run your command prompt or
terminal as an administrator for the changes to be made.
command line
npm start
2. Follow the instructions in Sideload Outlook add-ins for testing to sideload the add-
in in Outlook. Make sure that you're signed in to Outlook with a user that's a
member of the same Microsoft 365 organization as the Microsoft 365
administrator account that you used to connect to Azure while configuring SSO in
step 3 of the previous section. Doing so establishes the appropriate conditions for
SSO to succeed.
4. In the message compose window, choose the Show Taskpane button to open the
add-in task pane.
5. At the bottom of the task pane, choose the Get My User Profile Information
button to initiate the SSO process.
6. If a dialog window appears to request permissions on behalf of the add-in, this
means that SSO is not supported for your scenario and the add-in has instead
fallen back to an alternate method of user authentication. This may occur when the
tenant administrator hasn't granted consent for the add-in to access Microsoft
Graph, or when the user isn't signed in to Office with a valid Microsoft account or
Microsoft 365 Education or Work account. Choose Accept to continue.
7 Note
After a user accepts this permissions request, they won't be prompted again
in the future.
7. The add-in retrieves profile information for the signed-in user and writes it to the
body of the email message.
Next steps
Congratulations, you've successfully created a task pane add-in that uses SSO when
possible, and uses an alternate method of user authentication when SSO is not
supported. To learn about customizing your add-in to add new functionality that
requires different permissions, see Customize your Node.js SSO-enabled add-in.
See also
Enable single sign-on for Office Add-ins
Customize your Node.js SSO-enabled add-in
Create a Node.js Office Add-in that uses single sign-on
Troubleshoot error messages for single sign-on (SSO)
Using Visual Studio Code to publish
Register an Office Add-in that uses
single sign-on (SSO) with the Microsoft
identity platform
Article • 04/18/2023
This article explains how to register an Office Add-in with the Microsoft identity platform
so that you can use SSO. Register the add-in when you begin developing it so that when
you progress to testing or production, you can change the existing registration or create
separate registrations for development, testing, and production versions of the add-in.
The following table itemizes the information that you need to carry out this procedure
and the corresponding placeholders that appear in the instructions.
A human readable name for the add-in. (Uniqueness Contoso Marketing <add-in-
recommended, but not required.) Excel Add-in name>
(Prod)
The fully qualified domain name (except for protocol) of the localhost:6789 , <fully-
add-in. You must use a domain that you own. For this reason, addins.contoso.com qualified-
you cannot use certain well-known domains such as domain-
azurewebsites.net or cloudapp.net . The domain must be name>
the same, including any subdomains, as is used in the URLs
in the <Resources> section of the add-in's manifest.
2. Select App registrations. If you don't see the icon, search for "app registration" in
the search bar.
6. Copy and save the values for the Application (client) ID and the Directory (tenant)
ID. You'll use both of them in later procedures.
Add a client secret
Sometimes called an application password, a client secret is a string value your app can
use in place of a certificate to identity itself.
1. From the left pane, select Certificates & secrets. Then on the Client secrets tab,
select New client secret.
Client secret lifetime is limited to two years (24 months) or less. You can't
specify a custom lifetime longer than 24 months.
Microsoft recommends that you set an expiration value of less than 12
months.
4. Select Add. The new secret is created and the value is temporarily displayed.
) Important
Record the secret's value for use in your client application code. This secret value is
never displayed again after you leave this pane.
7 Note
If you get an error saying that the domain is already owned but you own it,
follow the procedure at Quickstart: Add a custom domain name to Azure
Active Directory to register it, and then repeat this step. (This error can also
occur if you are not signed in with credentials of an admin in the Microsoft
365 tenancy. See step 2. Sign out and sign in again with admin credentials
and repeat the process from step 3.)
Add a scope
1. On the Expose an API page, select Add a scope.
2. In the Add a scope pane, specify the scope's attributes. The following table shows
example values for and Outlook add-in requiring the profile , openid ,
Files.ReadWrite , and Mail.Read permissions. Modify the text to match the
Scope The name of your scope. A For SSO this must be set to
name common scope naming access_as_user .
convention is
resource.operation.constraint .
Field Description Values
Who can Determines if admin consent is For learning SSO and samples, we
consent required or if users can consent recommend you set this to Admins and
without an admin approval. users.
The domain part of the Scope name displayed just below the text field should
automatically match the Application ID URI set in the previous step, with
/access_as_user appended to the end; for example,
api://localhost:6789/c6c1f32b-5e55-4997-881a-753cc1d563b7/access_as_user .
7 Note
5. In the Select permissions search box, search for the permissions your add-in
needs. For example, for an Outlook add-in, you might use profile , openid ,
Files.ReadWrite , and Mail.Read .
7 Note
6. Select the checkbox for each permission as it appears. Note that the permissions
will not remain visible in the list as you select each one. After selecting the
permissions that your add-in needs, select Add permissions.
7. Select Grant admin consent for [tenant name]. Select Yes for the confirmation
that appears.
3. Select Save.
A message pops up on the browser stating that the manifest was updated
successfully.
Congratulations! You've completed the app registration to enable SSO for your Office
add-in.
Grant administrator consent to the add-
in
Article • 06/23/2023
7 Note
This procedure is only needed when you're developing the add-in. When your
production add-in is deployed to AppSource or the Microsoft 365 admin center,
users will individually trust it or an admin will consent for the organization at
installation.
Carry out this procedure after you have registered the add-in.
1. Browse to the Azure portal - App registrations page to view your app
registration.
2. Sign in with the admin credentials to your Microsoft 365 tenancy. For example,
MyName@contoso.onmicrosoft.com.
7 Note
Use the getAccessToken API to get an access token that contains the identity for the
current user signed in to Office. The access token is also an ID token because it contains
identity claims about the signed-in user, such as their name and email. You can also use
the ID token to identify the user when calling your own web services. To call
getAccessToken , you must configure your Office Add-in to use SSO with Office.
In this article, you'll create an Office Add-in that gets the ID token, and displays the
user's name, email, and unique ID in the task pane.
7 Note
SSO with Office and the getAccessToken API don't work in all scenarios. Always
implement a fallback dialog to sign in the user when SSO is unavailable. For more
information, see Authenticate and authorize with the Office dialog API.
2. Sign in with the admin credentials to your Microsoft 365 tenancy. For example,
MyName@contoso.onmicrosoft.com.
3. Select New registration. On the Register an application page, set the values as
follows.
number for your web application. If you created the add-in using yo office,
the port number is typically 3000 and found in the package.json file. If you
created the add-in with Visual Studio 2019, the port is found in the SSL URL
property of the web project.
Choose Register.
4. On the Office-Add-in-SSO page, copy and save the values for the Application
(client) ID and the Directory (tenant) ID. You'll use both of them in later
procedures.
7 Note
5. Select Authentication under Manage. In the Implicit grant section, enable the
checkboxes for both Access token and ID token.
7. Select Expose an API under Manage. Select the Set link. This will generate the
Application ID URI in the form api://[app-id-guid] , where [app-id-guid] is the
Application (client) ID.
8. In the generated ID, insert localhost:[port]/ (note the forward slash "/"
appended to the end) between the double forward slashes and the GUID. Replace
[port] with the correct port number for your web application. If you created the
add-in using yo office, the port number is typically 3000 and found in the
package.json file. If you created the add-in with Visual Studio 2019, the port is
found in the SSL URL property of the web project.
When you're finished, the entire ID should have the form api://localhost:
[port]/[app-id-guid] ; for example api://localhost:44355/c6c1f32b-5e55-4997-
881a-753cc1d563b7 .
9. Select the Add a scope button. In the panel that opens, enter access_as_user as
the <Scope> name.
11. Fill in the fields for configuring the admin and user consent prompts with values
that are appropriate for the access_as_user scope which enables the Office client
application to use your add-in's web APIs with the same rights as the current user.
Suggestions:
7 Note
The domain part of the <Scope> name displayed just below the text field
should automatically match the Application ID URI that you set earlier, with
/access_as_user appended to the end; for example,
api://localhost:6789/c6c1f32b-5e55-4997-881a-753cc1d563b7/access_as_user .
14. In the Authorized client applications section, enter the following ID to pre-
authorize all Microsoft Office application endpoints.
endpoints)
7 Note
17. Select API permissions under Manage and select Add a permission. On the panel
that opens, choose Microsoft Graph and then choose Delegated permissions.
18. Use the Select permissions search box to search for the permissions your add-in
needs. Search for and select the profile permission. The profile permission is
required for the Office application to get a token to your add-in web application.
profile
7 Note
19. Select the Add permissions button at the bottom of the panel.
20. On the same page, choose the Grant admin consent for <tenant-name> button,
and then select Yes for the confirmation that appears.
The project is created and will contain two projects in the solution.
sso-display-user-info: Contains the manifest and details for sideloading the
add-in to Excel.
sso-display-user-infoWeb: The ASP.NET project that hosts the web pages for
the add-in.
1. Near the bottom of the manifest is a closing </Resources> element. Insert the
following XML just below the </Resources> element but before the closing
</VersionOverrides> element. For Office applications other than Outlook, add the
markup to the end of the <VersionOverrides ...
xsi:type="VersionOverridesV1_0"> section. For Outlook, add the markup to the
XML
<WebApplicationInfo>
<Id>[application-id]</Id>
<Resource>api://localhost:[port]/[application-id]</Resource>
<Scopes>
<Scope>openid</Scope>
<Scope>user.read</Scope>
<Scope>profile</Scope>
</Scopes>
</WebApplicationInfo>
2. Replace [port] with the correct port number for your project. If you created the
add-in using yo office, the port number is typically 3000 and found in the
package.json file. If you created the add-in with Visual Studio 2019, the port is
found in the SSL URL property of the web project.
your add-in doesn't access Microsoft Graph. If it does, you also need <Scope>
elements for the required Microsoft Graph permissions; for example, User.Read ,
Mail.Read . Libraries that you use in your code to access Microsoft Graph may need
2. On the menu, choose Tools > NuGet Package Manager > Package Manager
Console.
2. Add the following script tag to the <head> section of the page. This will
include the jwt-decode package was added earlier.
HTML
HTML
<body>
<h1>Welcome</h1>
<p>
Sign in to Office, then choose the <b>Get ID Token</b> button
to see your
ID token information.
</p>
<button id="getIDToken">Get ID Token</button>
<div>
<span id="userInfo"></span>
</div>
</body>
2. Replace the entire contents of the file with the following code.
JavaScript
(function () {
"use strict";
The add-in will display the name, email, and ID of the account you signed in with.
7 Note
If you encounter any errors, review the registration steps in this article for the app
registration. Missing a detail when setting up the app registration is a common
cause of issues working with SSO. If you still can't get the add-in to run
successfully, see Troubleshoot error messages for single sign-on (SSO).
See also
Using claims to reliably identify a user (Subject and Object ID)
Authorize to Microsoft Graph with SSO
Article • 08/14/2023
Users sign in to Office using either their personal Microsoft account or their Microsoft
365 Education or work account. The best way for an Office Add-in to get authorized
access to Microsoft Graph is to use the credentials from the user's Office sign on. This
enables them to access their Microsoft Graph data without needing to sign in a second
time.
Add-in calls
1 getAccessToken() Office host requests
access token
Microso iden ty
Office host returns pla orm returns
access token A SAML token access token A
A
SAML token
A
Request access
Add-in passes access
token A to web server API SAML token
6 token for
A Microso Graph
A
Return access
token B 7
SAML token
B
Return data 9
Return data 10
1. The client-side code of the add-in calls the Office.js API getAccessToken. This tells
the Office host to obtain an access token for the add-in.
If the user is not signed in, the Office host in conjunction with the Microsoft
identity platform provides UI for the user to sign in and consent.
2. The Office host request an access token from the Microsoft identity platform.
3. The Microsoft identity platform returns access token A to the Office host. Access
token A only provides access to the add-in's own server-side APIs. It does not
provide access to Microsoft Graph.
4. The Office host returns access token A to the add-in's client-side code. Now the
client-side code can make authenticated calls to the server-side APIs.
5. The client-side code makes an HTTP request to a web API on the server-side that
requires authentication. It includes access token A as authorization proof. Server-
side code validates access token A.
6. The server-side code uses the OAuth 2.0 On-Behalf-Of flow (OBO) to request a
new access token with permissions to Microsoft Graph.
7. The Microsoft identity platform returns the new access token B with permissions to
Microsoft Graph (and a refresh token, if the add-in requests offline_access
permission). The server can optionally cache access token B.
8. The server-side code makes a request to a Microsoft Graph API and includes
access token B with permissions to Microsoft Graph.
10. The server-side code returns the data back to the client-side code.
On subsequent requests the client code will always pass access token A when making
authenticated calls to server-side code. The server-side code can cache token B so that it
does not need to request it again on future API calls.
Depending on your language and framework, libraries might be available that will
simplify the server-side code you have to write. Your code should do the following:
Validate the access token A every time it is passed from the client-side code. For
more information, see Validate the access token.
Initiate the OAuth 2.0 On-Behalf-Of flow (OBO) with a call to the Microsoft identity
platform that includes the access token, some metadata about the user, and the
credentials of the add-in (its ID and secret). For more information about the OBO
flow, see Microsoft identity platform and OAuth 2.0 On-Behalf-Of flow.
Optionally, after the flow completes, cache the returned access token B with
permissions to Microsoft Graph. You'll want to do this if the add-in makes more
than one call to Microsoft Graph. For more information, see Acquire and cache
tokens using the Microsoft Authentication Library (MSAL)
Create one or more Web API methods that get Microsoft Graph data by passing
the (possibly cached) access token B to Microsoft Graph.
If your code passes the allowConsentPrompt option in the call of getAccessToken , like
OfficeRuntime.auth.getAccessToken( { allowConsentPrompt: true } ); , then Office can
prompt the user for consent if the Microsoft identity platform reports to Office that
consent has not yet been granted to the add-in. However, for security reasons, Office
can only prompt the user to consent to the Microsoft Graph profile scope. Office
cannot prompt for consent to other Microsoft Graph scopes, not even User.Read . This
means that if the user grants consent on the prompt, Office returns an access token. But
the attempt to exchange the access token for a new access token with additional
Microsoft Graph scopes fails with error AADSTS65001, which means consent (to
Microsoft Graph scopes) has not been granted.
7 Note
The request for consent with { allowConsentPrompt: true } could still fail even for
the profile scope if the administrator has turned off end-user consent. For more
information, see Configure how end-users consent to applications using Azure
Active Directory.
Your code can, and should, handle this error by falling back to an alternate system of
authentication, which prompts the user for consent to Microsoft Graph scopes. For code
examples, see Create a Node.js Office Add-in that uses single sign-on and Create an
ASP.NET Office Add-in that uses single sign-on and the samples they link to. The entire
process requires multiple round trips to the Microsoft identity platform. To avoid this
performance penalty, include the forMSGraphAccess option in the call of getAccessToken ;
for example, OfficeRuntime.auth.getAccessToken( { forMSGraphAccess: true } ) . This
signals to Office that your add-in needs Microsoft Graph scopes. Office will ask the
Microsoft identity platform to verify that consent to Microsoft Graph scopes has already
been granted to the add-in. If it has, the access token is returned. If it hasn't, then the
call of getAccessToken returns error 13012. Your code can handle this error by falling
back to an alternate system of authentication immediately, without making a doomed
attempt to exchange tokens with the Microsoft identity platform.
the option when you deploy for production. The bogus 13012 only happens when you
are sideloading in Outlook.
For Outlook add-ins, be sure to enable Modern Authentication for the Microsoft 365
tenancy. For information about how to do this, see Enable or disable modern
authentication for Outlook in Exchange Online.
See also
OAuth2 Token Exchange
Microsoft identity platform and OAuth 2.0 On-Behalf-Of flow
IdentityAPI requirement sets
Create an ASP.NET Office Add-in that
uses single sign-on
Article • 05/20/2023
Users can sign in to Office, and your Office Web Add-in can take advantage of this sign-
in process to authorize users to your add-in and to Microsoft Graph without requiring
users to sign in a second time. This article walks you through the process of enabling
single sign-on (SSO) in an add-in.
Client-side code that provides a task pane that loads in Microsoft Excel, Word, or
PowerPoint. The client-side code calls the Office JS API getAccessToken() to get
the SSO access token to call server-side REST APIs.
Server-side code that uses ASP.NET Core to provide a single REST API /api/files .
The server-side code uses the Microsoft Authentication Library for .NET
(MSAL.NET) for all token handling, authentication, and authorization.
The sample uses SSO and the On-Behalf-Of (OBO) flow to obtain correct access tokens
and call Microsoft Graph APIs. If you are unfamiliar with how this flow works, see How
SSO works at runtime for more detail.
Prerequisites
Visual Studio 2019 or later.
At least a few files and folders stored on OneDrive for Business in your Microsoft
365 subscription.
A build of Microsoft 365 that supports the IdentityAPI 1.3 requirement set. You can
get a free developer sandbox that provides a renewable 90-day Microsoft 365 E5
developer subscription. The developer sandbox includes a Microsoft Azure
subscription that you can use for app registrations in later steps in this article. If
you prefer, you can use a separate Microsoft Azure subscription for app
registrations. Get a trial subscription at Microsoft Azure .
7 Note
The Begin folder is a starter project. The UI and other aspects of the add-in
that are not directly connected to SSO or authorization are already done.
Later sections of this article walk you through the process of completing it.
The Complete folder contains the same sample with all coding steps from this
article completed. To use the completed version, just follow the instructions in
this article, but replace "Begin" with "Complete" and skip the sections Code
the client side and Code the server side.
Use the following values for placeholders for the subsequent app registration steps.
Placeholder Value
<add-in-name> Office-Add-in-ASPNET-SSO
<fully-qualified-domain-name> localhost:44355
1. Sign in to the Azure portal with the admin credentials to your Microsoft 365
tenancy. For example, MyName@contoso.onmicrosoft.com.
2. Select App registrations. If you don't see the icon, search for "app registration" in
the search bar.
The App registrations page appears.
6. Copy and save the values for the Application (client) ID and the Directory (tenant)
ID. You'll use both of them in later procedures.
Add a client secret
Sometimes called an application password, a client secret is a string value your app can
use in place of a certificate to identity itself.
1. From the left pane, select Certificates & secrets. Then on the Client secrets tab,
select New client secret.
Client secret lifetime is limited to two years (24 months) or less. You can't
specify a custom lifetime longer than 24 months.
Microsoft recommends that you set an expiration value of less than 12
months.
4. Select Add. The new secret is created and the value is temporarily displayed.
) Important
Record the secret's value for use in your client application code. This secret value is
never displayed again after you leave this pane.
7 Note
If you get an error saying that the domain is already owned but you own it,
follow the procedure at Quickstart: Add a custom domain name to Azure
Active Directory to register it, and then repeat this step. (This error can also
occur if you are not signed in with credentials of an admin in the Microsoft
365 tenancy. See step 2. Sign out and sign in again with admin credentials
and repeat the process from step 3.)
Add a scope
1. On the Expose an API page, select Add a scope.
2. In the Add a scope pane, specify the scope's attributes. The following table shows
example values for and Outlook add-in requiring the profile , openid ,
Files.ReadWrite , and Mail.Read permissions. Modify the text to match the
Scope The name of your scope. A For SSO this must be set to
name common scope naming access_as_user .
convention is
resource.operation.constraint .
Field Description Values
Who can Determines if admin consent is For learning SSO and samples, we
consent required or if users can consent recommend you set this to Admins and
without an admin approval. users.
The domain part of the Scope name displayed just below the text field should
automatically match the Application ID URI set in the previous step, with
/access_as_user appended to the end; for example,
api://localhost:6789/c6c1f32b-5e55-4997-881a-753cc1d563b7/access_as_user .
7 Note
5. In the Select permissions search box, search for the permissions your add-in
needs. For example, for an Outlook add-in, you might use profile , openid ,
Files.ReadWrite , and Mail.Read .
7 Note
6. Select the checkbox for each permission as it appears. Note that the permissions
will not remain visible in the list as you select each one. After selecting the
permissions that your add-in needs, select Add permissions.
7. Select Grant admin consent for [tenant name]. Select Yes for the confirmation
that appears.
3. Select Save.
A message pops up on the browser stating that the manifest was updated
successfully.
Congratulations! You've completed the app registration to enable SSO for your Office
add-in.
2. Under Common Properties, select Startup Project, and then Multiple startup
projects. Ensure that the Action for both projects is set to Start, and that the
Office-Add-in-ASPNETCoreWebAPI project is listed first. Close the dialog.
XML
<WebApplicationInfo>
<Id>Enter_client_ID_here</Id>
<Resource>api://localhost:44355/Enter_client_ID_here</Resource>
<Scopes>
<Scope>Files.Read</Scope>
<Scope>profile</Scope>
<Scope>openid</Scope>
</Scopes>
</WebApplicationInfo>
7 Note
The <Resource> value is the Application ID URI you set when you registered
the add-in. The <Scopes> section is used only to generate a consent dialog
box if the add-in is sold through AppSource.
8. Replace the placeholder Enter_client_secret_here with the client secret value you
saved previously.
7 Note
You must also change the TenantId to support single-tenant if you configured
your app registration for single-tenant. Replace the Common value with the
Application (client) ID for single-tenant support.
Get the access token and call the application server REST
API
1. In the Office-Add-in-ASPNETCore-WebAPI project, open the
wwwroot\js\HomeES6.js file. It already has code that ensures that Promises are
supported, even in the Trident (Internet Explorer 11) webview control, and an
Office.onReady call to assign a handler to the add-in's only button.
7 Note
As the name suggests, the HomeES6.js uses JavaScript ES6 syntax because
using async and await best shows the essential simplicity of the SSO API.
When the localhost server is started, this file is transpiled to ES5 syntax so that
the sample will support Trident.
2. In the getUserFileNames function, replace TODO 1 with the following code. About
this code, note:
It calls Office.auth.getAccessToken to get the access token from Office using
SSO. This token will contain the user's identity as well as access permission to
the application server.
The access token is passed to callRESTApi which makes the actual call to the
application server. The application server then uses the OBO flow to call
Microsoft Graph.
Any errors from calling getAccessToken will be handled by
handleClientSideErrors .
JavaScript
3. In the getUserFileNames function, replace TODO 2 with the following code. This will
write the list of file names to the document.
JavaScript
try {
await writeFileNamesToOfficeDocument(fileNameList);
showMessage("Your data has been added to the document.");
} catch (error) {
// The error from writeFileNamesToOfficeDocument will begin
// "Unable to add filenames to document."
showMessage(error);
}
4. In the callRESTApi function, replace TODO 3 with the following code. About this
code, note:
JavaScript
try {
let result = await $.ajax({
url: relativeUrl,
headers: { "Authorization": "Bearer " + accessToken },
type: "GET",
dataType: "json",
contentType: "application/json; charset=utf-8"
});
return result;
} catch (error) {
handleServerSideErrors(error);
}
JavaScript
switch (error.code) {
case 13001:
// No one is signed into Office. If the add-in cannot be
effectively used when no one
// is logged into Office, then the first call of
getAccessToken should pass the
// `allowSignInPrompt: true` option.
showMessage("No one is signed into Office. But you can use
many of the add-ins functions anyway. If you want to log in, press the
Get OneDrive File Names button again.");
break;
case 13002:
// The user aborted the consent prompt. If the add-in cannot
be effectively used when consent
// has not been granted, then the first call of getAccessToken
should pass the `allowConsentPrompt: true` option.
showMessage("You can use many of the add-ins functions even
though you have not granted consent. If you want to grant consent,
press the Get OneDrive File Names button again.");
break;
case 13006:
// Only seen in Office on the web.
showMessage("Office on the web is experiencing a problem.
Please sign out of Office, close the browser, and then start again.");
break;
case 13008:
// Only seen in Office on the web.
showMessage("Office is still working on the last operation.
When it completes, try this operation again.");
break;
case 13010:
// Only seen in Office on the web.
showMessage("Follow the instructions to change your browser's
zone configuration.");
break;
default:
// For all other errors, including 13000, 13003, 13005, 13007,
13012, and 50001, fall back
// to non-SSO sign-in by using MSAL authentication.
showMessage("SSO failed. In these cases you should implement a
falback to MSAL authentication.");
break;
}
JavaScript
additional claims, the user gets a prompt for all required forms of
authentication.
JavaScript
In the rare case the original SSO token is expired, it will detect this error
condition and call getUserFilenames again. This results in another call to
getAccessToken which returns a refreshed access token. The
JavaScript
It adds required services to handle token validation that is required for the
REST APIs.
It adds Microsoft Graph and OBO flow support in the call to
EnableTokenAcquisitionToCallDownstreamApi().AddMicrosoftGraph(...) . The
OBO flow is handled automatically for you, and the Microsoft Graph SDK is
provided to your REST API controllers.
The DownstreamApi configuration is specified in the appsettings.json file.
C#
.AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamApi"))
.AddInMemoryTokenCaches();
C#
[Authorize]
[Route("api/[controller]")]
[RequiredScope("access_as_user")]
public class FilesController : Controller
{
public FilesController(ITokenAcquisition tokenAcquisition,
GraphServiceClient graphServiceClient, IOptions<MicrosoftGraphOptions>
graphOptions)
{
_tokenAcquisition = tokenAcquisition;
_graphServiceClient = graphServiceClient;
_graphOptions = graphOptions;
2. Replace TODO 10 with the following code. About this code, note:
C#
// GET api/files
[HttpGet]
[Produces("application/json")]
public async Task<IActionResult> Get()
{
List<DriveItem> result = new List<DriveItem>();
try
{
var files = await
_graphServiceClient.Me.Drive.Root.Children.Request()
.Top(10)
.Select(m => new { m.Name })
.GetAsync();
result = files.ToList();
}
catch (MsalException ex)
{
var errorResponse = new
{
message = "An authentication error occurred while
acquiring a token for downstream API",
details = ex.Message
};
return StatusCode((int)HttpStatusCode.Unauthorized,
Json(errorResponse));
}
catch (ServiceException ex)
{
if (ex.InnerException is
MicrosoftIdentityWebChallengeUserException challengeException)
{
_tokenAcquisition.ReplyForbiddenWithWwwAuthenticateHeader(_graphOptions
.Value.Scopes.Split(' '),
challengeException.MsalUiRequiredException);
}
else
{
var errorResponse = new
{
message = "An error occurred calling Microsoft
Graph",
details = ex.RawResponseBody
};
return StatusCode((int)HttpStatusCode.BadRequest,
Json(errorResponse));
}
}
catch (Exception ex)
{
var errorResponse = new
{
message = "An error occurred while calling the
downstream API",
details = ex.Message
};
return StatusCode((int)HttpStatusCode.BadRequest,
Json(errorResponse));
}
return Json(result);
}
3. In the Properties pane, open the Start Document drop down and choose one of
the three options (Excel, Word, or PowerPoint).
5. In the Office application, select the Show Add-in in the SSO ASP.NET group to
open the task pane add-in.
6. Select Get OneDrive File Names. If you're logged into Office with either a
Microsoft 365 Education or work account, or a Microsoft account, and SSO is
working as expected, the first 10 file and folder names in your OneDrive for
Business are displayed on the task pane. If you are not logged in, or you are in a
scenario that does not support SSO, or SSO is not working for any reason, you will
be prompted to sign in. After you sign in, the file and folder names appear.
Deploy the add-in
When you're ready to deploy to a staging or production server, be sure to update the
following areas in the project solution.
See also
Create a Node.js Office Add-in that uses single sign-on.
Authorize to Microsoft Graph with SSO.
Create a Node.js Office Add-in that uses
single sign-on
Article • 05/20/2023
Users can sign in to Office, and your Office Web Add-in can take advantage of this sign-
in process to authorize users to your add-in and to Microsoft Graph without requiring
users to sign in a second time. For an overview, see Enable SSO in an Office Add-in.
This article walks you through the process of enabling single sign-on (SSO) in an add-in.
The sample add-in you create has two parts; a task pane that loads in Microsoft Excel,
and a middle-tier server that handles calls to Microsoft Graph for the task pane. The
middle-tier server is built with Node.js and Express and exposes a single REST API,
/getuserfilenames , that returns a list of the first 10 file names in the user's OneDrive
folder. The task pane uses the getAccessToken() method to get an access token for the
signed in user to the middle-tier server. The middle-tier server uses the On-Behalf-Of
flow (OBO) to exchange the access token for a new one with access to Microsoft Graph.
You can extend this pattern to access any Microsoft Graph data. The task pane always
calls a middle-tier REST API (passing the access token) when it needs Microsoft Graph
services. The middle-tier uses the token obtained via OBO to call Microsoft Graph
services and return the results to the task pane.
This article works with an add-in that uses Node.js and Express. For a similar article
about an ASP.NET-based add-in, see Create an ASP.NET Office Add-in that uses single
sign-on.
Prerequisites
Node.js (the latest LTS version)
At least a few files and folders stored on OneDrive for Business in your Microsoft
365 subscription
A build of Microsoft 365 that supports the IdentityAPI 1.3 requirement set. You can
get a free developer sandbox that provides a renewable 90-day Microsoft 365 E5
developer subscription. The developer sandbox includes a Microsoft Azure
subscription that you can use for app registrations in later steps in this article. If
you prefer, you can use a separate Microsoft Azure subscription for app
registrations. Get a trial subscription at Microsoft Azure .
7 Note
The Begin folder is a starter project. The UI and other aspects of the
add-in that are not directly connected to SSO or authorization are
already done. Later sections of this article walk you through the process
of completing it.
The Complete folder contains the same sample with all coding steps
from this article completed. To use the completed version, just follow the
instructions in this article, but replace "Begin" with "Complete" and skip
the sections Code the client side and Code the middle-tier server side.
3. Enter npm install in the console to install all of the dependencies itemized in the
package.json file.
4. Run the command npm run install-dev-certs . Select Yes to the prompt to install
the certificate.
Use the following values for placeholders for the subsequent app registration steps.
Placeholder Value
<add-in-name> Office-Add-in-NodeJS-SSO
<fully-qualified-domain-name> localhost:3000
1. Sign in to the Azure portal with the admin credentials to your Microsoft 365
tenancy. For example, MyName@contoso.onmicrosoft.com.
2. Select App registrations. If you don't see the icon, search for "app registration" in
the search bar.
1. From the left pane, select Certificates & secrets. Then on the Client secrets tab,
select New client secret.
4. Select Add. The new secret is created and the value is temporarily displayed.
) Important
Record the secret's value for use in your client application code. This secret value is
never displayed again after you leave this pane.
7 Note
If you get an error saying that the domain is already owned but you own it,
follow the procedure at Quickstart: Add a custom domain name to Azure
Active Directory to register it, and then repeat this step. (This error can also
occur if you are not signed in with credentials of an admin in the Microsoft
365 tenancy. See step 2. Sign out and sign in again with admin credentials
and repeat the process from step 3.)
Add a scope
1. On the Expose an API page, select Add a scope.
2. In the Add a scope pane, specify the scope's attributes. The following table shows
example values for and Outlook add-in requiring the profile , openid ,
Files.ReadWrite , and Mail.Read permissions. Modify the text to match the
Scope The name of your scope. A For SSO this must be set to
name common scope naming access_as_user .
convention is
resource.operation.constraint .
Field Description Values
Who can Determines if admin consent is For learning SSO and samples, we
consent required or if users can consent recommend you set this to Admins and
without an admin approval. users.
The domain part of the Scope name displayed just below the text field should
automatically match the Application ID URI set in the previous step, with
/access_as_user appended to the end; for example,
api://localhost:6789/c6c1f32b-5e55-4997-881a-753cc1d563b7/access_as_user .
7 Note
5. In the Select permissions search box, search for the permissions your add-in
needs. For example, for an Outlook add-in, you might use profile , openid ,
Files.ReadWrite , and Mail.Read .
7 Note
6. Select the checkbox for each permission as it appears. Note that the permissions
will not remain visible in the list as you select each one. After selecting the
permissions that your add-in needs, select Add permissions.
7. Select Grant admin consent for [tenant name]. Select Yes for the confirmation
that appears.
3. Select Save.
A message pops up on the browser stating that the manifest was updated
successfully.
Congratulations! You've completed the app registration to enable SSO for your Office
add-in.
2. Open the .ENV file and use the values that you copied earlier from the Office-Add-
in-NodeJS-SSO app registration. Set the values as follows:
Name Value
The values should not be in quotation marks. When you are done, the file should
be similar to the following:
JavaScript
CLIENT_ID=8791c036-c035-45eb-8b0b-265f43cc4824
CLIENT_SECRET=X7szTuPwKNts41:-/fa3p.p@l6zsyI/p
NODE_ENV=development
SERVER_SOURCE=<https://localhost:3000>
3. Open the add-in manifest file "manifest\manifest_local.xml" and then scroll to the
bottom of the file. Just above the </VersionOverrides> end tag, you'll find the
following markup.
XML
<WebApplicationInfo>
<Id>$app-id-guid$</Id>
<Resource>api://localhost:3000/$app-id-guid$</Resource>
<Scopes>
<Scope>Files.Read</Scope>
<Scope>profile</Scope>
<Scope>openid</Scope>
</Scopes>
</WebApplicationInfo>
4. Replace the placeholder "$app-id-guid$" in both places in the markup with the
Application ID that you copied when you created the Office-Add-in-NodeJS-SSO
app registration. The "$" symbols are not part of the ID, so don't include them. This
is the same ID you used for the CLIENT_ID in the .ENV file.
7 Note
The <Resource> value is the Application ID URI you set when you registered
the add-in. The <Scopes> section is used only to generate a consent dialog
box if the add-in is sold through AppSource.
7 Note
As the name suggests, the ssoAuthES6.js uses JavaScript ES6 syntax because
using async and await best shows the essential simplicity of the SSO API.
When the localhost server is started, this file is transpiled to ES5 syntax so that
the sample will support Trident.
2. In the getFileNameList function, replace TODO 1 with the following code. About
this code, note:
The function getFileNameList is called when the user chooses the Get
OneDrive File Names button on the task pane.
It calls the callWebServerAPI function specifying which REST API to call. This
returns JSON containing a list of file names from the user's OneDrive.
The JSON is passed to the writeFileNamesToOfficeDocument function to list
the file names in the document.
JavaScript
try {
const jsonResponse = await callWebServerAPI('GET',
'/getuserfilenames');
if (jsonResponse === null) {
// Null is returned when a message was displayed to the user
// regarding an authentication error that cannot be resolved.
return;
}
await writeFileNamesToOfficeDocument(jsonResponse);
showMessage('Your OneDrive filenames are added to the document.');
} catch (error) {
console.log(error.message);
showMessage(error.message);
}
3. In the callWebServerAPI function, replace TODO 2 with the following code. About
this code, note:
JavaScript
4. In the callWebServerAPI function, replace TODO 3 with the following code. About
this code, note:
This code handles the scenario where the SSO token expired. If so we need to
call Office.auth.getAccessToken to get a refreshed token. The simplest way is
to make a recursive call which results in a new call to
Office.auth.getAccessToken . The retryRequest parameter ensures the
JavaScript
// Check for fail condition: Is SSO token expired? If so, retry the
call which will get a refreshed token.
const jsonBody = await response.json();
if (
authSSO === true &&
jsonBody != null &&
jsonBody.type === 'TokenExpiredError'
) {
if (!retryRequest) {
return callWebServerAPI(method, path, true); // Try the call
again. The underlying call to Office JS getAccessToken will refresh the
token.
} else {
// Indicates a second call to retry and refresh the token
failed.
authSSO = false;
return callWebServerAPI(method, path, true); // Try the call
again, but now using MSAL fallback auth.
}
}
5. In the callWebServerAPI function, replace TODO 4 with the following code. About
this code, note:
The Microsoft Graph string is set by our web server whenever a Microsoft
Graph call fails.
JavaScript
// Check for fail condition: Did we get a Microsoft Graph API error,
which is returned as bad request (403)?
if (response.status === 403 && jsonBody.type === 'Microsoft Graph') {
throw new Error('Microsoft Graph error: ' + jsonBody.errorDetails);
}
JavaScript
7. In the getAccessToken function, replace TODO 6 with the following code. About this
code, note:
authSSO tracks if we are using SSO, or using MSAL fallback. If SSO is used, the
function calls Office.auth.getAccessToken and returns the token.
Errors are handled by the handleSSOErrors function which will return a token
if it switches to fallback MSAL authentication.
Fallback authentication uses the MSAL library to sign in the user. The add-in
itself is an SPA, and uses an SPA app registration to access the web server.
JavaScript
if (authSSO) {
try {
// Get the access token from Office host using SSO.
// Note that Office.auth.getAccessToken modifies the options
parameter. Create a copy of the object
// to avoid modifying the original object.
const options = JSON.parse(JSON.stringify(ssoOptions));
const token = await Office.auth.getAccessToken(options);
return token;
} catch (error) {
console.log(error.message);
return handleSSOErrors(error);
}
} else {
// Get access token through MSAL fallback.
try {
const accessToken = await getAccessTokenMSAL();
return accessToken;
} catch (error) {
console.log(error);
throw new Error(
'Cannot get access token. Both SSO and fallback auth
failed. ' +
error
);
}
}
8. In the handleSSOErrors function, replace TODO 7 with the following code. For more
information about these errors, see Troubleshoot SSO in Office Add-ins.
JavaScript
switch (error.code) {
case 13001:
// No one is signed into Office. If the add-in cannot be
effectively used when no one
// is logged into Office, then the first call of getAccessToken
should pass the
// `allowSignInPrompt: true` option. Since this sample does
that, you should not see
// this error.
showMessage(
'No one is signed into Office. But you can use many of the
add-ins functions anyway. If you want to log in, press the Get OneDrive
File Names button again.'
);
break;
case 13002:
// The user aborted the consent prompt. If the add-in cannot be
effectively used when consent
// has not been granted, then the first call of getAccessToken
should pass the `allowConsentPrompt: true` option.
showMessage(
'You can use many of the add-ins functions even though you
have not granted consent. If you want to grant consent, press the Get
OneDrive File Names button again.'
);
break;
case 13006:
// Only seen in Office on the web.
showMessage(
'Office on the web is experiencing a problem. Please sign
out of Office, close the browser, and then start again.'
);
break;
case 13008:
// Only seen in Office on the web.
showMessage(
'Office is still working on the last operation. When it
completes, try this operation again.'
);
break;
case 13010:
// Only seen in Office on the web.
showMessage(
"Follow the instructions to change your browser's zone
configuration."
);
break;
9. Replace TODO 8 with the following code. For any errors that can't be handled the
code switches to fallback authentication using MSAL.
JavaScript
API call requires an access token by the client to ensure the correct client is accessing
their data. The access token is exchanged for a Microsoft Graph token through the On-
Behalf-Of flow (OBO). The new Microsoft Graph token is cached by the MSAL library for
subsequent API calls. It's never sent outside of the web server. For more information, see
Middle-tier access token request
JavaScript
router.get(
"/getuserfilenames",
authHelper.validateJwt,
async function (req, res) {
// TODO 10: Exchange the access token for a Microsoft Graph token
// by using the OBO flow.
}
);
2. Replace TODO 10 with the following code. About this code, note:
JavaScript
try {
const authHeader = req.headers.authorization;
let oboRequest = {
oboAssertion: authHeader.split(' ')[1],
scopes: ["files.read"],
};
// The Scope claim tells you what permissions the client application
has in the service.
// In this case we look for a scope value of access_as_user, or full
access to the service as the user.
const tokenScopes = jwt.decode(oboRequest.oboAssertion).scp.split('
');
const accessAsUserScope = tokenScopes.find(
(scope) => scope === 'access_as_user'
);
if (!accessAsUserScope) {
res.status(401).send({ type: "Missing access_as_user" });
return;
}
const cca = authHelper.getConfidentialClientApplication();
const response = await cca.acquireTokenOnBehalfOf(oboRequest);
// TODO 11: Call Microsoft Graph to get list of filenames.
} catch (err) {
// TODO 12: Handle any errors.
}
3. Replace TODO 11 with the following code. About this code, note:
It constructs the URL for the Microsoft Graph API call and then makes the call
via the getGraphData function.
It returns errors by sending an HTTP 500 response along with details.
On success it returns the JSON with the filename list to the client.
JavaScript
// Minimize the data that must come from MS Graph by specifying only
the property we need ("name")
// and only the top 10 folder or file names.
const rootUrl = '/me/drive/root/children';
res.status(200).send(itemNames);
}
// TODO 12: Check for expired token.
4. Replace TODO 12 with the following code. This code specifically checks if the token
expired because the client can request a new token and call again.
JavaScript
} catch (err) {
// On rare occasions the SSO access token is unexpired when Office
validates it,
// but expires by the time it is used in the OBO flow. Microsoft
identity platform will respond
// with "The provided value for the 'assertion' is not valid. The
assertion has expired."
// Construct an error message to return to the client so it can
refresh the SSO token.
if (err.errorMessage.indexOf('AADSTS500133') !== -1) {
res.status(401).send({ type: "TokenExpiredError", errorDetails:
err });
} else {
res.status(403).send({ type: "Unknown", errorDetails: err });
}
}
The sample must handle both fallback authentication through MSAL and SSO
authentication through Office. The sample will try SSO first, and the authSSO boolean at
the top of the file tracks if the sample is using SSO or has switched to fallback auth.
5. You need to sideload the add-in into an Office application (Excel, Word, or
PowerPoint) to test it. The instructions depend on your platform. There are links to
instructions at Sideload an Office Add-in for Testing.
6. In the Office application, on the Home ribbon, select the Show Add-in button in
the SSO Node.js group to open the task pane add-in.
7. Click the Get OneDrive File Names button. If you're logged into Office with either
a Microsoft 365 Education or work account, or a Microsoft account, and SSO is
working as expected the first 10 file and folder names in your OneDrive for
Business are inserted into the document. (It may take as much as 15 seconds the
first time.) If you're not logged in, or you're in a scenario that doesn't support SSO,
or SSO isn't working for any reason, you'll be prompted to sign in. After you sign
in, the file and folder names appear.
7 Note
If you were previously signed into Office with a different ID, and some Office
applications that were open at the time are still open, Office may not reliably
change your ID even if it appears to have done so. If this happens, the call to
Microsoft Graph may fail or data from the previous ID may be returned. To prevent
this, be sure to close all other Office applications before you press Get OneDrive
File Names.
Security notes
The /getuserfilenames route in getFilesroute.js uses a literal string to compose
the call for Microsoft Graph. If you change the call so that any part of the string
comes from user input, sanitize the input so that it cannot be used in a Response
header injection attack.
In app.js the following content security policy is in place for scripts. You may want
to specify additional restrictions depending on your add-in security needs.
Always follow security best practices in the Microsoft identity platform documentation.
Troubleshoot error messages for single
sign-on (SSO)
Article • 08/14/2023
This article provides some guidance about how to troubleshoot problems with single
sign-on (SSO) in Office Add-ins, and how to make your SSO-enabled add-in robustly
handle special conditions or errors.
7 Note
The Single Sign-on API is currently supported for Word, Excel, Outlook, and
PowerPoint. For more information about where the Single Sign-on API is currently
supported, see IdentityAPI requirement sets. If you're working with an Outlook
add-in, be sure to enable Modern Authentication for the Microsoft 365 tenancy. For
information about how to do this, see Enable or disable modern authentication
for Outlook in Exchange Online.
Debugging tools
We strongly recommend that you use a tool that can intercept and display the HTTP
Requests from, and Responses to, your add-in's web service when you are developing.
Two of the most popular are:
HomeES6.js in Office-Add-in-ASPNET-SSO
ssoAuthES6.js in Office-Add-in-NodeJS-SSO
13000
The getAccessToken API is not supported by the add-in or the Office version.
The version of Office does not support SSO. The required version is Microsoft 365
subscription, in any monthly channel.
The add-in manifest is missing the proper WebApplicationInfo section.
Your add-in should respond to this error by falling back to an alternate system of user
authentication. For more information, see Requirements and Best Practices.
13001
The user is not signed into Office. In most scenarios, you should prevent this error from
ever being seen by passing the option allowSignInPrompt: true in the AuthOptions
parameter.
But there may be exceptions. For example, you want the add-in to open with features
that require a logged in user; but only if the user is already logged into Office. If the user
is not, you want the add-in to open with an alternate set of features that do not require
that the user is signed in. In this case, logic which runs when the add-in launches calls
getAccessToken without allowSignInPrompt: true . Use the 13001 error as the flag to tell
This error is never seen in Office on the web. If the user's cookie expires, Office on the
web returns error 13006.
13002
The user aborted sign in or consent; for example, by choosing Cancel on the consent
dialog.
If your add-in provides functions that don't require the user to be signed in (or to
have granted consent), then your code should catch this error and allow the add-in
to stay running.
If the add-in requires a signed-in user who has granted consent, your code should
have a sign-in button appear.
13003
User Type not supported. The user isn't signed into Office with a valid Microsoft account
or Microsoft 365 Education or work account. This may happen if Office runs with an on-
premises domain account, for example. Your code should fall back to an alternate
system of user authentication. In Outlook, this error may also occur if modern
authentication is disabled for the user's tenant in Exchange Online. For more
information, see Requirements and Best Practices.
13004
Invalid Resource. (This error should only be seen in development.) The add-in manifest
hasn't been configured correctly. Update the manifest. For more information, see
Validate an Office Add-in's manifest. The most common problem is that the <Resource>
element (in the <WebApplicationInfo> element) has a domain that does not match the
domain of the add-in. Although the protocol part of the Resource value should be "api"
not "https"; all other parts of the domain name (including port, if any) should be the
same as for the add-in.
13005
Invalid Grant. This usually means that Office has not been pre-authorized to the add-in's
web service. For more information, see Create the service application and Register the
add-in with Azure AD v2.0 endpoint. This also may happen if the user has not granted
your service application permissions to their profile , or has revoked consent. Your code
should fall back to an alternate system of user authentication.
Another possible cause, during development, is that your add-in using Internet Explorer,
and you are using a self-signed certificate. (To determine which browser or webview is
being used by the add-in, see Browsers and webview controls used by Office Add-ins.)
13006
Client Error. This error is only seen in Office on the web. Your code should suggest that
the user sign out and then restart the Office browser session.
13007
The Office application was unable to get an access token to the add-in's web service.
If this error occurs during development, be sure that your add-in registration and
add-in manifest specify the profile permission (and the openid permission, if you
are using MSAL.NET). For more information, see Register the add-in with Azure AD
v2.0 endpoint.
In production, an account mismatch could cause this error. For example, if the user
attempts to sign in with a personal Microsoft account (MSA) when a Work or
school account was expected. For these cases, your code should fall back to an
alternate system of user authentication. For more information on account types,
see Identity and account types for single- and multi-tenant apps
13008
The user triggered an operation that calls getAccessToken before a previous call of
getAccessToken completed. This error is only seen on Office on the web. Your code
should ask the user to repeat the operation after the previous operation has completed.
13010
The user is running the add-in in Office on Microsoft Edge. The user's Microsoft 365
domain, and the login.microsoftonline.com domain, are in a different security zones in
the browser settings. This error is only seen on Office on the web. If this error is
returned, the user will have already seen an error explaining this and linking to a page
about how to change the zone configuration. If your add-in provides functions that
don't require the user to be signed in, then your code should catch this error and allow
the add-in to stay running.
13012
There are several possible causes.
The add-in is running on a platform that does not support the getAccessToken API.
For example, it is not supported on iPad. See also Identity API requirement sets.
The Office document was opened from the Files tab of a Teams channel using the
Edit in Teams option on the Open dropdown menu. The getAccessToken API isn't
supported in this scenario.
The forMSGraphAccess option was passed in the call to getAccessToken and the
user obtained the add-in from AppSource. In this scenario, the tenant admin has
not granted consent to the add-in for the Microsoft Graph scopes (permissions)
that it needs. Recalling getAccessToken with the allowConsentPrompt will not solve
the problem because Office is allowed to prompt the user for consent to only the
AAD profile scope.
50001
This error (which is not specific to getAccessToken ) may indicate that the browser has
cached an old copy of the office.js files. When you are developing, clear the browser's
cache. Another possibility is that the version of Office is not recent enough to support
SSO. On Windows, the minimum version is 16.0.12215.20006. On Mac, it is
16.32.19102902.
In a production add-in, the add-in should respond to this error by falling back to an
alternate system of user authentication. For more information, see Requirements and
Best Practices.
Office-Add-in-ASPNET-SSO
Office-Add-in-NodeJS-SSO
Regardless of your architecture, if the claims value has been sent from AAD, your code
should recall getAccessToken and pass the option authChallenge: CLAIMS-STRING-HERE in
the options parameter. When AAD sees this string, it prompts the user for the
additional factor(s) and then returns a new access token which will be accepted in the
on-behalf-of flow.
If the add-in needs Microsoft Graph scopes that can only be consented to by an admin,
your code should throw an error. If the only scopes that are needed can be consented to
by the user, then your code should fall back to an alternate system of user
authentication.
Your server-side code should send a 403 Forbidden response to the client which
should log the error to the console or record it in a log.
Be sure your add-in manifest Scopes section specifies all needed permissions. And
be sure your registration of the add-in's web service specifies the same
permissions. Check for spelling mistakes too. For more information, see Register
the add-in with Azure AD v2.0 endpoint.
Always use the Office dialog API to authenticate and authorize users with your Office
Add-in. You must also use the Office dialog API if you're implementing fallback
authentication when single sign-on (SSO) cannot be used.
Office Add-ins run in an iframe when opened in Office on the web. Many identity
authorities, also called Secure Token Services (STS), prevent their sign-in page from
opening in an iframe. These include Google, Facebook, and services protected by the
Microsoft identity platform (formerly Azure AD V 2.0) such as a Microsoft account, a
Microsoft 365 Education or work account, or other common account. Also security
features implemented in the webview when Office Add-ins run in Office on Windows, or
Office on Mac can prevent sign-in pages from working correctly.
For authorization to work correctly, the sign-in page must open in a separate browser or
webview control instance. This is why Office provides the Office dialog API, specifically
the displayDialogAsync method.
7 Note
This article assumes that you're familiar with Use the Office dialog API in your
Office Add-ins.
For brevity hereafter, this article uses "browser instance" to mean "browser or
webview instance".
The dialog box that is opened with this API has the following characteristics.
It is nonmodal .
It is a completely separate browser instance from the task pane, meaning:
It has its own runtime environment and window object and global variables.
There is no shared execution environment with the task pane.
It does not share the same session storage (the Window.sessionStorage
property) as the task pane.
The first page opened in the dialog box must be hosted in the same domain as the
task pane, including protocol, subdomains, and port, if any.
The dialog box can send information back to the task pane by using the
messageParent method. We recommend that this method be called only from a
page that is hosted in the same domain as the task pane, including protocol,
subdomains, and port. Otherwise, there are complications in how you call the
method and process the message. For more information, see Cross-domain
messaging to the host runtime.
By default, the dialog box opens in a new web view control, not in an iframe. This
ensures that it can open the sign-in page of an identity provider. As you'll see later in
this article, the characteristics of the Office dialog box have implications for how you use
authentication or authorization libraries such as Microsoft Authentication Library (MSAL)
and Passport.
7 Note
To configure the dialog box to open in a floating iframe, pass the displayInIframe:
true option in the call to displayDialogAsync . Do not do this when you're using the
Office dialog API for sign in.
When a user invokes a function in the application that accesses the user's data in the
resource service, they are prompted to sign in to the service and then prompted to
grant the application the permissions it needs to the user's resources. The service then
redirects the sign-in window to the previously registered URL and passes the access
token. The application uses the access token to access the user's resources.
You can use the Office dialog API to manage this process by using a flow that is similar
to the one described for users to sign in. The only differences are:
If the user hasn't previously granted the application the permissions it needs, the
user is prompted to do so in the dialog box after signing in.
Your code in the dialog box window sends the access token to the host window
either by using messageParent to send the stringified access token or by storing
the access token where the host window can retrieve it (and using messageParent
to tell the host window that the token is available). The token has a time limit, but
while it lasts, the host window can use it to directly access the user's resources
without any further prompting.
Some authentication sample add-ins that use the Office dialog API for this purpose are
listed in Samples.
Closely related to this is the fact that a library will typically provide both interactive and
"silent" methods for getting a token. When you can do both the authentication and the
data calls to the resource in the same browser instance, your code calls the silent
method to obtain a token just before your code adds the token to the data call. The
silent method checks for an unexpired token in the cache and returns it, if there is one.
Otherwise, the silent method calls the interactive method which redirects to the STS's
sign-in. After sign-in completes, the interactive method returns the token, but also
caches it in memory. But when the Office dialog API is being used, the data calls to the
resource, which would call the silent method, are in the task pane's browser instance.
The library's token cache does not exist in that instance.
As an alternative, your add-in's dialog box browser instance can directly call the library's
interactive method. When that method returns a token, your code must explicitly store
the token someplace where the task pane's browser instance can retrieve it, such as
Local Storage* or a server-side database. Another option is to pass the token to the task
pane with the messageParent method. This alternative is only possible if the interactive
method stores the access token in a place where your code can read it. Sometimes a
library's interactive method is designed to store the token in a private property of an
object that is inaccessible to your code.
7 Note
* There is a bug that will effect your strategy for token handling. If the add-in is
running in Office on the web in either the Safari or Edge browser, the dialog box
and task pane do not share the same Local Storage, so it can't be used to
communicate between them.
These auth-context objects, and the methods that create them, are not usable in Office
Add-ins. Since the sign-in occurs in the Office dialog box's browser instance, the object
would have to be created there. But the data calls to the resource are in the task pane
browser instance and there is no way to get the object from one instance to another.
For example, you can't pass the object with messageParent because messageParent can
only pass string values. A JavaScript object with methods can't be reliably stringified.
How you can use libraries with the Office dialog API
In addition to, or instead of, monolithic "auth context" objects, most libraries provide
APIs at a lower level of abstraction that enable your code to create less monolithic
helper objects. For example, MSAL.NET v. 3.x.x has an API to construct a sign-in URL,
and another API that constructs an AuthResult object that contains an access token in a
property that is accessible to your code. For examples of MSAL.NET in an Office Add-in
see: Office Add-in Microsoft Graph ASP.NET and Outlook Add-in Microsoft Graph
ASP.NET . For an example of using msal.js in an add-in, see Office Add-in Microsoft
Graph React .
For more information about authentication and authorization libraries, see Microsoft
Graph: Recommended libraries and Other external services: Libraries.
Samples
Office Add-in Microsoft Graph ASP.NET : An ASP.NET based add-in (Excel, Word,
or PowerPoint) that uses the MSAL.NET library and the Authorization Code Flow to
sign in and get an access token for Microsoft Graph data.
Outlook Add-in Microsoft Graph ASP.NET : Just like the one above, but the Office
application is Outlook.
Office Add-in Microsoft Graph React : A NodeJS based add-in (Excel, Word, or
PowerPoint) that uses the msal.js library and the Implicit Flow to sign in and get an
access token for Microsoft Graph data.
See also
Authorize external services in your Office Add-in
Use the Office dialog API in your Office Add-ins
Authorization with non-Microsoft
identity providers
Article • 03/21/2023
There are many popular identity providing services, in addition to the Microsoft identity
platform, that you can use in your add-in. They give users, and applications such as your
Office Add-in, access to the users' accounts in other applications.
The industry standard framework for enabling web application access to an online
service is OAuth 2.0. In most situations, you don't need to know the details of how the
framework works to use it in your add-in. Many libraries are available that simplify the
details for you.
A fundamental idea of OAuth is that an application can be a security principal unto itself,
just like a user or a group, with its own identity and set of permissions. In the most
typical scenarios, when the user takes an action in the Office Add-in that requires the
online service, the add-in sends the service a request for a specific set of permissions to
the user's account. The service then prompts the user to grant the add-in those
permissions. After the permissions are granted, the service sends the add-in a small
encoded access token. The add-in can use the service by including the token in all its
requests to the service's APIs. But the add-in can act only within the permissions that
the user granted it. The token also expires after a specified time.
Several OAuth patterns, called flows or grant types, are designed for different scenarios.
The following two patterns are the most commonly implemented.
Implicit flow: Communication between the add-in and the online service is
implemented with client-side JavaScript. This flow is commonly used in single-
page applications (SPAs).
Authorization Code flow: Communication is server-to-server between your add-
in's web application and the online service. So, it is implemented with server-side
code.
The purpose of an OAuth flow is to secure the identity and authorization of the
application. In the Authorization Code flow, you're provided a client secret that needs to
be kept hidden. An application that has no server-side backend, such as an SPA, has no
way to protect the secret, so we recommend that you use the Implicit flow in SPAs.
You should be familiar with the pros and cons of the Implicit flow and the Authorization
Code flow. For more information about these two flows, see Authorization Code and
Implicit .
7 Note
You also have the option of using a middleman service to perform authorization
and pass the access token to your add-in. For details about this scenario, see the
Middleman services section later in this article.
For information about libraries that support the Implicit flow, see the Libraries section
later in this article.
Libraries
Libraries are available for many languages and platforms, for both the Implicit flow and
the Authorization Code flow. Some libraries are general purpose, while others are for
specific online services.
General OAuth 2.0: A page of links to libraries for over a dozen languages is maintained
by the IETF OAuth Working Group at: OAuth Code . Note that some of these libraries
are for implementing an OAuth compliant service. The libraries of interest to you as a an
add-in developer are called client libraries on this page because your web server is a
client of the OAuth compliant service.
Middleman services
Your add-in can use a middleman service such as OAuth.io or Auth0 to perform
authorization. A middleman service may either provide access tokens for popular online
services or simplify the process of enabling social login for your add-in, or both. With
very little code, your add-in can use either client-side script or server-side code to
connect to the middleman service and it will send your add-in any required tokens for
the online service. All of the authorization implementation code is in the middleman
service.
What is CORS?
CORS stands for Cross Origin Resource Sharing . For information about how to use
CORS inside add-ins, see Addressing same-origin policy limitations in Office Add-ins.
See also
Overview of authentication and authorization in Office Add-ins.
Authorize to Microsoft Graph from an
Office Add-in
Article • 06/23/2023
Your add-in can get authorization to Microsoft Graph data by obtaining an access token
to Microsoft Graph from the Microsoft identity platform. Use either the Authorization
Code flow or the Implicit flow just as you would in other web applications but with one
exception: The Microsoft identity platform doesn't allow its sign-in page to open in an
iframe. When an Office Add-in is running in Office on the web, the task pane is an iframe.
This means you'll need to open the sign-in page in a dialog box by using the Office
dialog API. This affects how you use authentication and authorization helper libraries.
For more information, see Authentication with the Office dialog API.
7 Note
If you're implementing SSO and plan to access Microsoft Graph, see Authorize to
Microsoft Graph with SSO.
After your code obtains the access token to Microsoft Graph, either it passes the access
token from the dialog box to the task pane, or it stores the token in a database and
signals the task pane that the token is available. (See Authentication with the Office
dialog API for details.) Code in the task pane requests data from Microsoft Graph and
includes the token in those requests. For more information about calling Microsoft
Graph and the Microsoft Graph SDKs, see Microsoft Graph documentation.
For add-ins using a server-side with a .NET-based framework such as .NET Core or
ASP.NET, use MSAL.NET .
For add-ins using a NodeJS-based server-side, use Passport Azure AD .
For add-ins using the Implicit flow, use msal.js .
For more information about recommended libraries for working with Microsoft Identity
Platform (formerly AAD v.2.0), see Microsoft identity platform authentication libraries.
The following samples get Microsoft Graph data from an Office Add-in.
Office Add-ins extend the Office experience by providing contextual functionality that
users can access within Office clients. Add-ins empower users to get more done by
enabling them to access external functionality within Office, without costly context
switches.
Your add-in UI design must integrate seamlessly with Office to provide an efficient,
natural interaction for your users. Take advantage of add-in commands to provide
access to your add-in and apply the best practices that we recommend when you create
a custom HTML-based UI.
Design explicitly for Office. The functionality, as well as the look and feel, of an
add-in must harmoniously complement the Office experience. Add-ins should feel
native. They should fit seamlessly into Word on an iPad or PowerPoint on the web.
A well-designed add-in will be an appropriate blend of your experience, the
platform, and the Office application. Apply document and UI theming where
appropriate. Consider using Fluent UI for the web as your design language and
tool set. The Fluent UI for the web has two flavors.
For non-React UIs: Use Fabric Core, an open-source collection of CSS classes
and Sass mixins that give you access to colors, animations, fonts, icons, and
grids. (It's called "Fabric Core" instead of "Fluent Core" for historical reasons.) To
get started, see Fabric Core in Office Add-ins.
7 Note
For React UIs: use Fluent UI React, a React front-end framework designed to
build experiences that fit seamlessly into a broad range of Microsoft products. It
provides robust, up-to-date, accessible React-based components which are
highly customizable using CSS-in-JS. To get started, see Fluent UI React in Office
Add-ins.
Make it enjoyable and keep users in control. People enjoy using products that are
both functional and visually appealing. Craft your experience carefully. Get the
details right by considering every interaction and visual detail. Allow users to
control their experience. The necessary steps to complete a task must be clear and
relevant. Important decisions should be easy to understand. Actions should be
easily reversible. An add-in is not a destination – it’s an enhancement to Office
functionality.
Design for all platforms and input methods. Add-ins are designed to work on all
the platforms that Office supports, and your add-in UX should be optimized to
work across platforms and form factors. Support mouse/keyboard and touch input
devices, and ensure that your custom HTML UI is responsive to adapt to different
form factors. For more information, see Touch.
See also
Add-in development best practices
Use Fluent UI React in Office Add-ins
Article • 07/17/2023
7 Note
This article describes the use of Fluent UI React in the context of Office Add-ins.
However, it's also used in a wide range of Microsoft 365 apps and extensions. For
more information, see Fluent UI React and the Fluent UI Web open source
repository.
This article describes how to create an add-in that's built with React and that uses Fluent
UI React components.
The latest version of Yeoman and the Yeoman generator for Office Add-ins. To
install these tools globally, run the following command via the command prompt.
command line
7 Note
command line
yo office
7 Note
When you run the yo office command, you may receive prompts about the data
collection policies of Yeoman and the Office Add-in CLI tools. Use the information
that's provided to respond to the prompts as you see fit.
When prompted, provide the following information to create your add-in project.
Choose a project type: Office Add-in Task Pane project using React framework
Choose a script type: TypeScript
What do you want to name your add-in? My Office Add-in
Which Office client application would you like to support? Word
After you complete the wizard, the generator creates the project and installs supporting
Node components.
Tip
You can ignore the next steps guidance that the Yeoman generator provides after
the add-in project's been created. The step-by-step instructions within this article
provide all of the guidance you'll need to complete this tutorial.
Try it out
1. Navigate to the root folder of the project.
command line
2. Complete the following steps to start the local web server and sideload your add-
in.
7 Note
Office Add-ins should use HTTPS, not HTTP, even while you're developing. If
you're prompted to install a certificate after you run one of the following
commands, accept the prompt to install the certificate that the Yeoman
generator provides. You may also have to run your command prompt or
terminal as an administrator for the changes to be made.
Tip
If you're testing your add-in on Mac, run the following command before
proceeding. When you run this command, the local web server starts.
command line
To test your add-in in Word, run the following command in the root directory
of your project. This starts the local web server and opens Word with your
add-in loaded.
command line
npm start
To test your add-in in Word on a browser, run the following command in the
root directory of your project. When you run this command, the local web
server starts. Replace "{url}" with the URL of a Word document on your
OneDrive or a SharePoint library to which you have permissions.
7 Note
command line
https://contoso.sharepoint.com/:t:/g/EZGxP7ksiE5DuxvY638G798BpuhwluxCM
fF1WZQj3VYhYQ?e=F4QM1R
df.com/:t:/p/user/EQda453DNTpFnl1bFPhOVR0BwlrzetbXvnaRYii2lDr_oQ?
e=RSccmNP
3. To open the add-in task pane, on the Home tab, select the Show Taskpane button.
Notice the default text and the Run button at the bottom of the task pane. In the
remainder of this walkthrough, you'll redefine this text and button by creating a
React component that uses Fluent UI React components.
Install Fluent UI React as a dependency
Before you can create React components, you must first install Fluent UI React as a
dependency in your add-in project. To do so, run the following code in the root
directory of your add-in project.
command line
Complete the following steps to add the FluentProvider component to your add-in
project and configure it to apply the Web Light theme.
1. Open your add-in project in a code editor, navigate to ./src/taskpane, then open
the index.tsx file.
2. Replace the contents of the file with the following code.
TypeScript
if ((module as any).hot) {
(module as any).hot.accept("./components/App", () => {
const NextApp = require("./components/App").default;
render(NextApp);
});
}
TypeScript
/* global Word */
TypeScript
3. Remove the following import statements, as they aren't used in this sample.
TypeScript
4. Replace the default render() function with the following code that uses the
ButtonExample component.
TypeScript
render() {
return (
<div className="ms-welcome">
<Header logo="assets/logo-filled.png" title={this.props.title}
message="Welcome" />
<HeroList message="Discover what this add-in can do for you
today!" items={this.state.listItems} >
<ButtonExample />
</HeroList>
</div>
);
}
5. Save your changes.
Congratulations, you've successfully created a task pane add-in using React and Fluent
UI React!
See also
Fabric Core in Office Add-ins
UX design patterns for Office Add-ins
Fluent UI GitHub repository
Fabric Core in Office Add-ins
Article • 04/04/2023
Fabric Core is an open-source collection of CSS classes and Sass mixins that's intended
for use in non-React Office Add-ins. Fabric Core contains basic elements of the Fluent UI
design language such as icons, colors, typefaces, and grids. Fabric Core is framework
independent, so it can be used with any single-page application or any server-side web
UI framework. (It's called "Fabric Core" instead of "Fluent Core" for historical reasons.)
If your add-in's UI isn't React-based, you can also make use of a set of non-React
components. See Use Office UI Fabric JS components.
7 Note
This article describes the use of Fabric Core in the context of Office Add-ins, but it's
also used in a wide range of Microsoft 365 apps and extensions. For more
information, see Fabric Core and the open source repo Office UI Fabric Core .
7 Note
While Fabric Core is the recommended library to design non-React add-ins, the
team is working on Fluent UI Web Components to provide a newer solution. Built
on FAST , the Fluent UI Web Components library allows you to use, customize,
and build Web Components to create a more modern and standards-based UI. We
invite you to test this library by completing the quick start and welcome feedback
on your experience through GitHub .
HTML
<link rel="stylesheet"
href="https://static2.sharepointonline.com/files/fabric/office-ui-
fabric-core/9.6.1/css/fabric.min.css">
HTML
For more detailed instructions, see Fluent UI Icons. To find more icons that are
available in Fabric Core, use the search feature on that page. When you find an
icon to use in your add-in, be sure to prefix the icon name with ms-Icon-- .
For information about font sizes and colors that are available in Fabric Core, see
Typography and the Colors table of contents at Colors.
Samples
The following sample add-ins use Fabric Core and/or Office UI Fabric JS components.
Some of these repos are archived, meaning that they are no longer being updated with
bug or security fixes, but you can still use them to learn how to use Fabric Core and
Fabric UI components.
As you design and develop your Office Add-ins, you'll want to ensure that all potential
users and customers are able to use your add-in successfully. Apply the following
guidelines to ensure that your solution is accessible to all audiences.
See also
Web Content Accessibility Guidelines (WCAG) 2.0
Guidance on Applying WCAG 2.0 to Non-Web Information and Communications
Technologies (WCAG2ICT)
European Standard on accessibility requirements for Information and
Communication Technologies (ICT)
Data visualization style guidelines for
Office Add-ins
Article • 06/29/2023
Good data visualizations help users find insights in their data. They can use those
insights to tell stories that inform and persuade. This article provides guidelines to help
you design effective data visualizations in your add-ins for Excel and other Office apps.
We recommend that you use Fluent UI to create the chrome for your data visualizations.
Fluent UI includes styles and components that integrate seamlessly with the Office look
and feel.
Chart titles
Follow these guidelines for chart titles.
Make your chart titles easily readable. Position them to create a clear visual
hierarchy in relation to the rest of the chart.
In general, use sentence capitalization (capitalize the first word). To create contrast
or to reinforce hierarchies, you can use all caps, but all caps should be used
sparingly.
Incorporate the Fluent UI type ramp to make your charts consistent with the Office
UI, which uses Segoe. You can also use a different typeface to differentiate chart
content from the UI.
Fluent UI React typography styles
Fabric Core typography styles
Axis labels
Make your axis labels dark enough to read clearly, with adequate contrast ratios
between the text and background colors. Make sure that they are not so dark that they
compete with data ink.
Light grays are most effective for axis labels. Explore the following Fluent UI neutral
color palettes.
Data ink
The pixels that represent the actual data in a chart are referred to as data ink. This
should be the central focus of the visualization. Avoid the use of drop shadows, heavy
outlines, or unnecessary design elements that distort or compete with the data. Use
gradients only when data values are tied to color values. Avoid three-dimensional charts
unless a measurable, objective value is bound to a third dimension.
Color
Choose colors that follow operating system or application themes rather than
hardcoded colors. At the same time, make sure that the colors you apply don't distort
the data. Misuse of color in data visualizations can result in data distortion and incorrect
reading of information.
For best practices for use of color in data visualizations, see the following:
Why rainbow colors aren't the best option for data visualizations
Color Brewer 2.0: Color Advice for Cartography
I Want Hue
Gridlines
Gridlines are often necessary for accurately reading a chart, but should be presented as
a secondary visual element, enhancing the data ink, not competing with it. Make static
gridlines thin and light, unless they are designed specifically for high contrast. You can
also use interaction to create dynamic, just-in-time gridlines that appear in context
when a user interacts with a chart.
Light grays are most effective for gridlines. Explore the following Fluent UI neutral color
palettes.
Legends
Add legends if necessary to:
Make sure that your legends enhance the data ink and don't compete with it. Place
legends:
Flush left above the plot area by default, if all legend items fit above the chart.
On the upper right side of the plot area, if all legend items don't fit above the
chart, and make it scrollable, if necessary.
To optimize for readability and accessibility, map legend markers to the relevant chart
shape. For example, use circle legend markers for scatter plot and bubble chart legends.
Use line segment legend markers for line charts.
Design principles
The Office Design team created the following set of design principles, which we use
when designing new data visualizations for the Office product suite.
For more information about how to design user-friendly interactive data visualizations,
see UI Tenets and Traps .
Motion design principles
Motion follows stimulus. Visual elements should move in the same direction at the same
rate. This applies to:
Chart creation
Transition from one chart type to another chart type
Filtering
Sorting
Adding or subtracting data
Brushing or slicing data
Resizing a chart
See also
The Five Best Libraries for Building Data Visualizations
The Visual Display of Quantitative Information
Voice and tone guidelines
Article • 05/18/2023
As you design your Office Add-ins, consider the voice that you use in your UI text and
elements. Strive to match the voice and tone of the Office UI, which is conversational,
engaging, and accessible to users.
Use a natural style. Write the way that you speak. Avoid jargon and overly
technical words and phrases. Use terms that are familiar to your users.
Use simple, direct language. Use short words and sentences, and active voice in
your text.
Be consistent. Use the same words for the same concepts throughout.
Engage the user. Address the user as "you". Avoid using third person. Use
imperatives for user tasks.
Be helpful and empathetic. Make your text positive, polite, supportive, and
encouraging. Emphasize what users can accomplish ― not what they can't.
Know your customers. Be mindful of cultural considerations and globalization
when you use idioms or colloquialisms.
See also
Guidelines for writing for all abilities
Top 10 tips for Microsoft style and voice
Guidelines on word choice
Office Add-in validation policies
Office Add-in design language
Article • 04/04/2023
The Office design language is a clean and simple visual system that ensures consistency
across experiences. It contains a set of visual elements that define Office interfaces,
including:
A standard typeface
A common color palette
A set of typographic sizes and weights
Icon guidelines
Shared icon assets
Animation definitions
Common components
Fluent UI is the official front-end framework for building with the Office design
language. Using Fluent UI is optional, but it is the fastest way to ensure that your add-
ins feel like a natural extension of Office. Take advantage of Fluent UI to design and
build add-ins that complement Office.
Many Office Add-ins are associated with a preexisting brand. You can retain a strong
brand and its visual or component language in your add-in. Look for opportunities to
retain your own visual language while integrating with Office. Consider ways to swap
out Office colors, typography, icons, or other stylistic elements with elements of your
own brand. Consider ways to follow common add-in layouts or UX design patterns while
inserting controls and components that are familiar to your customers.
Inserting a heavily branded HTML-based UI inside of Office can create dissonance for
customers. Find a balance that fits seamlessly in Office but also clearly aligns with your
service or parent brand. When an add-in does not fit with Office, it's often because
stylistic elements conflict. For example, typography is too large and off grid, colors are
contrasting or particularly loud, or animations are superfluous and behave differently
than Office. The appearance and behavior of controls or components veer too far from
Office standards.
Color guidelines for Office Add-ins
Article • 04/04/2023
Color is often used to emphasize brand and reinforce visual hierarchy. It helps identify
an interface as well as guide customers through an experience. Inside Office, color is
used for the same goals but it is applied purposefully and minimally. At no point does it
overwhelm customer content. Even when each Office app is branded with its own
dominant color, it is used sparingly.
Fabric Core includes a set of default theme colors. When Fabric Core is applied to an
Office Add-in in components or in layouts, the same goals apply. Color should
communicate hierarchy, purposefully guiding customers to action without interfering
with content. Fabric Core theme colors can introduce a new accent color to the overall
interface. This new accent can conflict with Office app branding and interfere with
hierarchy. In other words, Fabric Core can introduce a new accent color to the overall
interface when used inside an add-in. This new accent color can distract and interfere
with the overall hierarchy. Consider ways to avoid conflicts and interference. Use neutral
accents or overwrite Fabric Core theme colors to match Office app branding or your
own brand colors.
For mail and task pane add-ins, use the Context.officeTheme property to
match the theme of the Office applications. This API is currently available in
Office 2016 or later.
For PowerPoint content add-ins, see Use Office themes in your PowerPoint
add-ins.
Icons are the visual representation of a behavior or concept. They are often used to add
meaning to controls and commands. Visuals, either realistic or symbolic, enable the user
to navigate the UI the same way signs help users navigate their environment. They
should be simple, clear, and contain only the necessary details to enable customers to
quickly parse what action will occur when they choose a control.
Office app ribbon interfaces have a standard visual style. This ensures consistency and
familiarity across Office apps. The guidelines will help you design a set of PNG assets for
your solution that fit in as a natural part of Office.
Many HTML containers contain controls with iconography. Use Fabric Core’s custom
font to render Office styled icons in your add-in. The icon font provided by Fabric Core
contains many glyphs for common Office metaphors that you can scale, color, and style
to suit your needs. If you have an existing visual language with your own set of icons,
feel free to use it in your HTML canvases. Building continuity with your own brand with a
standard set of icons is an important part of any design language. Be careful to avoid
creating confusion for customers by conflicting with Office metaphors.
For the Monoline style of Microsoft 365, see Monoline style icon guidelines for
Office Add-ins.
For the Fresh style of perpetual Office 2013+, see Fresh style icon guidelines for
Office Add-ins.
7 Note
You must choose one style or the other and your add-in will use the same icons
whether it is running in Microsoft 365 or perpetual Office.
See also
Add-in development best practices
Add-in commands for Excel, Word, and PowerPoint
Fresh style icon guidelines for Office
Add-ins
Article • 04/04/2023
The Office 2013+ (perpetual) versions of Office use Microsoft's Fresh style iconography.
If you would prefer that your icons match the Monoline style of Microsoft 365, see
Monoline style icon guidelines for Office Add-ins.
Best practices
Follow these guidelines when you create your icons.
Do Don't
Keep visuals simple and clear, Don't use artifacts that make your icon look messy.
focusing on the key elements
of the communication.
Use the Office icon language to Don’t repurpose Fabric Core glyphs for add-in commands in the
represent behaviors or Office app ribbon or contextual menus. Fabric Core icons are
concepts. stylistically different and will not match.
Reuse common Office visual Don't reuse visual metaphors for different commands. Using the
metaphors such as paintbrush same icon for different behaviors and concepts can cause
for format or magnifying glass confusion.
for find.
Redraw your icons to make Don't resize your icons by shrinking or enlarging in size. This
them small or larger. Take the can lead to poor visual quality and unclear actions. Complex
time to redraw cutouts, icons created at a larger size may lose clarity if resized to be
corners, and rounded edges to smaller without redraw.
maximize line clarity.
Do Don't
Use a white fill for accessibility. Avoid relying on your logo or brand to communicate what an
Most objects in your icons will add-in command does. Brand marks aren't always recognizable
require a white background to at smaller icon sizes and when modifiers are applied. Brand
be legible across Office UI marks often conflict with Office app ribbon icon styles, and can
themes and in high-contrast compete for user attention in a saturated environment.
modes.
16 px (Required)
20 px
24 px
32 px (Required)
40 px
48 px
64 px (Recommended, best for Mac)
80 px (Required)
) Important
For an image that is your add-in's representative icon, see Create effective listings
in AppSource and within Office for size and other requirements.
Make sure to redraw your icons for each size rather than shrink them to fit.
Icon anatomy and layout
Office icons are typically comprised of a base element with action and conceptual
modifiers overlaid. Action modifiers represent concepts such as add, open, new, or close.
Conceptual modifiers represent status, alteration, or a description of the icon.
To create commands that align with the Office UI, follow layout guidelines for the base
element and modifiers. This ensures that your commands look professional and that
your customers will trust your add-in. If you make exceptions to these guidelines, do so
intentionally.
The following image shows the layout of base elements and modifiers in an Office icon.
Center base elements in the pixel frame with empty padding all around.
Place action modifiers on the top left.
Place conceptual modifiers on the bottom right.
Limit the number of elements in your icons. At 32 px, limit the number of modifiers
to a maximum of two. At 16 px, limit the number of modifiers to one.
Base element padding
Place base elements consistently across sizes. If base elements can't be centered in the
frame, align them to the top left, leaving the extra pixels on the bottom right. For best
results, apply the padding guidelines listed in the table in the following section.
Modifiers
All modifiers should have a 1 px transparent cutout between each element, including
the background. Elements should not directly overlap. Create whitespace between rules
and edges. Modifiers can vary slightly in size, but use these dimensions as a starting
point.
16 px 0 9 px
20 px 1px 10 px
24 px 1px 12 px
32 px 2px 14 px
40 px 2px 20 px
48 px 3px 22 px
64 px 5px 29 px
80 px 5px 38 px
Icon colors
7 Note
These color guidelines are for ribbon icons used in Add-in commands. These icons
are not rendered with Fluent UI and the color palette is different from the palette
described at Microsoft UI Fabric | Colors | Shared .
Office icons have a limited color palette. Use the colors listed in the following table to
guarantee seamless integration with the Office UI. Apply the following guidelines to the
use of color.
Use color to communicate meaning rather than for embellishment. It should
highlight or emphasize an action, status, or an element that explicitly differentiates
the mark.
If possible, use only one additional color beyond gray. Limit additional colors to
two at the most.
Colors should have a consistent appearance in all icon sizes. Office icons have
slightly different color palettes for different icon sizes. 16 px and smaller icons are
slightly darker and more vibrant than 32 px and larger icons. Without these subtle
adjustments, colors appear to vary across sizes.
Aim to differentiate foreground and background elements along the 190 value
threshold.
Follow Office icon visual styles.
Use colors from our icon palette.
Avoid the use of gradients.
Avoid large blocks of color with similar values.
See also
Icon manifest element
IconUrl manifest element
HighResolutionIconUrl manifest element
Create an icon for your add-in
Monoline style icon guidelines for
Office Add-ins
Article • 04/04/2023
Monoline style iconography are used in Office apps. If you would prefer that your icons
match the Fresh style of perpetual Office 2013+, see Fresh style icon guidelines for
Office Add-ins.
The following guidelines are for 3rd party developers who want to create icons for
features that will be consistent with the icons already present Office products.
Design principles
Simple, clean, clear.
Contain only necessary elements.
Inspired by Windows icon style.
Accessible to all users.
Convey meaning
Reduction of elements
Reduce the icon to its core meaning, using only elements that are essential to the
metaphor.
Limit the number of elements in an icon to two, regardless of icon size.
Consistency
Sizes, arrangement, and color of icons should be consistent.
Styling
Perspective
Monoline icons are forward-facing by default. Certain elements that require perspective
and/or rotation, such as a cube, are allowed, but exceptions should be kept to a
minimum.
Embellishment
Monoline is a clean minimal style. Everything uses flat color, which means there are no
gradients, textures, or light sources.
Designing
Sizes
We recommend that you produce each icon in all these sizes to support high DPI
devices. The absolutely required sizes are 16 px, 20 px, and 32 px, as those are the 100%
sizes.
) Important
For an image that is your add-in's representative icon, see Create effective listings
in AppSource and within Office for size and other requirements.
Layout
The following is an example of icon layout with a modifier.
Elements
Base: The main concept that the icon represents. This is usually the only visual
needed for the icon, but sometimes the main concept can be enhanced with a
secondary element, a modifier.
Modifier Any element that overlays the base; that is, a modifier that typically
represents an action or a status. It modifies the base element by acting as an
addition, alteration, or a descriptor.
Construction
Element placement
Base elements are placed in the center of the icon within the padding. If it can't be
placed perfectly centered, then the base should err to the top right. In the following
example, the icon is perfectly centered.
In the following example, the icon is erring to the left.
Modifiers are almost always placed in the bottom right corner of the icon canvas. In
some rare cases, modifiers are placed in a different corner. For example, if the base
element would be unrecognizable with the modifier in the bottom right corner, then
consider placing it in the upper left corner.
Padding
Each size icon has a specified amount of padding around the icon. The base element
stays within the padding, but the modifier should butt up to the edge of the canvas,
extending outside of the padding to the edge of the icon border. The following images
show the recommended padding to use for each of the icon sizes.
Line weights
Monoline is a style dominated by line and outlined shapes. Depending on what size you
are producing the icon should use the following line weights.
Icon Size: 16px 20px 24px 32px 40px 48px 64px 80px 96px
Line 1px 1px 1px 1px 2px 2px 2px 2px 3px
Weight:
Icon Size: 16px 20px 24px 32px 40px 48px 64px 80px 96px
Example
icon:
Cutouts
When an icon element is placed on top of another element, a cutout (of the bottom
element) is used to provide space between the two elements, mainly for readability
purposes. This usually happens when a modifier is placed on top of a base element, but
there are also cases where neither of the elements is a modifier. These cutouts between
the two elements is sometimes referred to as a "gap".
The size of the gap should be the same width as the line weight used on that size. If
making a 16 px icon, the gap width would be 1px and if it is a 48 px icon then the gap
should be 2px. The following example shows a 32 px icon with a gap of 1px between the
modifier and the underlying base.
In some cases, the gap can be increase by a 1/2 px if the modifier has a diagonal or
curved edge and the standard gap doesn't provide enough separation. This will likely
only affect the icons with 1px line weight: 16 px, 20 px, 24 px, and 32 px.
Background fills
Most icons in the Monoline icon set require background fills. However, there are cases
where the object would not naturally have a fill, so no fill should be applied. The
following icons have a white fill.
The following icons have no fill. (The gear icon is included to show that the center hole
is not filled.)
Dos
Fill any element that has a defined boundary, and would naturally have a fill.
Use a separate shape to create the background fill.
Use Background Fill from the color palette.
Maintain the pixel separation between overlapping elements.
Fill between multiple objects.
Don'ts
Don't fill objects that would not naturally be filled; for example, a paperclip.
Don't fill brackets.
Don't fill behind numbers or alpha characters.
Color
The color palette has been designed for simplicity and accessibility. It contains 4 neutral
colors and two variations for blue, green, yellow, red, and purple. Orange is intentionally
not included in the Monoline icon color palette. Each color is intended to be used in
specific ways as outlined in this section.
Palette
How to use color
In the Monoline color palette, all colors have Standalone, Outline, and Fill variations.
Generally, elements are constructed with a fill and a border. The colors are applied in
one of the following patterns.
The most common situation will be to have an element use Dark Gray Standalone with
Background Fill.
When using a colored Fill, it should always be with its corresponding Outline color. For
example, Blue Fill should only be used with Blue Outline. But there are two exceptions to
this general rule.
You should limit your icons to one additional color, other than the Outline and Fill
mentioned above. However, more colors can be used if it is vital for its metaphor, with a
limit of two additional colors other than gray. In rare cases, there are exceptions when
more colors are needed. The following are good examples of icons that use just one
color.
Use Medium Gray for interior "content", such as grid lines in an icon of a spreadsheet.
Additional interior colors are used when the content needs to show the behavior of the
control.
Text lines
When text lines are in a "container" (for example, text on a document), use medium
gray. Text lines not in a container should be Dark Gray.
Text
Avoid using text characters in icons. Since Office products are used around the world,
we want to keep icons as language neutral as possible.
Production
See also
Icon manifest element
IconUrl manifest element
HighResolutionIconUrl manifest element
Create an icon for your add-in
Layout
Article • 04/04/2023
Each HTML container embedded in Office will have a layout. These layouts are the main
screens of your add-in. In them you will create experiences that enable customers to
initiate actions, modify settings, view, scroll, or navigate content. Design your add-in
with a consistent layouts across screens to guarantee continuity of experience. If you
have an existing website that your customers are familiar with using, consider reusing
layouts from your existing web pages. Adapt them to fit harmoniously within Office
HTML containers.
For guidelines on layout, see Task pane, Content. For more information about how to
assemble Fluent UI React, or Office UI Fabric JS, components into common layouts and
user experience flows, see UX design patterns templates.
When you design an Office Add-in, you can use motion to enhance the user experience.
UI elements, controls, and components often have interactive behaviors that require
transitions, motion, or animation. Common characteristics of motion across UI elements
define the animation aspects of a design language.
Because Office is focused on productivity, the animation language supports the goal of
helping customers get things done. It strikes a balance between performant response,
reliable choreography, and detailed delight. Office Add-ins sit within this existing
animation language. Given this context, it's important to consider the following
guidelines when applying motion.
Standard elements used in an add-in can incorporate motion to help focus the user,
show how elements relate to each other, and validate user actions. Choreograph
elements to reinforce hierarchy and mental models.
Best practices
Do Don't
Identify key elements in the add-in that should Don't overwhelm the user by animating
have motion. Commonly animated elements in an every element. Avoid applying multiple
add-in are panels, overlays, modals, tool tips, motions that attempt to lead or focus the
menus, and teaching call outs. user on many elements at once.
Use simple, subtle motion that behaves in Don't create wait time for a motion. Motion
expected ways. Consider the origin of your in add-ins should not hinder task
triggering element. Use motion to create a link completion.
between the action and the resulting UI.
Use expected motions
We recommend using Fluent UI to create a visual connection with the Office platform.
Use it to fit seamlessly in your add-in. It will help you create experiences that are more
felt than observed. The animation CSS classes provide directionality, enter/exit, and
duration specifics that reinforce Office mental models and provide opportunities for
customers to learn how to interact with your add-in.
Best practices
Do Don't
Use motion that aligns with behaviors in Fluent UI. Don't create motions that interfere or
conflict with common motion patterns
in Office.
Ensure that there is a consistent application of motion Don't use different motions to
across like elements. animate the same component or
object.
Create consistency with use of direction in animation. Don't animate an element using
For example, a panel that opens from the right should multiple directions.
close to the right.
Avoid out of character motion for an element
Consider the size of the HTML canvas (task pane, dialog box, or content add-in) when
implementing motion. Avoid overloading in constrained spaces. Moving elements
should be in tune with Office. The character of add-in motion should be performant,
reliable, and fluid. Instead of impeding productivity, aim to inform and direct.
Best practices
Do Don't
Use Don't use exaggerated animations. Avoid creating experiences that embellish
recommended and distract your customers.
motion durations.
Segoe is the standard typeface for Office. Use it in your add-in to align with Office task
panes, dialog boxes, and content objects. Fabric Core gives you access to Segoe. It
provides a full type ramp of Segoe with many variations - across font weight and size -
in convenient CSS classes. Not all Fabric Core sizes and weights will look great in an
Office Add-in. To fit harmoniously or avoid conflicts, consider using a subset of the
Fabric Core type ramp. The following table lists Fabric Core's base classes that we
recommend for use in Office Add-ins.
7 Note
Text color is not included in these base classes. Use Fabric Core's "neutral primary"
for most text on white backgrounds.
Hero .ms- 28 Segoe This class is larger than all other typographic
font- px Light elements in Office. Use it sparingly to avoid
xxl unseating visual hierarchy.
Avoid use on long strings in constrained spaces.
Provide ample whitespace around text using this
class.
Commonly used for first-run messages, hero
elements, or other calls to action.
Title .ms- 21 Segoe This class matches the task pane title of Office
font- px Light applications.
xl Use it sparingly to avoid a flat typographic
hierarchy.
Commonly used as the top-level element such as
dialog box, page, or content titles.
Subtitle .ms- 17 Segoe This class is the first stop below titles.
font- px Semilight Commonly used as a subtitle, navigation element,
l or group header.
Type Class Size Weight Recommended Usage
Caption .ms- 11 Segoe Commonly used for secondary or tertiary text such
font- px Regular as timestamps, by lines, captions, or field labels.
xs
Annotation .ms- 10 Segoe The smallest step in the type ramp should be used
font- px Semibold rarely. It's available for circumstances where
mi legibility is not required.
UX design patterns for Office Add-ins
Article • 06/27/2023
Designing the user experience for Office Add-ins should provide a compelling
experience for Office users and extend the overall Office experience by fitting seamlessly
within the default Office UI.
Our UX patterns are composed of components. Components are controls that help your
customers interact with elements of your software or service. Buttons, navigation, and
menus are examples of common components that often have consistent styles and
behaviors.
Fluent UI React components look and behave like a part of Office, as do the framework-
neutral components of Office UI Fabric JS. Take advantage of either set of components
to integrate with Office. Alternatively, if your add-in has its own preexisting component
language, you don't need to discard it. Look for opportunities to retain it while
integrating with Office. Consider ways to swap out stylistic elements, remove conflicts,
or adopt styles and behaviors that remove user confusion.
The provided patterns are best practice solutions based on common customer scenarios
and user experience research. They are meant to provide both a quick entry point to
designing and developing add-ins as well as guidance to achieve balance between
Microsoft brand elements and your own. Providing a clean, modern user experience that
balances design elements from Microsoft's Fluent UI design language and the partner's
unique brand identity may help increase user retention and adoption of your add-in.
Getting started
The patterns are organized by key actions or experiences that are common in an add-in.
The main groups are:
Browse each grouping to get an idea of how you can design your add-in using best
practices.
7 Note
The example screens shown throughout this documentation are designed and
displayed at a resolution of 1366x768.
See also
Design tool kits
Best practices for developing Office Add-ins
Fluent UI React in Office Add-ins
Authentication patterns
Article • 08/15/2023
Add-ins may require users to sign-in or sign-up in order to access features and
functionality. Input boxes for username and password or buttons that start third party
credential flows are common interface controls in authentication experiences. A simple
and efficient authentication experience is an important first step to getting users started
with your add-in.
Best practices
Do Don't
Prior to sign-in, describe the value of your add-in Expect users to sign-in without
or demonstrate functionality without requiring an understanding the value and benefits of your
account. add-in.
Guide users through authentication flows with a Draw attention to secondary and tertiary
primary, highly visible button on each screen. tasks with competing buttons and calls to
action.
Use clear button labels that describe specific Use vague button labels like "Submit" or "Get
tasks like "Sign in" or "Create account". started" to guide users through
authentication flows.
Use a dialog to focus users' attention on Overcrowd your task pane with a first-run
authentication forms. experience and authentication forms.
Find small efficiencies in the flow like auto- Add unnecessary steps to the interaction like
focusing on input boxes. requiring users to click into form fields.
Provide a way for users to sign out and Force users to uninstall to switch identities.
reauthenticate.
Authentication flow
1. First-Run Placemat - Place your sign-in button as a clear call-to action inside your
add-in's first-run experience.
2. Identity Provider Choices Dialog - Display a clear list of identity providers including
a username and password form if applicable. Your add-in UI may be blocked while
the authentication dialog is open.
3. Identity Provider Sign-in - The identity provider will have their own UI. Microsoft
Azure Active Directory allows customization of sign-in and access panel pages for
consistent look and feel with your service. Learn More.
4. Progress - Indicate progress while settings and UI load.
7 Note
When using Microsoft's Identity service you'll have the opportunity to use a
branded sign-in button that is customizable to light and dark themes. Learn more.
7 Note
The single sign-on API is currently supported for Word, Excel, Outlook, and
PowerPoint. For more information about single sign-on support, see IdentityAPI
requirement sets. If you're working with an Outlook add-in, be sure to enable
Modern Authentication for the Microsoft 365 tenancy. For information about how
to do this, see Enable or disable modern authentication for Outlook in Exchange
Online.
Use single sign-on for a smoother end-user experience. The user's identity within Office
(either a Microsoft account or a Microsoft 365 identity) is used to sign in to your add-in.
As a result users only sign in once. This removes friction in the experience making it
easier for your customers to get started.
1. As an add-in is being installed, a user will see a consent window similar to the one
following:
7 Note
The add-in publisher will have control over the logo, strings and permission
scopes included in the consent window. The UI is pre-configured by
Microsoft.
2. The add-in will load after the user consents. It can extract and display any
necessary user customized information.
See also
Learn more about developing SSO Add-ins
Branding patterns
Article • 05/18/2023
These patterns provide brand visibility and context to your add-in users.
Best practices
Do Don't
Use familiar UI components with Don't invent new UI components that contradict
applied branding accents like established Office UI.
typography and color.
Place your add-in branding in a brand Don't repeat your task pane name in an immediately
bar footer at the bottom of your UI. adjacent brand bar at the top of your UI.
Use brand elements sparingly. Fit your Don't insert excessively branded elements into Office UI
solution into Office such that is that distract and confuse customers.
complementary.
Make your solution recognizable and Don't hide your solution with unrecognizable and
connect your screens together with inconsistently applied visual elements.
consistent visual elements.
Build connection with a parent service Don't make customers learn a new brand concept if
or business to ensure that customers there's a useful and understandable relationship that
know and trust your solution. can be leveraged to build trust and value.
Apply the following patterns and components as applicable to allow users to embrace
the full utility of your add-in.
Brand Bar
The brand bar is a space in the footer to include your brand name and logo. It also
serves as a link to your brand's website and an optional access location.
Splash Screen
Use this screen to display your branding while the add-in is loading or transitioning
between UI states.
First-run experience patterns
Article • 05/18/2023
Best practices
Follow these best practices when crafting your first-run experience.
Do Don't
Provide a simple and brief introduction to Don't include information and call-outs that aren't
the main actions in the add-in. relevant to getting started.
Give users the opportunity to complete an Don't expect users to learn everything at once.
action that will positively impact their use Focus on the action that provides the most value.
of the add-in.
Create an engaging experience that users Don't force the users to click through the first-run
will want to complete. experience. Give users an option to bypass the first-
run experience.
Apply the following patterns as applicable to create or enhance the first-run experience
for your add-in.
Carousel
The carousel takes users through a series of features or informational pages before they
start using the add-in.
Figure 1. Allow users to advance or skip the beginning pages of the carousel flow
Figure 2. Minimize the number of carousel screens to only what is needed to effectively
communicate your message
Figure 4. A value placemat with logo, clear value proposition, feature summary, and call-
to-action
Video Placemat
The video placemat shows users a video before they start using your add-in.
Figure 5. First-run video placemat - The screen contains a still image from the video with a
play button and clear call-to-action button
Figure 6. Video player - Users presented with a video within a dialog window
Navigation patterns
Article • 05/18/2023
The main features of an add-in are accessed through specific command types and
limited screen area. It's important that navigation is intuitive, provides context, and
allows the user to move easily throughout the add-in.
Best practices
Do Don't
Ensure the user has a clearly visible navigation Don't complicate the navigation process by
option. using non-standard UI.
Utilize the following components as applicable Don't make it difficult for the user to
to allow users to navigate through your add-in. understand their current place or context within
the add-in
Command Bar
The CommandBar is a surface within the task pane that houses commands that operate
on the content of the window, panel, or parent region it resides above. Optional features
include a hamburger menu access point, search, and side commands.
Tab Bar
The tab bar shows navigation using buttons with vertically stacked text and icons. Use
the tab bar to provide navigation using tabs with short and descriptive titles.
Back Button
The back button allows users to recover from a drill-down navigational action. This
pattern helps ensure users follow an ordered series of steps.
Design toolkits
Article • 06/23/2023
To help you get started, we've created toolkits for use with either the Sketch
application for Mac or the Adobe XD application for Windows or Mac. The following
downloads include all of our available patterns, along with brief descriptions and layout
recommendations.
Downloads
Fluent UI Design Sketch Toolkit
Fluent UI Design Adobe XD Toolkit
Add-in Sketch Toolkit
Add-in Adobe XD Toolkit
Segoe UI and Fabric MDL2 icon font
Office UI elements for Office Add-ins
Article • 04/04/2023
You can use several types of UI elements to extend the Office UI, including add-in
commands and HTML containers. These UI elements look like a natural extension of
Office and work across platforms. You can insert your custom web-based code into any
of these elements.
The following image shows the types of Office UI elements that you can create.
Add-in commands
Use add-in commands to add entry points to your add-in to the Office app ribbon.
Commands start actions in your add-in either by running JavaScript code, or by
launching an HTML container. You can create two types of add-in commands.
Command type Description
Ribbon buttons, Use to add custom buttons, menus (dropdowns), or tabs to the default
menus, and tabs ribbon in Office. Use Buttons and menus to trigger an action in Office. Use
tabs to group and organize buttons and menus.
Context menus Use to extend the default context menu. Context menus are displayed when
users right-click text in an Office document or a table in Excel.
HTML containers
Use HTML containers to embed HTML-based UI code within Office clients. These web
pages can then reference the Office JavaScript API to interact with content in the
document. You can create three types of HTML containers.
HTML Description
container
Task panes Display custom UI in the right pane of the Office document. Use task panes to
allow users to interact with your add-in side-by-side with the Office document.
Content Display custom UI embedded within Office documents. Use content add-ins to
add-ins allow users to interact with your add-in directly within the Office document. For
example, you might want to show external content such as videos or data
visualizations from other sources.
Dialog Display custom UI in a dialog box that overlays the Office document. Use a dialog
boxes box for interactions that require focus and more real estate, and do not require a
side-by-side interaction with the document.
See also
Add-in commands for Excel, Word, and PowerPoint
Task panes
Content add-ins
Dialog boxes
Add-in commands
Article • 04/11/2023
Add-in commands are UI elements that extend the Office UI and start actions in your
add-in. You can use add-in commands to add a button on the ribbon or an item to a
context menu. When users select an add-in command, they initiate actions such as
running JavaScript code, or showing a page of the add-in in a task pane. Add-in
commands help users find and use your add-in, which can help increase your add-in's
adoption and reuse, and improve customer retention.
7 Note
SharePoint catalogs do not support add-in commands. You can deploy add-in
commands via Integrated Apps or AppSource, or use sideloading to deploy
your add-in command for testing.
Content add-ins do not currently support add-in commands.
Task pane commands: The button or menu item opens the add-in's task pane. You
add this kind of add-in command with markup in the manifest. The "code behind"
the command is provided by Office.
Function commands: The button or menu item runs any arbitrary JavaScript. The
code almost always calls APIs in the Office JavaScript Library, but it doesn't have to.
This type of add-in typically displays no UI other than the button or menu item
itself. Note the following about function commands:
The function that is triggered can call the displayDialogAsync method to show a
dialog, which is a good way to display an error, show progress, or prompt for
input from the user. If the add-in is configured to use a shared runtime, the
function can also call the showAsTaskpane method.
The runtime in which the function command runs is a full browser-based
runtime. It can render HTML and call out to the Internet to send or get data.
As the ribbon gets more crowded, add-in commands will be displayed in the overflow
menu. The add-in commands for an add-in are usually grouped together.
1
If a user selects an item in the calendar but doesn't open the pop-out, the add-in's
ribbon group won't be visible on the ribbon.
Extension points
Ribbon tabs - Extend built-in tabs or create a new custom tab. An add-in can have
just one custom tab.
Context menus - Extend selected context menus.
Control types
Simple buttons - trigger specific actions.
Menus - simple menu dropdown with buttons that trigger actions.
7 Note
This feature is not supported in all Office applications or scenarios. For more
information, see Enable and Disable Add-in Commands.
This feature is not supported in all Office applications or scenarios. For more
information, see Position a custom tab on the ribbon.
7 Note
This feature is not supported in all Office applications or scenarios. For more
information, see Integrate built-in Office buttons into custom tabs.
Contextual tabs
You can specify that a tab is only visible on the ribbon in certain contexts, such as when
a chart is selected in Excel.
7 Note
This feature is not supported in all Office applications or scenarios. For more
information, see Create custom contextual tabs in Office Add-ins.
Supported platforms
Add-in commands are currently supported on the following platforms, except for
limitations specified in the subsections of Command capabilities earlier.
7 Note
Best practices
Apply the following best practices when you develop add-in commands.
Use commands to represent a specific action with a clear and specific outcome for
users. Do not combine multiple actions in a single button.
Provide granular actions that make common tasks within your add-in more
efficient to perform. Minimize the number of steps an action takes to complete.
7 Note
Add-ins that take up too much space might not pass AppSource validation.
Next steps
The best way to get started using add-in commands is to take a look at the Office Add-
in commands samples on GitHub.
For more information about specifying add-in commands in an XML manifest, see
Create add-in commands with the XML manifest and the VersionOverrides reference
content.
For more information about specifying add-in commands in the unified manifest for
Microsoft 365, see Create add-in commands with the unified manifest for Microsoft 365.
Create add-in commands with the XML
manifest
Article • 04/11/2023
Add-in commands provide an easy way to customize the default Office user interface
(UI) with specified UI elements that perform actions. For an introduction to add-in
commands, see Add-in commands.
This article describes how to edit your XML manifest to define add-in commands and
how to create the code for function commands.
Tip
For instructions on how to create add-in commands with the unified manifest for
Microsoft 365, see Create add-in commands with the unified manifest for
Microsoft 365.
The following diagram shows the hierarchy of elements used to define add-in
commands. These elements are described in more detail in this article.
Sample commands
All the task pane add-ins created by yo office have add-in commands. They contain an
add-in command (button) to show the task pane. Generate these projects by following
one of the quick starts, such as Build an Excel task pane add-in. Ensure that you have
read Add-in commands to understand command capabilities.
Important parts of an add-in command
The following steps explain how to add add-in commands to an existing add-in.
The following example shows the <VersionOverrides> element and its child elements.
XML
<OfficeApp>
...
<VersionOverrides
xmlns="http://schemas.microsoft.com/office/taskpaneappversionoverrides"
xsi:type="VersionOverridesV1_0">
<Requirements>
<!-- add information about requirement sets -->
</Requirements>
<Hosts>
<Host xsi:type="Workbook">
<!-- add information about form factors -->
</Host>
</Hosts>
<Resources>
<!-- add information about resources -->
</Resources>
</VersionOverrides>
...
</OfficeApp>
The <DesktopFormFactor> element specifies the settings for an add-in that runs in
Office on the web, Windows, and Mac.
The following example shows the <Hosts>, <Host>, and <DesktopFormFactor>
elements.
XML
<OfficeApp>
...
<VersionOverrides
xmlns="http://schemas.microsoft.com/office/taskpaneappversionoverrides"
xsi:type="VersionOverridesV1_0">
...
<Hosts>
<Host xsi:type="Workbook">
<DesktopFormFactor>
</DesktopFormFactor>
</Host>
</Hosts>
...
</VersionOverrides>
...
</OfficeApp>
7 Note
The yo office projects use webpack to avoid manually adding the JavaScript to
the HTML.
XML
<DesktopFormFactor>
<FunctionFile resid="Commands.Url" />
<ExtensionPoint xsi:type="PrimaryCommandSurface">
<!-- information about this extension point -->
</ExtensionPoint>
<!-- You can define more than one ExtensionPoint element as needed -->
</DesktopFormFactor>
) Important
Office.js must be initialized before the add-in command logic runs. For more
information, see Initialize your Office Add-in.
Outlook notifications
When an add-in needs to provide status updates, such as progress indicators or error
messages, it must do so through the notification APIs. The processing for the
notifications must also be defined in a separate HTML file that is specified in the
FunctionFile node of the manifest.
The following examples show how to use the <ExtensionPoint> element with
PrimaryCommandSurface and ContextMenu attribute values, and the child elements
that should be used with each.
) Important
For elements that contain an ID attribute, make sure you provide a unique ID. We
recommend that you use your company's name along with your ID. For example,
use the following format: <CustomTab id="mycompanyname.mygroupname"> .
XML
<ExtensionPoint xsi:type="PrimaryCommandSurface">
<CustomTab id="Contoso Tab">
<!-- If you want to use a default tab that comes with Office, remove the
above CustomTab element, and then uncomment the following OfficeTab element
-->
<!-- <OfficeTab id="TabData"> -->
<Label resid="residLabel4" />
<Group id="Group1Id12">
<Label resid="residLabel4" />
<Icon>
<bt:Image size="16" resid="icon1_32x32" />
<bt:Image size="32" resid="icon1_32x32" />
<bt:Image size="80" resid="icon1_32x32" />
</Icon>
<Tooltip resid="residToolTip" />
<Control xsi:type="Button" id="Button1Id1">
Button controls
A button control performs a single action when the user selects it. It can either execute a
JavaScript function or show a task pane. The following example shows how to define
two buttons. The first button runs a JavaScript function without showing a UI, and the
second button shows a task pane. In the <Control> element:
XML
The following code shows an example function used by <FunctionName>. Note the call
to event.completed. This signals that you've successfully handled the event. When a
function is called multiple times, such as multiple clicks on the same add-in command,
all events are automatically queued. The first event runs automatically, while the other
events remain on the queue. When your function calls event.completed , the next
queued call to that function runs. You must implement event.completed , otherwise your
function won't run.
JavaScript
// Implement your custom code here. The following code is a simple Excel
example.
try {
await Excel.run(async (context) => {
const range = context.workbook.getSelectedRange();
range.format.fill.color = "yellow";
await context.sync();
});
} catch (error) {
// Note: In a production add-in, notify the user through your add-
in's UI.
console.error(error);
}
Menu controls
A menu control can be used with either PrimaryCommandSurface or ContextMenu,
and defines:
When used with PrimaryCommandSurface, the root menu item displays as a button on
the ribbon. When the button is selected, the submenu displays as a drop-down list.
When used with ContextMenu, a menu item with a submenu is inserted on the context
menu. In both cases, individual submenu items can either execute a JavaScript function
or show a task pane. Only one level of submenus is supported at this time.
The following example shows how to define a menu item with two submenu items. The
first submenu item shows a task pane, and the second submenu item runs a JavaScript
function. In the <Control> element:
XML
The following shows an example of how to use the <Resources> element. Each resource
can have one or more <Override> child elements to define a different resource for a
specific locale.
XML
<Resources>
<bt:Images>
<bt:Image id="icon1_16x16"
DefaultValue="https://www.contoso.com/Images/icon_default.png">
<bt:Override Locale="ja-jp" Value="https://www.contoso.com/Images/ja-
jp16-icon_default.png" />
</bt:Image>
<bt:Image id="icon1_32x32"
DefaultValue="https://www.contoso.com/Images/icon_default.png">
<bt:Override Locale="ja-jp" Value="https://www.contoso.com/Images/ja-
jp32-icon_default.png" />
</bt:Image>
<bt:Image id="icon1_80x80"
DefaultValue="https://www.contoso.com/Images/icon_default.png">
<bt:Override Locale="ja-jp" Value="https://www.contoso.com/Images/ja-
jp80-icon_default.png" />
</bt:Image>
</bt:Images>
<bt:Urls>
<bt:Url id="residDesktopFuncUrl"
DefaultValue="https://www.contoso.com/Pages/Home.aspx">
<bt:Override Locale="ja-jp"
Value="https://www.contoso.com/Pages/Home.aspx" />
</bt:Url>
</bt:Urls>
<bt:ShortStrings>
<bt:String id="residLabel" DefaultValue="GetData">
<bt:Override Locale="ja-jp" Value="JA-JP-GetData" />
</bt:String>
</bt:ShortStrings>
<bt:LongStrings>
<bt:String id="residToolTip" DefaultValue="Get data for your document.">
<bt:Override Locale="ja-jp" Value="JA-JP - Get data for your
document." />
</bt:String>
</bt:LongStrings>
</Resources>
7 Note
You must use Secure Sockets Layer (SSL) for all URLs in the <Image> and <Url>
elements.
If your add-in uses an XML manifest, then add-in commands are only available for add-
ins that do not use ItemHasAttachment, ItemHasKnownEntity, or
ItemHasRegularExpressionMatch rules to limit the types of items they activate on.
However, contextual add-ins can present different commands depending on whether
the currently selected item is a message or appointment, and can choose to appear in
read or compose scenarios. Using add-in commands if possible is a best practice.
See also
Add-in commands
Sample: Create an Excel add-in with command buttons
Sample: Create an Word add-in with command buttons
Sample: Create an PowerPoint add-in with command buttons
Create add-in commands with the
unified manifest for Microsoft 365
Article • 07/27/2023
Add-in commands provide an easy way to customize the default Office user interface
(UI) with specified UI elements that perform actions. For an introduction to add-in
commands, see Add-in commands.
This article describes how to configure the Unified manifest for Microsoft 365 (preview)
to define add-in commands and how to create the code for function commands.
Tip
Instructions for creating add-in commands with the XML manifest are in Create
add-in commands with the XML manifest.
7 Note
The unified manifest is currently supported only for Outlook Add-ins on Windows.
It's in preview and not yet supported for production add-ins.
Two decisions
Decide which of two types of add-in commands you need: Task pane or function.
Decide which kind of UI element you need: button or menu item. Then carry out
the steps in the sections and subsections below that correspond to your decisions.
2. Ensure that there is a runtime object that has an "actions.type" property with the
value "openPage". This type of runtime opens a task pane.
7 Note
When support for the unified manifest is extended to other Office host
applications, the minimum requirement set for add-in commands in those
other hosts will be AddinCommands 1.1.
4. Ensure that the "id" of the runtime object has a descriptive name such as
"TaskPaneRuntime".
5. Ensure that the "code.page" property of the runtime object is set to the URL of the
page that should open in the task pane, such as
"https://localhost:3000/taskpane.html".
6. Ensure that the "actions.view" of the runtime object has a name that describes the
content of the page that you set in the preceding step, such as "homepage" or
"dashboard".
7. Ensure that the "actions.id" of the runtime object has a descriptive name such as
"ShowTaskPane" that indicates what happens when the user selects the add-in
command button or menu item.
8. Set the other properties and subproperties of the runtime object as shown in the
following completed example of a runtime object. The "type" and "lifetime"
properties are required and in Outlook Add-ins (which is the only host that
currently supports the unified manifest) they always have the values shown in this
example.
JSON
"runtimes": [
{
"requirements": {
"capabilities": [
{
"name": "Mailbox",
"minVersion": "1.3"
}
]
},
"id": "TaskPaneRuntime",
"type": "general",
"code": {
"page": "https://localhost:3000/taskpane.html"
},
"lifetime": "short",
"actions": [
{
"id": "ShowTaskPane",
"type": "openPage",
"view": "homepage"
}
]
}
]
2. Ensure that the array has an object with array properties named "contexts" and
"tabs", as shown in the following example.
JSON
"ribbons": [
{
"contexts": [
// child objects omitted
],
"tabs": [
// child objects omitted
]
}
]
3. Ensure that the "contexts" array has strings that specify the windows or panes in
which the UI for the task pane command should appear. For example, "mailRead"
means that it will appear in the reading pane or message window when an email
message is open, but "mailCompose" means it will appear when a new message or
a reply is being composed. The following are the allowable values:
"mailRead"
"mailCompose"
"meetingDetailsOrganizer"
"meetingDetailsAttendee"
JSON
"contexts": [
"mailRead"
],
4. Ensure that the "tabs" array has an object with a "builtInTabId" string property that
is set to the ID of ribbon tab in which you want your task pane command to
appear. Also, ensure that there is a "groups" array with at least one object in it. The
following is an example.
JSON
"tabs": [
{
"builtInTabID": "TabDefault",
"groups": [
{
// properties omitted
}
]
}
]
7 Note
The only allowed value for the "builtInTabID" property is "TabDefault", which
in Outlook is either the Home, Message, or Meeting tab. When support for
the unified manifest is added to other Office host applications, there will be
other possible values.
5. Ensure that the "groups" array has an object to define the custom control group
that will hold your add-in command UI controls. The following is an example. Note
the following about this JSON:
The "id" must be unique across all groups in all ribbon objects in the
manifest. Maximum length is 64 characters.
The "label" appears on the group on the ribbon. Maximum length is 64
characters.
One of the "icons" appears on the group only if the Office application
window, and hence the ribbon, has been sized by the user too small for any
of the controls in the group to appear. Office decides when to use one of
these icons and which one to use based on the size of the window and the
resolution of the device. You cannot control this. You must provide image
files for 16, 32, and 80 pixels, while five other sizes are also supported (20, 24,
40, 48, and 64 pixels). You must use Secure Sockets Layer (SSL) for all URLs.
7 Note
The name of the "icons.file" property may change during the preview of the
unified manifest for Office Add-ins. If you get intellisense or manifest
validation errors, try replacing "file" with "url".
JSON
"groups": [
{
"id": "msgReadGroup",
"label": "Contoso Add-in",
"icons": [
{
"size": 16,
"file": "https://localhost:3000/assets/icon-16.png"
},
{
"size": 32,
"file": "https://localhost:3000/assets/icon-32.png"
},
{
"size": 80,
"file": "https://localhost:3000/assets/icon-80.png"
}
],
"controls": [
{
// properties omitted
}
]
}
]
6. Ensure that there is a control object in the "controls" array for each button or
custom menu you want. The following is an example. Note the following about this
JSON:
The "id", "label", and "icons" properties have the same purpose and the same
restrictions as the corresponding properties of a group object, except that
they apply to a specific button or menu within the group.
The "type" property is set to "button" which means that the control will be a
ribbon button. You can also configure a task pane command to be run from a
menu item. See Menu and menu items.
The "supertip.title" (maximum length: 64 characters) and
"supertip.description" (maximum length: 128 characters) appear when the
cursor is hovering over the button or menu.
The "actionId" must be an exact match for the "runtimes.actions.id" that you
set in Configure the runtime for the task pane command.
JSON
{
"id": "msgReadOpenPaneButton",
"type": "button",
"label": "Show Task Pane",
"icons": [
{
"size": 16,
"file": "https://localhost:3000/assets/icon-16.png"
},
{
"size": 32,
"file": "https://localhost:3000/assets/icon-32.png"
},
{
"size": 80,
"file": "https://localhost:3000/assets/icon-80.png"
}
],
"supertip": {
"title": "Show Contoso Task Pane",
"description": "Opens the Contoso task pane."
},
"actionId": "ShowTaskPane"
}
You've now completed adding a task pane command to your add-in. Sideload and test
it.
Add a function command
The following subsections explain how to include a function command in an add-in.
JavaScript
Office.onReady(function() {
// Add any initialization code here.
});
function setNotification(event) {
const message = {
type:
Office.MailboxEnums.ItemNotificationMessageType.InformationalMessage,
message: "Performed action.",
icon: "Icon.80x80",
persistent: true,
};
2. Ensure that your source code includes an HTML file that is configured to load the
function file you created. The following is an example. Note the following about
this JSON:
The <body> element is empty because the file has no UI. Its only purpose is to
load JavaScript files.
The Office JavaScript Library and the commands.js file that you created in the
preceding step is explicitly loaded.
7 Note
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
2. Ensure that there is a runtime object that has a "actions.type" property with the
value "executeFunction".
3. Ensure that the "requirements.capabilities" array contains objects that specify any
Requirement Sets that are needed to support the APIs add-in commands. For
Outlook, the minimum requirement set for add-in commands is Mailbox 1.3. But if
your function command calls that API that is part of later Mailbox requirement set,
such as Mailbox 1.5, then you need to specify the later version (e.g., "1.5") as the
"minVersion" value.
7 Note
When support for the unified manifest is extended to other Office host
applications, the minimum requirement set for add-in commands in those
other hosts will be AddinCommands 1.1.
4. Ensure that the "id" of the runtime object has a descriptive name such as
"CommandsRuntime".
5. Ensure that the "code.page" property of the runtime object is set to the URL of the
UI-less HTML page that loads your function file, such as
"https://localhost:3000/commands.html".
6. Ensure that the "actions.id" of the runtime object has a descriptive name such as
"SetNotification" that indicates what happens when the user selects the add-in
command button or menu item.
) Important
The value of "actions.id" must exactly match the first parameter of the call to
Office.actions.associate in the function file.
7. Set the other properties and subproperties of the runtime object as shown in the
following completed example of a runtime object. The "type" and "lifetime"
properties are required and they always have the values shown in Outlook add-ins,
which is the only host that currently supports the unified manifest.
JSON
"runtimes": [
{
"id": "CommandsRuntime",
"type": "general",
"code": {
"page": "https://localhost:3000/commands.html"
},
"lifetime": "short",
"actions": [
{
"id": "SetNotification",
"type": "executeFunction",
}
]
}
]
2. Ensure that the array has an object with array properties named "contexts" and
"tabs", as shown in the following example.
JSON
"ribbons": [
{
"contexts": [
// child objects omitted
],
"tabs": [
// child objects omitted
]
}
]
3. Ensure that the "contexts" array has strings that specify the windows or panes in
which the UI for the function command should appear. For example, "mailRead"
means that it will appear in the reading pane or message window when an email
message is open, but "mailCompose" means it will appear when a new message or
a reply is being composed. The following are the allowable values:
mailRead
mailCompose
meetingDetailsOrganizer
meetingDetailsAttendee
JSON
"contexts": [
"mailRead"
],
4. Ensure that the "tabs" array has an object with a "builtInTabId" string property that
is set to the ID of ribbon tab in which you want your function command to appear
and a "groups" array with at least one object in it. The following is an example.
JSON
"tabs": [
{
"builtInTabID": "TabDefault",
"groups": [
{
// properties omitted
}
]
}
]
7 Note
The only allowed value for the "builtInTabID" property is "TabDefault", which
in Outlook is either the Home, Message, or Meeting tab. When support for
the unified manifest is added to other Office host applications, there will be
other possible values.
5. Ensure that the "groups" array has an object to define the custom control group
that will hold your add-in command UI controls. The following is an example. Note
the following about this JSON:
The "id" must be unique across all groups in all ribbon objects in the
manifest. Maximum length is 64 characters.
The "label" appears on the group on the ribbon. Maximum length is 64
characters.
One of the "icons" appears on the group only if the Office application
window, and hence the ribbon, has been sized by the user too small for any
of the controls in the group to appear. Office decides when to use one of
these icons and which one to use based on the size of the window and the
resolution of the device. You cannot control this. You must provide image
files for 16, 32, and 80 pixels, while five other sizes are also supported (20, 24,
40, 48, and 64 pixels). You must use Secure Sockets Layer (SSL) for all URLs.
7 Note
The name of the "icons.file" property may change during the preview of the
unified manifest for Office Add-ins. If you get intellisense or manifest
validation errors, try replacing "file" with "url".
JSON
"groups": [
{
"id": "msgReadGroup",
"label": "Contoso Add-in",
"icons": [
{
"size": 16,
"file": "https://localhost:3000/assets/icon-16.png"
},
{
"size": 32,
"file": "https://localhost:3000/assets/icon-32.png"
},
{
"size": 80,
"file": "https://localhost:3000/assets/icon-80.png"
}
],
"controls": [
{
// properties omitted
}
]
}
]
6. Ensure that there is a control object in the "controls" array for each button or
custom menu you want. The following is an example. Note the following about this
JSON:
The "id", "label", and "icons" properties have the same purpose and the same
restrictions as the corresponding properties of a group object, except that
they apply to a specific button or menu within the group.
The "type" property is set to "button" which means that the control will be a
ribbon button. You can also configure a function command to be run from a
menu item. See Menu and menu items.
The "supertip.title" (maximum length: 64 characters) and
"supertip.description" (maximum length: 128 characters) appear when the
cursor is hovering over the button or menu.
The "actionId" must be an exact match for the "runtime.actions.id" that you
set in Configure the runtime for the function command.
JSON
{
"id": "msgReadSetNotificationButton",
"type": "button",
"label": "Set Notification",
"icons": [
{
"size": 16,
"file": "https://localhost:3000/assets/icon-16.png"
},
{
"size": 32,
"file": "https://localhost:3000/assets/icon-32.png"
},
{
"size": 80,
"file": "https://localhost:3000/assets/icon-80.png"
}
],
"supertip": {
"title": "Set Notification",
"description": "Displays a notification message on the current
message."
},
"actionId": "SetNotification"
}
You've now completed adding a function command to your add-in. Sideload and test it.
2. Ensure that the array has an object with array properties named "contexts" and
"tabs", as shown in the following example.
JSON
"ribbons": [
{
"contexts": [
// child objects omitted
],
"tabs": [
// child objects omitted
]
}
]
3. Ensure that the "contexts" array has strings that specify the windows or panes in
which the menu should appear on the ribbon. For example, "mailRead" means that
it will appear in the reading pane or message window when an email message is
open, but "mailCompose" means it will appear when a new message or a reply is
being composed. The following are the allowable values:
mailRead
mailCompose
meetingDetailsOrganizer
meetingDetailsAttendee
JSON
"contexts": [
"mailRead"
],
4. Ensure that the "tabs" array has an object with a "builtInTabId" string property that
is set to the ID of ribbon tab in which you want your task pane command to
appear and a "groups" array with at least one object in it. The following is an
example.
JSON
"tabs": [
{
"builtInTabID": "TabDefault",
"groups": [
{
// properties omitted
}
]
}
]
7 Note
The only allowed value for the "builtInTabID" property is "TabDefault", which
in Outlook is either the Home, Message, or Meeting tab. When support for
the unified manifest is added to other Office host applications, there will be
other possible values.
5. Ensure that the "groups" array has an object to define the custom control group
that will hold your drop down menu control. The following is an example. Note the
following about this JSON:
The "id" must be unique across all groups in all ribbon objects in the
manifest. Maximum length is 64 characters.
The "label" appears on the group on the ribbon. Maximum length is 64
characters.
One of the "icons" appears on the group only if the Office application
window, and hence the ribbon, has been sized by the user too small for any
of the controls in the group to appear. Office decides when to use one of
these icons and which one to use based on the size of the window and the
resolution of the device. You cannot control this. You must provide image
files for 16, 32, and 80 pixels, while five other sizes are also supported (20, 24,
40, 48, and 64 pixels). You must use Secure Sockets Layer (SSL) for all URLs.
7 Note
The name of the "icons.file" property may change during the preview of the
unified manifest for Office Add-ins. If you get intellisense or manifest
validation errors, try replacing "file" with "url".
JSON
"groups": [
{
"id": "msgReadGroup",
"label": "Contoso Add-in",
"icons": [
{
"size": 16,
"file": "https://localhost:3000/assets/icon-16.png"
},
{
"size": 32,
"file": "https://localhost:3000/assets/icon-32.png"
},
{
"size": 80,
"file": "https://localhost:3000/assets/icon-80.png"
}
],
"controls": [
{
// properties omitted
}
]
}
]
6. Ensure that there is a control object in the "controls" array. The following is an
example. Note the following about this JSON:
The "id", "label", and "icons" properties have the same purpose and the same
restrictions as the corresponding properties of a group object, except that
they apply to the drop down menu within the group.
The "type" property is set to "menu" which means that the control will be a
drop down menu.
The "supertip.title" (maximum length: 64 characters) and
"supertip.description" (maximum length: 128 characters) appear when the
cursor is hovering over the menu.
The "items" property contains the JSON for the two menu options. The values
are added in later steps.
JSON
{
"id": "msgReadMenu",
"type": "menu",
"label": "Contoso Menu",
"icons": [
{
"size": 16,
"file": "https://localhost:3000/assets/icon-16.png"
},
{
"size": 32,
"file": "https://localhost:3000/assets/icon-32.png"
},
{
"size": 80,
"file": "https://localhost:3000/assets/icon-80.png"
}
],
"supertip": {
"title": "Show Contoso Actions",
"description": "Opens the Contoso menu."
},
"items": [
{
"id": "",
"type": "",
"label": "",
"supertip": {},
"actionId": ""
},
{
"id": "",
"type": "",
"label": "",
"supertip": {},
"actionId": ""
}
]
}
7. The first item shows a task pane. The following is an example. Note the following
about this code:
The "id", "label", and "supertip" properties have the same purpose and the
same restrictions as the corresponding properties of the parent menu object,
except that they apply to just this menu option.
The "icons" property is optional for menu items and there isn't one in this
example. If you include one, it has the same purposes and restrictions as the
"icons" property of the parent menu, except that the icon appears on the
menu item beside the label.
The "type" property is set to "menuItem".
The "actionId" must be an exact match for the "runtimes.actions.id" that you
set in Configure the runtime for the task pane command.
JSON
{
"id": "msgReadOpenPaneMenuItem",
"type": "menuItem",
"label": "Show Task Pane",
"supertip": {
"title": "Show Contoso Task Pane",
"description": "Opens the Contoso task pane."
},
"actionId": "ShowTaskPane"
},
8. The second item runs a function command. The following is an example. Note the
following about this code:
The "actionId" must be an exact match for the "runtimes.actions.id" that you
set in Configure the runtime for the function command.
JSON
{
"id": "msgReadSetNotificationMenuItem",
"type": "menuItem",
"label": "Set Notification",
"supertip": {
"title": "Set Notification",
"description": "Displays a notification message on the current
message."
},
"actionId": "SetNotification"
}
You've now completed adding a menu to your add-in. Sideload and test it.
See also
Add-in commands
Unified manifest for Microsoft 365 (preview).
Create custom contextual tabs in Office
Add-ins
Article • 03/14/2023
A contextual tab is a hidden tab control in the Office ribbon that is displayed in the tab
row when a specified event occurs in the Office document. For example, the Table
Design tab that appears on the Excel ribbon when a table is selected. You include
custom contextual tabs in your Office Add-in and specify when they are visible or
hidden, by creating event handlers that change the visibility. (However, custom
contextual tabs do not respond to focus changes.)
7 Note
This article assumes that you are familiar with the following documentation. Please
review it if you haven't worked with Add-in Commands (custom menu items and
ribbon buttons) recently.
) Important
Custom contextual tabs are currently only supported on Excel and only on these
platforms and builds.
7 Note
Custom contextual tabs work only on platforms that support the following
requirement sets. For more about requirement sets and how to work with them, see
Specify Office applications and API requirements.
RibbonApi 1.2
SharedRuntime 1.1
You can use the runtime checks in your code to test whether the user's host and
platform combination supports these requirement sets as described in Runtime
checks for method and requirement set support. (The technique of specifying the
requirement sets in the manifest, which is also described in that article, does not
currently work for RibbonApi 1.2.) Alternatively, you can implement an alternate UI
experience when custom contextual tabs are not supported.
When a custom contextual tab is visible, it appears on the right end of the ribbon.
If one or more built-in contextual tabs and one or more custom contextual tabs
from add-ins are visible at the same time, the custom contextual tabs are always to
the right of all of the built-in contextual tabs.
If your add-in has more than one contextual tab and there are contexts in which
more than one is visible, they appear in the order in which they are defined in your
add-in. (The direction is the same direction as the Office language; that is, is left-
to-right in left-to-right languages, but right-to-left in right-to-left languages.) See
Define the groups and controls that appear on the tab for details about how you
define them.
If more than one add-in has a contextual tab that is visible in a specific context,
then they appear in the order in which the add-ins were launched.
Custom contextual tabs, unlike custom core tabs, are not added permanently to
the Office application's ribbon. They are present only in Office documents on
which your add-in is running.
7 Note
The structure of the JSON blob's properties and subproperties (and the key names)
is roughly parallel to the structure of the CustomTab element and its descendant
elements in the manifest XML.
We'll construct an example of a contextual tabs JSON blob step-by-step. The full schema
for the contextual tab JSON is at dynamic-ribbon.schema.json. If you are working in
Visual Studio Code, you can use this file to get IntelliSense and to validate your JSON.
For more information, see Editing JSON with Visual Studio Code - JSON schemas and
settings .
1. Begin by creating a JSON string with two array properties named actions and
tabs . The actions array is a specification of all the functions that can be executed
by controls on the contextual tab. The tabs array defines one or more contextual
tabs, up to a maximum of 20.
JSON
'{
"actions": [
],
"tabs": [
]
}'
2. This simple example of a contextual tab will have only a single button and, thus,
only a single action. Add the following as the only member of the actions array.
About this markup, note:
JSON
{
"id": "executeWriteData",
"type": "ExecuteFunction",
"functionName": "writeData"
}
3. Add the following as the only member of the tabs array. About this markup, note:
7 Note
The tab object can also have an optional visible property that specifies
whether the tab is visible immediately when the add-in starts up. Since
contextual tabs are normally hidden until a user event triggers their visibility
(such as the user selecting an entity of some type in the document), the
visible property defaults to false when not present. In a later section, we
JSON
{
"id": "CtxTab1",
"label": "Contoso Data",
"groups": [
]
}
4. In the simple ongoing example, the contextual tab has only a single group. Add
the following as the only member of the groups array. About this markup, note:
) Important
The total number of controls on the whole tab can be no more than 20. For
example, you could have 3 groups with 6 controls each, and a fourth group
with 2 controls, but you cannot have 4 groups with 6 controls each.
JSON
{
"id": "CustomGroup111",
"label": "Insertion",
"icon": [
],
"controls": [
]
}
5. Every group must have an icon of at least two sizes, 32x32 px and 80x80 px.
Optionally, you can also have icons of sizes 16x16 px, 20x20 px, 24x24 px, 40x40
px, 48x48 px, and 64x64 px. Office decides which icon to use based on the size of
the ribbon and Office application window. Add the following objects to the icon
array. (If the window and ribbon sizes are large enough for at least one of the
controls on the group to appear, then no group icon at all appears. For an example,
watch the Styles group on the Word ribbon as you shrink and expand the Word
window.) About this markup, note:
) Important
Just as you typically must change the URLs in the add-in's manifest when you
move from development to production (such as changing the domain from
localhost to contoso.com), you must also change the URLs in your contextual
tabs JSON.
JSON
{
"size": 32,
"sourceLocation":
"https://cdn.contoso.com/addins/datainsertion/Images/Group32x32.png"
},
{
"size": 80,
"sourceLocation":
"https://cdn.contoso.com/addins/datainsertion/Images/Group80x80.png"
}
6. In our simple ongoing example, the group has only a single button. Add the
following object as the only member of the controls array. About this markup,
note:
"MobileButton".
id can be up to 125 characters.
actionId must be the ID of an action defined in the actions array. (See step
1 of this section.)
label is a user-friendly string to serve as the label of the button.
superTip represents a rich form of tool tip. Both the title and description
properties are required.
icon specifies the icons for the button. The previous remarks about the
contextual tab appears starts up. The default if not present is true .
JSON
{
"type": "Button",
"id": "CtxBt112",
"actionId": "executeWriteData",
"enabled": false,
"label": "Write Data",
"superTip": {
"title": "Data Insertion",
"description": "Use this button to insert data into the
document."
},
"icon": [
{
"size": 32,
"sourceLocation":
"https://cdn.contoso.com/addins/datainsertion/Images/WriteDataButton32x
32.png"
},
{
"size": 80,
"sourceLocation":
"https://cdn.contoso.com/addins/datainsertion/Images/WriteDataButton80x
80.png"
}
]
}
JSON
`{
"actions": [
{
"id": "executeWriteData",
"type": "ExecuteFunction",
"functionName": "writeData"
}
],
"tabs": [
{
"id": "CtxTab1",
"label": "Contoso Data",
"groups": [
{
"id": "CustomGroup111",
"label": "Insertion",
"icon": [
{
"size": 32,
"sourceLocation":
"https://cdn.contoso.com/addins/datainsertion/Images/Group32x32.png"
},
{
"size": 80,
"sourceLocation":
"https://cdn.contoso.com/addins/datainsertion/Images/Group80x80.png"
}
],
"controls": [
{
"type": "Button",
"id": "CtxBt112",
"actionId": "executeWriteData",
"enabled": false,
"label": "Write Data",
"superTip": {
"title": "Data Insertion",
"description": "Use this button to insert data into the
document."
},
"icon": [
{
"size": 32,
"sourceLocation":
"https://cdn.contoso.com/addins/datainsertion/Images/WriteDataButton32x32.pn
g"
},
{
"size": 80,
"sourceLocation":
"https://cdn.contoso.com/addins/datainsertion/Images/WriteDataButton80x80.pn
g"
}
]
}
]
}
]
}
]
}`
Register the contextual tab with Office with
requestCreateControls
The contextual tab is registered with Office by calling the
Office.ribbon.requestCreateControls method. This is typically done in either the function
that is assigned to Office.initialize or with the Office.onReady function. For more
about these functions and initializing the add-in, see Initialize your Office Add-in. You
can, however, call the method anytime after initialization.
) Important
The following is an example. Note that the JSON string must be converted to a
JavaScript object with the JSON.parse method before it can be passed to a JavaScript
function.
JavaScript
Office.onReady(async () => {
const contextualTabJSON = ` ... `; // Assign the JSON string such as the
one at the end of the preceding section.
const contextualTab = JSON.parse(contextualTabJSON);
await Office.ribbon.requestCreateControls(contextualTab);
});
JavaScript
Office.onReady(async () => {
const contextualTabJSON = ` ... `; // Assign the JSON string.
const contextualTab = JSON.parse(contextualTabJSON);
await Office.ribbon.requestCreateControls(contextualTab);
Next, define the handlers. The following is a simple example of a showDataTab , but see
Handling the HostRestartNeeded error later in this article for a more robust version of
the function. About this code, note:
JavaScript
The handler to hide the tab is nearly identical, except that it sets the visible property
back to false .
The Office JavaScript library also provides several interfaces (types) to make it easier to
construct the RibbonUpdateData object. The following is the showDataTab function in
TypeScript and it makes use of these types.
TypeScript
JavaScript
function myContextChanges() {
Office.ribbon.requestUpdate({
tabs: [
{
id: "CtxTab1",
visible: true
},
{
id: "OfficeAppTab1",
groups: [
{
id: "CustomGroup111",
controls: [
{
id: "MyButton",
enabled: true
}
]
}
]
]}
]
});
}
In the following example, the button that is enabled is on the very same contextual tab
that is being made visible.
JavaScript
function myContextChanges() {
Office.ribbon.requestUpdate({
tabs: [
{
id: "CtxTab1",
visible: true,
groups: [
{
id: "CustomGroup111",
controls: [
{
id: "MyButton",
enabled: true
}
]
}
]
}
]
});
}
JSON
`{
"actions": [
{
"id": "openChartsTaskpane",
"type": "ShowTaskpane",
"title": "Work with Charts",
"supportPinning": false
}
],
"tabs": [
{
// some tab properties omitted
"groups": [
{
// some group properties omitted
"controls": [
{
"type": "Button",
"id": "CtxBt112",
"actionId": "openChartsTaskpane",
"enabled": false,
"label": "Open Charts Taskpane",
// some control properties omitted
}
]
}
]
}
]
}`
To open any task pane that is not the default task pane, specify a sourceLocation
property in the definition of the action. In the following example, a second task pane is
opened from a different button.
) Important
When a sourceLocation is specified for the action, then the task pane does
not use the shared runtime. It runs in a new separate runtime.
No more than one task pane can use the shared runtime, so no more than
one action of type ShowTaskpane can omit the sourceLocation property.
JSON
`{
"actions": [
{
"id": "openChartsTaskpane",
"type": "ShowTaskpane",
"title": "Work with Charts",
"supportPinning": false
},
{
"id": "openTablesTaskpane",
"type": "ShowTaskpane",
"title": "Work with Tables",
"supportPinning": false
"sourceLocation": "https://MyDomain.com/myPage.html"
}
],
"tabs": [
{
// some tab properties omitted
"groups": [
{
// some group properties omitted
"controls": [
{
"type": "Button",
"id": "CtxBt112",
"actionId": "openChartsTaskpane",
"enabled": false,
"label": "Open Charts Taskpane",
// some control properties omitted
},
{
"type": "Button",
"id": "CtxBt113",
"actionId": "openTablesTaskpane",
"enabled": false,
"label": "Open Tables Taskpane",
// some control properties omitted
}
]
}
]
}
]
}`
JavaScript
function GetContextualTabsJsonSupportedLocale () {
const displayLanguage = Office.context.displayLanguage;
switch (displayLanguage) {
case 'en-US':
return `{
"actions": [
// actions omitted
],
"tabs": [
{
"id": "CtxTab1",
"label": "Contoso Data",
"groups": [
// groups omitted
]
}
]
}`;
case 'fr-FR':
return `{
"actions": [
// actions omitted
],
"tabs": [
{
"id": "CtxTab1",
"label": "Contoso Données",
"groups": [
// groups omitted
]
}
]
}`;
Then your code calls the function to get the localized blob that is passed to
requestCreateControls , as in the following example.
JavaScript
The simplest strategy for using this element is to define a custom core tab (that is,
noncontextual custom tab) in the manifest that duplicates the ribbon customizations of
the custom contextual tabs in your add-in. But you add
<OverriddenByRibbonApi>true</OverriddenByRibbonApi> as the first child element of the
duplicate Group, Control, and menu <Item> elements on the custom core tabs. The
effect of doing so is the following:
If the add-in runs on an application and platform that support custom contextual
tabs, then the custom core groups and controls won't appear on the ribbon.
Instead, the custom contextual tab will be created when the add-in calls the
requestCreateControls method.
If the add-in runs on an application or platform that doesn't support
requestCreateControls , then the elements do appear on the custom core tab.
The following is an example. Note that "MyButton" will appear on the custom core tab
only when custom contextual tabs are not supported. But the parent group and custom
core tab will appear regardless of whether custom contextual tabs are supported.
XML
<OfficeApp ...>
...
<VersionOverrides ...>
...
<Hosts>
<Host ...>
...
<DesktopFormFactor>
<ExtensionPoint ...>
<CustomTab ...>
...
<Group ...>
...
<Control ... id="Contoso.MyButton1">
<OverriddenByRibbonApi>true</OverriddenByRibbonApi>
...
<Action ...>
...
</OfficeApp>
) Important
function showDataTab() {
try {
Office.ribbon.requestUpdate({
tabs: [
{
id: "CtxTab1",
visible: true
}
]});
}
catch(error) {
if (error.code == "HostRestartNeeded"){
reportError("Contoso Awesome Add-in has been upgraded. Please
save your work, then close and reopen the Office application.");
}
}
}
Resources
Code sample: Create custom contextual tabs on the ribbon
Community demo of contextual tabs sample
https://www.youtube-nocookie.com/embed/9tLfm4boQIo
Enable and Disable Add-in Commands
Article • 04/04/2023
When some functionality in your add-in should only be available in certain contexts, you
can programmatically enable or disable your custom Add-in Commands. For example, a
function that changes the header of a table should only be enabled when the cursor is
in a table.
You can also specify whether the command is enabled or disabled when the Office client
application opens.
7 Note
This article assumes that you are familiar with the following documentation. Please
review it if you haven't worked with Add-in Commands (custom menu items and
ribbon buttons) recently.
7 Note
The RibbonApi 1.1 requirement set is not yet supported in the manifest, so you
cannot specify it in the manifest's <Requirements> section. To test for support,
your code should call Office.context.requirements.isSetSupported('RibbonApi',
'1.1') . If, and only if, that call returns true , your code can call the enable/disable
APIs. If the call of isSetSupported returns false , then all custom add-in commands
are enabled all of the time. You must design your production add-in, and any in-
app instructions, to take account of how it will work when the RibbonApi 1.1
requirement set isn't supported. For more information and examples of using
isSetSupported , see Specify Office applications and API requirements, especially
Runtime checks for method and requirement set support. (The section Specify
which Office versions and platforms can host your add-in of that article doesn't
apply to Ribbon 1.1.)
1. In the Runtimes element in the manifest, add the following child element: <Runtime
resid="Contoso.SharedRuntime.Url" lifetime="long" /> . (If there isn't already a
<Runtimes> element in the manifest, create it as the first child under the <Host>
element in the <VersionOverrides> section.)
2. In the Resources.Urls section of the manifest, add the following child element:
<bt:Url id="Contoso.SharedRuntime.Url" DefaultValue="https://{MyDomain}/{path-
to-start-page}" /> , where {MyDomain} is the domain of the add-in and {path-to-
start-page} is the path for the start page of the add-in; for example: <bt:Url
id="Contoso.SharedRuntime.Url"
DefaultValue="https://localhost:3000/index.html" /> .
3. Depending on whether your add-in contains a task pane, a function file, or an Excel
custom function, you must do one or more of the following three steps.
If the add-in contains a task pane, set the resid attribute of the
Action.SourceLocation element to exactly the same string as you used for the
resid of the <Runtime> element in step 1; for example,
If the add-in contains an Excel custom function, set the resid attribute of the
Page.SourceLocation element exactly the same string as you used for the
resid of the <Runtime> element in step 1; for example,
If the add-in contains a function file, set the resid attribute of the
FunctionFile element to exactly the same string as you used for the resid of
the <Runtime> element in step 1; for example, Contoso.SharedRuntime.Url .
The element should look like this: <FunctionFile
resid="Contoso.SharedRuntime.Url"/> .
XML
<OfficeApp ...>
...
<VersionOverrides ...>
...
<Hosts>
<Host ...>
...
<DesktopFormFactor>
<ExtensionPoint ...>
<CustomTab ...>
...
<Group ...>
...
<Control ... id="Contoso.MyButton3">
...
<Action ...>
<Enabled>false</Enabled>
...
</OfficeApp>
1. Create a RibbonUpdaterData object that (1) specifies the command, and its parent
group and tab, by their IDs as declared in the manifest; and (2) specifies the
enabled or disabled state of the command.
2. Pass the RibbonUpdaterData object to the Office.ribbon.requestUpdate() method.
function enableButton() {
Office.ribbon.requestUpdate({
tabs: [
{
id: "OfficeAppTab1",
groups: [
{
id: "CustomGroup111",
controls: [
{
id: "MyButton",
enabled: true
}
]
}
]
}
]
});
}
TypeScript
You can await the call of requestUpdate() if the parent function is asynchronous, but
note that the Office application controls when it updates the state of the ribbon. The
requestUpdate() method queues a request to update. The method will resolve the
promise object as soon as it has queued the request, not when the ribbon actually
updates.
JavaScript
Office.onReady(async () => {
await Excel.run(context => {
const charts = context.workbook.worksheets
.getActiveWorksheet()
.charts;
charts.onActivated.add(enableChartFormat);
charts.onDeactivated.add(disableChartFormat);
return context.sync();
});
});
Third, define the enableChartFormat handler. The following is a simple example, but see
Best practice: Test for control status errors below for a more robust way of changing a
control's status.
JavaScript
function enableChartFormat() {
const button = {
id: "ChartFormatButton",
enabled: true
};
const parentGroup = {
id: "MyGroup",
controls: [button]
};
const parentTab = {
id: "CustomChartTab",
groups: [parentGroup]
};
const ribbonUpdater = {tabs: [parentTab]};
Office.ribbon.requestUpdate(ribbonUpdater);
}
1. Whenever requestUpdate is called, the code should record the intended state of
the custom buttons and menu items.
2. When a custom control is clicked, the first code in the handler, should check to see
if the button should have been clickable. If shouldn't have been, the code should
report or log an error and try again to set the buttons to the intended state.
The following example shows a function that disables a button and records the button's
status. Note that chartFormatButtonEnabled is a global boolean variable that is initialized
to the same value as the Enabled element for the button in the manifest.
JavaScript
function disableChartFormat() {
const button = {
id: "ChartFormatButton",
enabled: false
};
const parentGroup = {
id: "MyGroup",
controls: [button]
};
const parentTab = {
id: "CustomChartTab",
groups: [parentGroup]
};
const ribbonUpdater = {tabs: [parentTab]};
Office.ribbon.requestUpdate(ribbonUpdater);
chartFormatButtonEnabled = false;
}
The following example shows how the button's handler tests for an incorrect state of the
button. Note that reportError is a function that shows or logs an error.
JavaScript
function chartFormatButtonHandler() {
if (chartFormatButtonEnabled) {
// Do work here
} else {
// Report the error and try again to disable.
reportError("That action is not possible at this time.");
disableChartFormat();
}
}
Error handling
In some scenarios, Office is unable to update the ribbon and will return an error. For
example, if the add-in is upgraded and the upgraded add-in has a different set of
custom add-in commands, then the Office application must be closed and reopened.
Until it is, the requestUpdate method will return the error HostRestartNeeded . The
following is an example of how to handle this error. In this case, the reportError
method displays the error to the user.
JavaScript
function disableChartFormat() {
try {
const button = {
id: "ChartFormatButton",
enabled: false
};
const parentGroup = {
id: "MyGroup",
controls: [button]
};
const parentTab = {
id: "CustomChartTab",
groups: [parentGroup]
};
const ribbonUpdater = {tabs: [parentTab]};
Office.ribbon.requestUpdate(ribbonUpdater);
chartFormatButtonEnabled = false;
}
catch(error) {
if (error.code == "HostRestartNeeded"){
reportError("Contoso Awesome Add-in has been upgraded. Please
save your work, close the Office application, and restart it.");
}
}
}
Integrate built-in Office buttons into
custom control groups and tabs
Article • 04/04/2023
You can insert built-in Office buttons into your custom control groups on the Office
ribbon by using markup in the add-in's manifest. (You can't insert your custom add-in
commands into a built-in Office group.) You can also insert entire built-in Office control
groups into your custom ribbon tabs.
7 Note
This article assumes that you are familiar with the article Basic concepts for add-in
commands. Please review it if you haven't done so recently.
) Important
The add-in feature and markup described in this article is only available in
PowerPoint on the web.
The markup described in this article only works on platforms that support
requirement set AddinCommands 1.3. See the later section Behavior on
unsupported platforms.
The following markup example adds the Office Paragraph control group to a custom tab
and positions it to appear just after a custom group.
XML
<ExtensionPoint xsi:type="ContosoRibbonTab">
<CustomTab id="Contoso.TabCustom1">
<Group id="Contoso.myCustomTab.group1">
<!-- additional markup omitted -->
</Group>
<OfficeGroup id="Paragraph" />
<Label resid="customTabLabel1" />
</CustomTab>
</ExtensionPoint>
The following markup example adds the Office Superscript control to a custom group
and positions it to appear just after a custom button.
XML
<ExtensionPoint xsi:type="ContosoRibbonTab">
<CustomTab id="Contoso.TabCustom2">
<Group id="Contoso.TabCustom2.group1">
<Label resid="residCustomTabGroupLabel"/>
<Icon>
<bt:Image size="16" resid="blue-icon-16" />
<bt:Image size="32" resid="blue-icon-32" />
<bt:Image size="80" resid="blue-icon-80" />
</Icon>
<Control xsi:type="Button" id="Contoso.Button1">
<!-- information on the control omitted -->
</Control>
<OfficeControl id="Superscript" />
<!-- other controls, as needed -->
</Group>
<Label resid="customTabLabel1" />
</CustomTab>
</ExtensionPoint>
7 Note
Users can customize the ribbon in the Office application. Any user customizations
will override your manifest settings. For example, a user can remove a button from
any group and remove any group from a tab.
Find the IDs of controls and control groups
The IDs for supported controls and control groups are in files in the repo Office Control
IDs . Follow the instructions in the ReadMe file of that repo.
You can specify where you want your add-in's custom tab to appear on the Office
application's ribbon by using markup in the add-in's manifest.
7 Note
This article assumes that you are familiar with the article Basic concepts for add-in
commands. Please review it if you have not done so recently.
) Important
The add-in feature and markup described in this article is only available in
PowerPoint on the web.
The markup described in this article only works on platforms that support
requirement set AddinCommands 1.3. See Behavior on unsupported
platforms below.
Specify where you want a custom tab to appear by identifying which built-in Office tab
you want it to be next to and specifying whether it should be on the left or right side of
the built-in tab. Make these specifications by including either an InsertBefore (left) or an
InsertAfter (right) element in the CustomTab element of your add-in's manifest. (You
cannot have both elements.)
In the following example, the custom tab is configured to appear just after the Review
tab. Note that the value of the <InsertAfter> element is the ID of the built-in Office tab.
XML
<ExtensionPoint xsi:type="ContosoRibbonTab">
<CustomTab id="Contoso.TabCustom2">
<Group id="Contoso.TabCustom2.group2">
<!-- additional markup omitted -->
</Group>
<Label resid="customTabLabel1" />
<InsertAfter>TabReview</InsertAfter>
</CustomTab>
</ExtensionPoint>
) Important
Giving excessive prominence to your add-in inconveniences and annoys users and
administrators. Do not position a custom tab before the Home tab unless your
add-in is the primary way users will interact with the document.
Content add-ins are surfaces that can be embedded directly into Excel or PowerPoint
documents. Content add-ins give users access to interface controls that run code to
modify documents or display data from a data source. Use content add-ins when you
want to embed functionality directly into the document.
Best practices
Include some navigational or commanding element such as the CommandBar or
Pivot at the top of your add-in.
Include a branding element such as the BrandBar at the bottom of your add-in
(applies to Excel and PowerPoint add-ins only).
Variants
Content add-in sizes for Excel and PowerPoint in Office desktop and in a web browser
are user specified.
Personality menu
Personality menus can obstruct navigational and commanding elements located near
the top right of the add-in. The following are the current dimensions of the personality
menu on Windows and Mac.
For Mac, the personality menu measures 26x26 pixels, but floats 8 pixels in from the
right and 6 pixels from the top, which increases the occupied space to 34x32 pixels, as
shown.
For a sample that implements a content add-in, see Excel Content Add-in Humongous
Insurance in GitHub.
Support considerations
Check to see if your Office Add-in will work on a specific Office application or
platform.
Some content add-ins may require the user to "trust" the add-in to read and write
to Excel or PowerPoint. You can declare what level of permissions you want your
user to have in the add-in's manifest.
See also
Office client application and platform availability for Office Add-ins
Fabric Core in Office Add-ins
UX design patterns for Office Add-ins
Requesting permissions for API use in add-ins
Use the Office dialog API in Office Add-
ins
Article • 03/21/2023
Use the Office dialog API to open dialog boxes in your Office Add-in. This article
provides guidance for using the dialog API in your Office Add-in. Consider opening a
dialog box from a task pane, content add-in, or add-in command to do the following:
Sign in a user with a resource such as Google, Facebook, or Microsoft identity. For
more information, see Authenticate with the Office dialog API.
Provide more screen space, or even a full screen, for some tasks in your add-in.
Host a video that would be too small if confined to a task pane.
7 Note
To open a dialog box, your code, typically a page in a task pane, calls the
displayDialogAsync method and passes to it the URL of the resource that you want to
open. The page on which this method is called is known as the "host page". For
example, if you call this method in script on index.html in a task pane, then index.html is
the host page of the dialog box that the method opens.
The resource that is opened in the dialog box is usually a page, but it can be a controller
method in an MVC application, a route, a web service method, or any other resource. In
this article, 'page' or 'website' refers to the resource in the dialog box. The following
code is a simple example.
JavaScript
Office.context.ui.displayDialogAsync('https://www.contoso.com/myDialog.html'
);
The URL uses the HTTPS protocol. This is mandatory for all pages loaded in a
dialog box, not just the first page loaded.
The dialog box's domain is the same as the domain of the host page, which can be
the page in a task pane or the function file of an add-in command. It is required
that the page, controller method, or other resource that is passed to the
displayDialogAsync method must be in the same domain as the host page.
) Important
The host page and the resource that opens in the dialog box must have the same
full domain. If you attempt to pass displayDialogAsync a subdomain of the add-in's
domain, it will not work. The full domain, including any subdomain, must match.
After the first page (or other resource) is loaded, a user can use links or other UI to
navigate to any website (or other resource) that uses HTTPS. You can also design the
first page to immediately redirect to another site.
By default, the dialog box will occupy 80% of the height and width of the device screen,
but you can set different percentages by passing a configuration object to the method,
as shown in the following example.
JavaScript
Office.context.ui.displayDialogAsync('https://www.contoso.com/myDialog.html'
, {height: 30, width: 20});
For a sample add-in that does this, see Build Office Add-ins for Excel . For more
samples that use displayDialogAsync , see Code samples.
Set both values to 100% to get what is effectively a full screen experience. The effective
maximum is 99.5%, and the window is still moveable and resizable.
You can open only one dialog box from a host window. An attempt to open another
dialog box generates an error. For example, if a user opens a dialog box from a task
pane, they can't open a second dialog box from a different page in the task pane.
However, when a dialog box is opened from an add-in command, the command opens
a new (but unseen) HTML file each time it is selected. This creates a new (unseen) host
window, so each such window can launch its own dialog box. For more information, see
Errors from displayDialogAsync.
JavaScript
Office.context.ui.displayDialogAsync('https://www.contoso.com/myDialog.html'
, {height: 30, width: 20, displayInIframe: true});
The default value is false , which is the same as omitting the property entirely. If the
add-in isn't running in Office on the web, the displayInIframe is ignored.
7 Note
You should not use displayInIframe: true if the dialog box will at any point
redirect to a page that can't be opened in an iframe. For example, the sign in pages
of many popular web services, such as Google and Microsoft account, can't be
opened in an iframe.
7 Note
For clarity, in this section we call the message target the host page, but strictly
speaking the messages are going to the Runtime in the task pane (or the runtime
that is hosting a function file). The distinction is only significant in the case of
cross-domain messaging. For more information, see Cross-domain messaging to
the host runtime.
The following example shows how to initialize Office JS and send a message to the host
page.
JavaScript
Office.onReady(function() {
// Add any initialization code for your dialog here.
});
The next example shows how to return a JSON string containing profile information.
JavaScript
function userProfileSignedIn(profile) {
const profileMessage = {
"name": profile.name,
"email": profile.email,
};
Office.context.ui.messageParent(JSON.stringify(profileMessage));
}
The messageParent function is one of only two Office JS APIs that can be called in the
dialog box. The other JS API that can be called in the dialog box is
Office.context.requirements.isSetSupported . For information about it, see Specify
Office applications and API requirements. However, in the dialog box, this API isn't
supported in volume-licensed perpetual Outlook 2016 (that is, the MSI version).
The host page must be configured to receive the message. You do this by adding a
callback parameter to the original call of displayDialogAsync . The callback assigns a
handler to the DialogMessageReceived event. The following is an example.
JavaScript
Office passes an AsyncResult object to the callback. It represents the result of the
attempt to open the dialog box. It does not represent the outcome of any events in the
dialog box. For more on this distinction, see Handle errors and events.
The value property of the asyncResult is set to a Dialog object, which exists in the
host page, not in the dialog box's execution context.
The processMessage is the function that handles the event. You can give it any
name you want.
The dialog variable is declared at a wider scope than the callback because it is
also referenced in processMessage .
JavaScript
function processMessage(arg) {
const messageFromDialog = JSON.parse(arg.message);
showUserName(messageFromDialog.name);
}
Office passes the arg object to the handler. Its message property is the string sent by
the call of messageParent in the dialog box. In this example, it is a stringified
representation of a user's profile from a service, such as Microsoft account or Google, so
it's deserialized back to an object with JSON.parse . The showUserName implementation
isn't shown. It might display a personalized welcome message on the task pane.
When the user interaction with the dialog box is completed, your message handler
should close the dialog box, as shown in this example.
JavaScript
function processMessage(arg) {
dialog.close();
// message processing code goes here;
}
The dialog object must be the same one that is returned by the call of
displayDialogAsync . You need to declare the dialog object as a global variable. Or you
can scope the dialog object to the displayDialogAsync call with an anonymous callback
function as shown in the following example. In the example, processMessage does not
need to close the dialog since the close method is called in the anonymous callback
function.
JavaScript
Office.context.ui.displayDialogAsync('https://www.contoso.com/myDialog.html'
, {height: 30, width: 20},
function (asyncResult) {
const dialog = asyncResult.value;
dialog.addEventHandler(Office.EventType.DialogMessageReceived, (arg)
=> {
dialog.close();
processMessage(arg);
});
}
);
If the add-in needs to open a different page of the task pane after receiving the
message, you can use the window.location.replace method (or window.location.href )
as the last line of the handler. The following is an example.
JavaScript
function processMessage(arg) {
// message processing code goes here;
window.location.replace("/newPage.html");
// Alternatively ...
// window.location.href = "/newPage.html";
}
For an example of an add-in that does this, see the Insert Excel charts using Microsoft
Graph in a PowerPoint add-in sample.
Conditional messaging
Because you can send multiple messageParent calls from the dialog box, but you have
only one handler in the host page for the DialogMessageReceived event, the handler
must use conditional logic to distinguish different messages. For example, if the dialog
box prompts a user to sign in to an identity provider such as Microsoft account or
Google, it sends the user's profile as a message. If authentication fails, the dialog box
sends error information to the host page, as in the following example.
JavaScript
if (loginSuccess) {
const userProfile = getProfile();
const messageObject = {messageType: "signinSuccess", profile:
userProfile};
const jsonMessage = JSON.stringify(messageObject);
Office.context.ui.messageParent(jsonMessage);
} else {
const errorDetails = getError();
const messageObject = {messageType: "signinFailure", error:
errorDetails};
const jsonMessage = JSON.stringify(messageObject);
Office.context.ui.messageParent(jsonMessage);
}
The loginSuccess variable would be initialized by reading the HTTP response from
the identity provider.
The implementation of the getProfile and getError functions is not shown. They
each get data from a query parameter or from the body of the HTTP response.
Anonymous objects of different types are sent depending on whether the sign in
was successful. Both have a messageType property, but one has a profile property
and the other has an error property.
The handler code in the host page uses the value of the messageType property to branch
as shown in the following example. Note that the showUserName function is the same as
in the previous example and showNotification function displays the error in the host
page's UI.
JavaScript
function processMessage(arg) {
const messageFromDialog = JSON.parse(arg.message);
if (messageFromDialog.messageType === "signinSuccess") {
dialog.close();
showUserName(messageFromDialog.profile.name);
window.location.replace("/newPage.html");
} else {
dialog.close();
showNotification("Unable to authenticate user: " +
messageFromDialog.error);
}
}
7 Note
JavaScript
Office.context.ui.messageParent("Some message", { targetOrigin:
"https://resource.contoso.com" });
If the message doesn't include sensitive data, you can set the targetOrigin to "*" which
allows it to be sent to any domain. The following is an example.
JavaScript
Tip
[HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\16.0\WEF\AllowedDialogComm
unicationDomains]
"My trusted domain"="https://www.contoso.com"
"Another trusted domain"="https://fabrikam.com"
JavaScript
function processMessage(arg) {
dialog.close();
This Dialog object has a messageChild method that sends any string, including
stringified data, to the dialog box. This raises a DialogParentMessageReceived event in
the dialog box. Your code should handle this event, as shown in the next section.
Consider a scenario in which the UI of the dialog is related to the currently active
worksheet and that worksheet's position relative to the other worksheets. In the
following example, sheetPropertiesChanged sends Excel worksheet properties to the
dialog box. In this case, the current worksheet is named "My Sheet" and it's the second
sheet in the workbook. The data is encapsulated in an object and stringified so that it
can be passed to messageChild .
JavaScript
function sheetPropertiesChanged() {
const messageToDialog = JSON.stringify({
name: "My Sheet",
position: 2
});
dialog.messageChild(messageToDialog);
}
JavaScript
Office.onReady(function () {
Office.context.ui.addHandlerAsync(Office.EventType.DialogParentMessageReceiv
ed,
onMessageFromParent);
});
Then, define the onMessageFromParent handler. The following code continues the
example from the preceding section. Note that Office passes an argument to the
handler and that the message property of the argument object contains the string from
the host page. In this example, the message is reconverted to an object and jQuery is
used to set the top heading of the dialog to match the new worksheet name.
JavaScript
function onMessageFromParent(arg) {
const messageFromParent = JSON.parse(arg.message);
document.querySelector('h1').textContent = messageFromParent.name;
}
It's best practice to verify that your handler is properly registered. You can do this by
passing a callback to the addHandlerAsync method. This runs when the attempt to
register the handler completes. Use the handler to log or show an error if the handler
was not successfully registered. The following is an example. Note that reportError is a
function, not defined here, that logs or displays the error.
JavaScript
Office.onReady(function () {
Office.context.ui.addHandlerAsync(
Office.EventType.DialogParentMessageReceived,
onMessageFromParent,
onRegisterMessageComplete);
});
function onRegisterMessageComplete(asyncResult) {
if (asyncResult.status !== Office.AsyncResultStatus.Succeeded) {
reportError(asyncResult.error.message);
}
}
Conditional messaging from parent page to dialog box
Because you can make multiple messageChild calls from the host page, but you have
only one handler in the dialog box for the DialogParentMessageReceived event, the
handler must use conditional logic to distinguish different messages. You can do this in
a way that is precisely parallel to how you would structure conditional messaging when
the dialog box is sending a message to the host page as described in Conditional
messaging.
7 Note
In some situations, the messageChild API, which is a part of the DialogApi 1.2
requirement set, may not be supported. Some alternative ways for parent-to-
dialog-box messaging are described in Alternative ways of passing messages to a
dialog box from its host page.
) Important
If the parameter isn't used, Office assumes that the target is the same domain that the
parent runtime is currently hosting.
7 Note
Using messageChild to send a cross-domain message requires the Dialog Origin 1.1
requirement set. The DialogMessageOptions parameter is ignored on older versions
of Office that do not support the requirement set, so the behavior of the method is
unaffected if you pass it.
JavaScript
dialog.messageChild(messageToDialog, { targetOrigin:
"https://resource.contoso.com" });
If the message doesn't include sensitive data, you can set the targetOrigin to "*" which
allows it to be sent to any domain. The following is an example.
JavaScript
Because the runtime that is hosting the dialog can't access the <AppDomains> section
of the manifest and thereby determine whether the domain from which the message
comes is trusted, you must use the DialogParentMessageReceived handler to determine
this. The object that is passed to the handler contains the domain that is currently
hosted in the parent as its origin property. The following is an example of how to use
the property.
JavaScript
function onMessageFromParent(arg) {
if (arg.origin === "https://addin.fabrikam.com") {
// process message
} else {
dialog.close();
showNotification("Messages from " + arg.origin + " are not
accepted.");
}
}
For example, your code could use the Office.onReady or Office.initialize function to store
an array of trusted domains in a global variable. The arg.origin property could then be
checked against that list in the handler.
Tip
The DialogMessageOptions parameter was added to the messageChild method as a
required parameter in mid-2021. Older add-ins that send a cross-domain message
with the method no longer work until they are updated to use the new parameter.
Until the add-in is updated, in Office on Windows only, users and system
administrators can enable those add-ins to continue working by specifying the
trusted domains with a registry setting:
HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\16.0\WEF\AllowedDialogCo
mmunicationDomains. To do this, create a file with a .reg extension, save it to the
Windows computer, and then double-click it to run it. The following is an example
of the contents of such a file.
[HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\16.0\WEF\AllowedDialogComm
unicationDomains]
"My trusted domain"="https://www.contoso.com"
"Another trusted domain"="https://fabrikam.com"
JavaScript
function closeButtonClick() {
const messageObject = {messageType: "dialogClosed"};
const jsonMessage = JSON.stringify(messageObject);
Office.context.ui.messageParent(jsonMessage);
}
The host page handler for DialogMessageReceived would call dialog.close , as in this
example. (See previous examples that show how the dialog object is initialized.)
JavaScript
function processMessage(arg) {
const messageFromDialog = JSON.parse(arg.message);
if (messageFromDialog.messageType === "dialogClosed") {
dialog.close();
}
}
Even when you don't have your own close-dialog UI, an end user can close the dialog
box by choosing the X in the upper-right corner. This action triggers the
DialogEventReceived event. If your host pane needs to know when this happens, it
should declare a handler for this event. See the section Errors and events in the dialog
box for details.
Code samples
All of the following samples use displayDialogAsync . Some have NodeJS-based servers
and others have ASP.NET/IIS-based servers, but the logic of using the method is the
same regardless of how the server-side of the add-in is implemented.
See also
Dialog API requirement sets
Best practices and rules for the Office dialog API
Authenticate with the Office dialog API
Use the Office dialog box to show a video
Handling errors and events in the Office dialog box
Runtimes in Office Add-ins
Best practices and rules for the Office
dialog API
Article • 04/04/2023
This article provides rules, gotchas, and best practices for the Office dialog API, including
best practices for designing the UI of a dialog and using the API with in a single-page
application (SPA)
7 Note
This article presupposes that you are familiar with the basics of using the Office
dialog API as described in Use the Office dialog API in your Office Add-ins.
See also Handling errors and events with the Office dialog box.
Best practices
If the user chooses Allow, the Office dialog box opens. If the user chooses Ignore, the
prompt closes and the Office dialog box does not open. Instead, the
displayDialogAsync method returns error 12009. Your code should catch this error and
either provide an alternate experience that does not require a dialog, or display a
message to the user advising that the add-in requires them to allow the dialog. (For
more about 12009, see Errors from displayDialogAsync.)
If, for any reason, you want to turn off this feature, then your code must opt out. It
makes this request with the DialogOptions object that is passed to the
displayDialogAsync method. Specifically, the object should include promptBeforeOpen:
false . When this option is set to false, Office on the web will not prompt the user to
allow the add-in open a dialog, and the Office dialog will not open.
completely closed when Office attempts to open the second. If that happens, Office will
return a 12007 error: "The operation failed because this add-in already has an active
dialog."
The close method doesn't accept a callback parameter, and it doesn't return a Promise
object so it cannot be awaited with either the await keyword or with a then method.
For this reason, we suggest the following technique when you need to open a new
dialog immediately after closing a dialog: encapsulate the code to open the new dialog
in a function and design the function to recursively call itself if the call of
displayDialogAsync returns 12007 . The following is an example.
JavaScript
function openFirstDialog() {
Office.context.ui.displayDialogAsync("https://MyDomain/firstDialog.html",
{ width: 50, height: 50},
(result) => {
if(result.status === Office.AsyncResultStatus.Succeeded) {
const dialog = result.value;
dialog.close();
openSecondDialog();
}
else {
// Handle errors
}
}
);
}
function openSecondDialog() {
Office.context.ui.displayDialogAsync("https://MyDomain/secondDialog.html",
{ width: 50, height: 50},
(result) => {
if(result.status === Office.AsyncResultStatus.Failed) {
if (result.error.code === 12007) {
openSecondDialog(); // Recursive call
}
else {
// Handle other errors
}
}
}
);
}
Alternatively, you could force the code to pause before it tries to open the second
dialog by using the setTimeout method. The following is an example.
JavaScript
function openFirstDialog() {
Office.context.ui.displayDialogAsync("https://MyDomain/firstDialog.html",
{ width: 50, height: 50},
(result) => {
if(result.status === Office.AsyncResultStatus.Succeeded) {
const dialog = result.value;
dialog.close();
setTimeout(() => {
Office.context.ui.displayDialogAsync("https://MyDomain/secondDialog.html", {
width: 50, height: 50},
(result) => { /* callback body */ }
);
}, 1000);
}
else {
// Handle errors
}
}
);
}
7 Note
So, if you passed a route to the displayDialogAsync method, you wouldn't really have
an SPA; you'd have two instances of the same SPA. Moreover, much of the code in the
task pane instance would never be used in that instance and much of the code in the
dialog box instance would never be used in that instance. It would be like having two
SPAs in the same bundle.
Microsoft recommendations
Instead of passing a client-side route to the displayDialogAsync method, we
recommend that you do one of the following:
If the code that you want to run in the dialog box is sufficiently complex, create
two different SPAs explicitly; that is, have two SPAs in different folders of the same
domain. One SPA runs in the dialog box and the other in the dialog box's host
page where displayDialogAsync was called.
In most scenarios, only simple logic is needed in the dialog box. In such cases, your
project will be greatly simplified by hosting a single HTML page, with embedded or
referenced JavaScript, in the domain of your SPA. Pass the URL of the page to the
displayDialogAsync method. While this means that you are deviating from the
literal idea of a single-page app; you don't really have a single instance of an SPA
when you are using the Office dialog API.
Alternative ways of passing messages to
a dialog box from its host page
Article • 04/04/2023
The recommended way to pass data and messages from a parent page to a child dialog
box is with the messageChild method as described in Use the Office dialog API in your
Office Add-ins. If your add-in is running on a platform or host that does not support the
DialogApi 1.2 requirement set, there are two other ways that you can pass information
to the dialog box.
7 Note
* There is a bug that will effect your strategy for token handling. If the add-in is
running in Office on the web in either the Safari or Edge browser, the dialog box
and task pane do not share the same Local Storage, so it cannot be used to
communicate between them.
JavaScript
localStorage.setItem("clientID", "15963ac5-314f-4d9b-b5a1-ccb2f1aea248");
Code in the dialog box reads the item when it's needed, as in the following example.
JavaScript
JavaScript
Office.context.ui.displayDialogAsync('https://myAddinDomain/myDialog.html?
clientID=15963ac5-314f-4d9b-b5a1-ccb2f1aea248');
For a sample that uses this technique, see Insert Excel charts using Microsoft Graph in a
PowerPoint add-in .
Code in your dialog box can parse the URL and read the parameter value.
) Important
Office automatically adds a query parameter called _host_info to the URL that is
passed to displayDialogAsync . (It is appended after your custom query parameters,
if any. It is not appended to any subsequent URLs that the dialog box navigates to.)
Microsoft may change the content of this value, or remove it entirely, in the future,
so your code should not read it. The same value is added to the dialog box's
session storage (the Window.sessionStorage property). Again, your code should
neither read nor write to this value.
Handle errors and events in the Office
dialog box
Article • 04/04/2023
This article describes how to trap and handle errors when opening the dialog box and
errors that happen inside the dialog box.
7 Note
This article presupposes that you are familiar with the basics of using the Office
dialog API as described in Use the Office dialog API in your Office Add-ins.
See also Best practices and rules for the Office dialog API.
Errors returned by the call of displayDialogAsync because the dialog box cannot
be created.
Errors, and other events, in the dialog box.
Code Meaning
number
12004 The domain of the URL passed to displayDialogAsync is not trusted. The domain must
be the same domain as the host page (including protocol and port number).
12005 The URL passed to displayDialogAsync uses the HTTP protocol. HTTPS is required. (In
some versions of Office, the error message text returned with 12005 is the same one
returned for 12004.)
12007 A dialog box is already opened from this host window. A host window, such as a task
pane, can only have one dialog box open at a time.
12009 The user chose to ignore the dialog box. This error can occur in Office on the web,
where users may choose not to allow an add-in to present a dialog box. For more
information, see Handling pop-up blockers with Office on the web.
Code Meaning
number
12011 The add-in is running in Office on the web and the user's browser configuration is
blocking popups. This most commonly happens when the browser is Edge Legacy and
the domain of the add-in is in different security zone from the domain that the dialog
is trying to open. Another scenario which triggers this error is that the browser is Safari
and it's configured to block all popups. Consider responding to this error with a
prompt to the user to change their browser configuration or use a different browser.
JavaScript
let dialog;
Office.context.ui.displayDialogAsync('https://myDomain/myDialog.html',
function (asyncResult) {
if (asyncResult.status === Office.AsyncResultStatus.Failed) {
showNotification(asyncResult.error.code = ": " +
asyncResult.error.message);
} else {
dialog = asyncResult.value;
dialog.addEventHandler(Office.EventType.DialogMessageReceived,
processMessage);
}
});
12003 The dialog box was directed to a URL with the HTTP protocol. HTTPS is required.
12006 The dialog box was closed, usually because the user chose the Close button X.
Your code can assign a handler for the DialogEventReceived event in the call to
displayDialogAsync . The following is a simple example.
JavaScript
let dialog;
Office.context.ui.displayDialogAsync('https://myDomain/myDialog.html',
function (result) {
dialog = result.value;
dialog.addEventHandler(Office.EventType.DialogEventReceived,
processDialogEvent);
}
);
For an example of a handler for the DialogEventReceived event that creates custom
error messages for each error code, see the following example.
JavaScript
function processDialogEvent(arg) {
switch (arg.error) {
case 12002:
showNotification("The dialog box has been directed to a page
that it cannot find or load, or the URL syntax is invalid.");
break;
case 12003:
showNotification("The dialog box has been directed to a URL with
the HTTP protocol. HTTPS is required."); break;
case 12006:
showNotification("Dialog closed.");
break;
default:
showNotification("Unknown error in dialog box.");
break;
}
}
See also
For a sample add-in that handles errors in this way, see Office Add-in Dialog API
Example .
Use the Office dialog box to show a
video
Article • 04/04/2023
This article explains how to play a video in an Office Add-in dialog box.
7 Note
This article presumes you're familiar with the basics of using the Office dialog box
as described in Use the Office dialog API in your Office Add-ins.
To play a video in a dialog box with the Office dialog API, follow these steps.
1. Create a page containing an iframe and no other content. The page must be in the
same domain as the host page. For a reminder of what a host page is, see Open a
dialog box from a host page. In the src attribute of the iframe, point to the URL of
an online video. The protocol of the video's URL must be HTTPS. In this article,
we'll call this page "video.dialogbox.html". The following is an example of the
markup.
HTML
3. If your add-in needs to know when the user closes the dialog box, register a
handler for the DialogEventReceived event and handle the 12006 event. For details,
see Errors and events in the Office dialog box.
For a sample of a video playing in a dialog box, see the video placemat design pattern.
Task panes in Office Add-ins
Article • 04/04/2023
Task panes are interface surfaces that typically appear on the right side of the window
within Word, PowerPoint, Excel, and Outlook. Task panes give users access to interface
controls that run code to modify documents or emails, or display data from a data
source. Use task panes when you don't need to embed functionality directly into the
document.
Best practices
Do Don't
Include the name of your add-in in the title. Don't append your company name to
the title.
Do Don't
Use short descriptive names in the title. Don't append strings such as "add-in,"
"for Word," or "for Office" to the title of
your add-in.
Variants
The following images show the various task pane sizes with the Office app ribbon at a
1366x768 resolution. For Excel, additional vertical space is required to accommodate the
formula bar.
Personality menu
Personality menus can obstruct navigational and commanding elements located near
the top right of the add-in. The following are the current dimensions of the personality
menu on Windows and Mac. (The personality menu isn't supported in Outlook.)
For Mac, the personality menu measures 26x26 pixels, but floats 8 pixels in from the
right and 6 pixels from the top, which increases the space to 34x32 pixels, as shown.
See also
Fabric Core in Office Add-ins
UX design patterns for Office Add-ins
Add custom keyboard shortcuts to your
Office Add-ins
Article • 03/14/2023
Keyboard shortcuts, also known as key combinations, enable your add-in's users to work
more efficiently. Keyboard shortcuts also improve the add-in's accessibility for users with
disabilities by providing an alternative to the mouse.
) Important
Keyboard shortcuts are currently only supported on Excel and only on these
platforms and builds:
7 Note
Keyboard shortcuts work only on platforms that support the following requirement
sets. For more about requirement sets and how to work with them, see Specify
Office applications and API requirements.
SharedRuntime 1.1
Also needed if the add-in enables the user to customize keyboard shortcuts:
KeyboardShortcuts 1.1
7 Note
XML
...
</VersionOverrides>
<ExtendedOverrides Url="https://contoso.com/addin/shortcuts.json">
</ExtendedOverrides>
</OfficeApp>
1. Inside the JSON file, there are two arrays. The actions array will contain objects that
define the actions to be invoked and the shortcuts array will contain objects that
map key combinations onto actions. Here is an example.
JSON
{
"actions": [
{
"id": "SHOWTASKPANE",
"type": "ExecuteFunction",
"name": "Show task pane for add-in"
},
{
"id": "HIDETASKPANE",
"type": "ExecuteFunction",
"name": "Hide task pane for add-in"
}
],
"shortcuts": [
{
"action": "SHOWTASKPANE",
"key": {
"default": "Ctrl+Alt+Up"
}
},
{
"action": "HIDETASKPANE",
"key": {
"default": "Ctrl+Alt+Down"
}
}
]
}
For more information about the JSON objects, see Construct the action objects
and Construct the shortcut objects. The complete schema for the shortcuts JSON is
at extended-manifest.schema.json.
7 Note
In a later step, the actions will themselves be mapped to functions that you write.
In this example, you will later map SHOWTASKPANE to a function that calls the
Office.addin.showAsTaskpane method and HIDETASKPANE to a function that calls
the Office.addin.hide method.
2. In the JavaScript file, use the Office.actions.associate API to map each action that
you specified in the JSON file to a JavaScript function. Add the following JavaScript
to the file. Note the following about the code.
The first parameter is one of the actions from the JSON file.
The second parameter is the function that runs when a user presses the key
combination that is mapped to the action in the JSON file.
JavaScript
});
JavaScript
Office.actions.associate('SHOWTASKPANE', function () {
return Office.addin.showAsTaskpane()
.then(function () {
return;
})
.catch(function (error) {
return error.code;
});
});
JavaScript
Office.actions.associate('HIDETASKPANE', function () {
return Office.addin.hide()
.then(function () {
return;
})
.catch(function (error) {
return error.code;
});
});
Following the previous steps lets your add-in toggle the visibility of the task pane by
pressing Ctrl+Alt+Up and Ctrl+Alt+Down. The same behavior is shown in the Excel
keyboard shortcuts sample in the Office Add-ins PnP repo in GitHub.
JSON
"actions": [
{
"id": "SHOWTASKPANE",
"type": "ExecuteFunction",
"name": "Show task pane for add-in"
},
{
"id": "HIDETASKPANE",
"type": "ExecuteFunction",
"name": "Hide task pane for add-in"
}
]
JSON
"shortcuts": [
{
"action": "SHOWTASKPANE",
"key": {
"default": "Ctrl+Alt+Up"
}
},
{
"action": "HIDETASKPANE",
"key": {
"default": "Ctrl+Alt+Down"
}
}
]
7 Note
KeyTips, also known as sequential key shortcuts, such as the Excel shortcut to
choose a fill color Alt+H, H, are not supported in Office Add-ins.
Avoid key combinations in use by other add-ins
There are many keyboard shortcuts that are already in use by Office. Avoid registering
keyboard shortcuts for your add-in that are already in use, however there may be some
instances where it's necessary to override existing keyboard shortcuts or handle conflicts
between multiple add-ins that have registered the same keyboard shortcut.
In the case of a conflict, the user will see a dialog box the first time they attempt to use
a conflicting keyboard shortcut. Note that the text for the add-in option that is
displayed in this dialog comes from the name property in the action object in
shortcuts.json file.
The user can select which action the keyboard shortcut will take. After making the
selection, the preference is saved for future uses of the same shortcut. The shortcut
preferences are saved per user, per platform. If the user wishes to change their
preferences, they can invoke the Reset Office Add-ins shortcut preferences command
from the Tell me search box. Invoking the command clears all of the user's add-in
shortcut preferences and the user will again be prompted with the conflict dialog box
the next time they attempt to use a conflicting shortcut.
For the best user experience, we recommend that you minimize conflicts with Excel with
these good practices.
Use only keyboard shortcuts with the following pattern: Ctrl+Shift+Alt+x, where x
is some other key.
If you need more keyboard shortcuts, check the list of Excel keyboard shortcuts ,
and avoid using any of them in your add-in.
When the keyboard focus is inside the add-in UI, Ctrl+Spacebar and
Ctrl+Shift+F10 will not work as these are essential accessibility shortcuts.
On a Windows or Mac computer, if the "Reset Office Add-ins shortcut preferences"
command is not available on the search menu, the user can manually add the
command to the ribbon by customizing the ribbon through the context menu.
In the following example, the default key is the fallback key for any platform that is not
specified. The only platform not specified is Windows, so the default key will only apply
to Windows.
JSON
"shortcuts": [
{
"action": "SHOWTASKPANE",
"key": {
"default": "Ctrl+Alt+Up",
"mac": "Command+Shift+Up",
"web": "Ctrl+Alt+1",
}
},
{
"action": "HIDETASKPANE",
"key": {
"default": "Ctrl+Alt+Down",
"mac": "Command+Shift+Down",
"web": "Ctrl+Alt+2"
}
}
]
Ctrl+N
Ctrl+Shift+N
Ctrl+T
Ctrl+Shift+T
Ctrl+W
Ctrl+PgUp/PgDn
7 Note
The APIs described in this section require the KeyboardShortcuts 1.1 requirement
set.
that must be defined in the add-in's extended manifest JSON. The values are the user's
preferred key combinations. The value can also be null , which will remove any
customization for that actionId and revert back to the default keyboard combination
that is defined in the add-in's extended manifest JSON.
If the user is logged into Office, the custom combinations are saved in the user's
roaming settings per platform. Customizing shortcuts are currently not supported for
anonymous users.
JavaScript
const userCustomShortcuts = {
SHOWTASKPANE:"CTRL+SHIFT+1",
HIDETASKPANE:"CTRL+SHIFT+2"
};
Office.actions.replaceShortcuts(userCustomShortcuts)
.then(function () {
console.log("Successfully registered.");
})
.catch(function (ex) {
if (ex.code == "InvalidOperation") {
console.log("ActionId does not exist or shortcut combination is
invalid.");
}
});
To find out what shortcuts are already in use for the user, call the
Office.actions.getShortcuts method. This method returns an object of type
[actionId:string]:string|null} , where the values represent the current keyboard
combination the user must use to invoke the specified action. The values can come from
three different sources:
If there was a conflict with the shortcut and the user has chosen to use a different
action (either native or another add-in) for that keyboard combination, the value
returned will be null since the shortcut has been overridden and there is no
keyboard combination the user can currently use to invoke that add-in action.
If the shortcut has been customized using the Office.actions.replaceShortcuts
method, the value returned will be the customized keyboard combination.
If the shortcut has not been overridden or customized, it will return the value from
the add-in's extended manifest JSON.
JavaScript
Office.actions.getShortcuts()
.then(function (userShortcuts) {
for (const action in userShortcuts) {
let shortcut = userShortcuts[action];
console.log(action + ": " + shortcut);
}
});
JavaScript
) Important
The shared runtime is only supported in some Office applications. For more
information, see Shared runtime requirement sets.
You can show the task pane of your Office Add-in by calling the
Office.addin.showAsTaskpane() method.
JavaScript
function onCurrentQuarter() {
Office.addin.showAsTaskpane()
.then(function() {
// Code that enables task pane UI elements for
// working with the current quarter.
});
}
The previous code assumes a scenario where there is an Excel worksheet named
CurrentQuarterSales. The add-in will make the task pane visible whenever this
worksheet is activated. The method onCurrentQuarter is a handler for the
Office.Worksheet.onActivated event which has been registered for the worksheet.
You can also hide the task pane by calling the Office.addin.hide() method.
JavaScript
function onCurrentQuarterDeactivated() {
Office.addin.hide();
}
using.
Consider the following scenario: A task pane is designed with tabs. The Home tab is
open when the add-in is first launched. Suppose a user opens the Settings tab and,
later, code in the task pane calls hide() in response to some event. Still later code calls
showAsTaskpane() in response to another event. The task pane will reappear, and the
Settings tab is still selected.
In addition, any event listeners that are registered in the task pane continue to run even
when the task pane is hidden.
Consider the following scenario: The task pane has a registered handler for the Excel
Worksheet.onActivated and Worksheet.onDeactivated events for a sheet named Sheet1.
The activated handler causes a green dot to appear in the task pane. The deactivated
handler turns the dot red (which is its default state). Suppose then that code calls
hide() when Sheet1 is not activated and the dot is red. While the task pane is hidden,
Sheet1 is activated. Later code calls showAsTaskpane() in response to some event. When
the task pane opens, the dot is green because the event listeners and handlers ran even
though the task pane was hidden.
JavaScript
Office.addin.onVisibilityModeChanged(function(args) {
if (args.visibilityMode == "Taskpane") {
// Code that runs whenever the task pane is made visible.
// For example, an Excel.run() that loads the names of
// all worksheets and passes them to the task pane UI.
}
});
The function returns another function that deregisters the handler. Here is a simple, but
not robust, example.
JavaScript
const removeVisibilityModeHandler =
Office.addin.onVisibilityModeChanged(function(args) {
if (args.visibilityMode == "Taskpane") {
// Code that runs whenever the task pane is made visible.
}
});
JavaScript
JavaScript
See also
Configure your Office Add-in to use a shared runtime
Run code in your Office Add-in when the document opens
Localization for Office Add-ins
Article • 07/27/2023
You can implement any localization scheme that's appropriate for your Office Add-in.
The JavaScript API and manifest schema of the Office Add-ins platform provide some
choices. You can use the Office JavaScript API to determine a locale and display strings
based on the locale of the Office application, or to interpret or display data based on
the locale of the data. You can use the manifest to specify locale-specific add-in file
location and descriptive information. Alternatively, you can use Visual Studio and
Microsoft Ajax script to support globalization and localization.
JavaScript
function sayHelloWithDisplayLanguage() {
const myLanguage = Office.context.displayLanguage;
switch (myLanguage) {
case 'en-US':
write('Hello!');
break;
case 'fr-FR':
write('Bonjour!');
break;
}
}
JavaScript
XML Manifest
Every Office Add-in specifies a DefaultLocale element and a locale in its manifest. By
default, the Office Add-in platform and Office client applications apply the values of
the Description, DisplayName, IconUrl, HighResolutionIconUrl, and SourceLocation
elements to all locales. You can optionally support specific values for specific
locales, by specifying an Override child element for each additional locale, for any
of these five elements. The value for the DefaultLocale element and for the Locale
attribute of the Override element is specified according to RFC 3066 , "Tags for the
Identification of Languages." Table 1 describes the localizing support for these
elements.
IconUrl The icon image is optional. You can use the same
override technique to specify a certain image for a
specific culture. If you use and localize an icon, users in
each locale you specify can see a localized icon image for
the add-in.
For Outlook add-ins, users can see the icon in the EAC
after installing the add-in.
For content and task pane add-ins, users can see the
icon on the ribbon after installing the add-in.
Resources Important: This Users in each locale you specify can see string and icon
element is available only when resources that you specifically create for the add-in for
using add-in manifest version that locale.
1.1.
SourceLocation Users in each locale you specify can see a webpage that
you specifically design for the add-in for that locale.
7 Note
You can localize the description and display name for only the locales that
Office supports. See Overview of deploying languages for Microsoft 365
Apps for a list of languages and locales for the current release of Office.
Examples
For example, an Office Add-in can specify the DefaultLocale as en-us . For the
DisplayName element, the add-in can specify an Override child element for the
locale fr-fr , as shown below.
XML
<DefaultLocale>en-us</DefaultLocale>
...
<DisplayName DefaultValue="Video player">
<Override Locale="fr-fr" Value="Lecteur vidéo" />
</DisplayName>
7 Note
If you need to localize for more than one area within a language family, such
as de-de and de-at , we recommend that you use separate Override elements
for each area. Using the language name alone, in this case, de , is not
supported across all combinations of Office client applications and platforms.
This means that the add-in assumes the en-us locale by default. Users see the
English display name of "Video player" for all locales unless the client computer's
locale is fr-fr , in which case users would see the French display name "Lecteur
vidéo".
7 Note
You may only specify a single override per language, including for the default
locale. For example, if your default locale is en-us you cannot not specify an
override for en-us as well.
The following example applies a locale override for the Description element. It first
specifies a default locale of en-us and an English description, and then specifies an
Override statement with a French description for the fr-fr locale.
XML
<DefaultLocale>en-us</DefaultLocale>
...
<Description DefaultValue=
"Watch YouTube videos referenced in the emails you receive
without leaving your email client.">
<Override Locale="fr-fr" Value=
"Visualisez les vidéos YouTube référencées dans vos courriers
électronique directement depuis Outlook."/>
</Description>
This means that the add-in assumes the en-us locale by default. Users would see
the English description in the DefaultValue attribute for all locales unless the client
computer's locale is fr-fr , in which case they would see the French description.
In the following example, the add-in specifies a separate image that's more
appropriate for the fr-fr locale and culture. Users see the image DefaultLogo.png
by default, except when the locale of the client computer is fr-fr . In this case,
users would see the image FrenchLogo.png.
XML
<!-- Replace "domain" with a real web server name and path. -->
<IconUrl DefaultValue="https://<domain>/DefaultLogo.png"/>
<Override Locale="fr-fr" Value="https://<domain>/FrenchLogo.png"/>
The following example shows how to localize a resource in the Resources section. It
applies a locale override for an image that is more appropriate for the ja-jp
culture.
XML
<Resources>
<bt:Images>
<bt:Image id="icon1_16x16"
DefaultValue="https://www.contoso.com/icon_default.png">
<bt:Override Locale="ja-jp" Value="https://www.contoso.com/ja-
jp16-icon_default.png" />
</bt:Image>
...
For Outlook add-ins, the SourceLocation element also aligns to the form factor. This
allows you to provide a separate, localized source HTML file for each corresponding
form factor. You can specify one or more Override child elements in each applicable
settings element (DesktopSettings, TabletSettings, or PhoneSettings). The following
example shows settings elements for the desktop, tablet, and smartphone form
factors, each with one HTML file for the default locale and another for the French
locale.
XML
<DesktopSettings>
<SourceLocation DefaultValue="https://contoso.com/Desktop.html">
<Override Locale="fr-fr"
Value="https://contoso.com/fr/Desktop.html" />
</SourceLocation>
<RequestedHeight>250</RequestedHeight>
</DesktopSettings>
<TabletSettings>
<SourceLocation DefaultValue="https://contoso.com/Tablet.html">
<Override Locale="fr-fr"
Value="https://contoso.com/fr/Tablet.html" />
</SourceLocation>
<RequestedHeight>200</RequestedHeight>
</TabletSettings>
<PhoneSettings>
<SourceLocation DefaultValue="https://contoso.com/Mobile.html">
<Override Locale="fr-fr"
Value="https://contoso.com/fr/Mobile.html" />
</SourceLocation>
</PhoneSettings>
7 Note
This section is not applicable if you are using the unified manifest (preview).
Some extensibility features of Office Add-ins, such as keyboard shortcuts, are configured
with JSON files that are hosted on your server, instead of with the add-in's XML
manifest. This section assumes that you're familiar with extended overrides. See Work
with extended overrides of the manifest and ExtendedOverrides element.
Use the ResourceUrl attribute of the ExtendedOverrides element to point Office to a file
of localized resources. The following is an example.
XML
...
</VersionOverrides>
<ExtendedOverrides Url="https://contoso.com/addin/extended-
overrides.json"
ResourceUrl="https://contoso.com/addin/my-
resources.json">
</ExtendedOverrides>
</OfficeApp>
The extended overrides file then uses tokens instead of strings. The tokens name strings
in the resource file. The following is an example that assigns a keyboard shortcut to a
function (defined elsewhere) that displays the add-in's task pane. Note about this
markup:
The example isn't quite valid. (We add a required additional property to it below.)
The tokens must have the format ${resource.name-of-resource}.
JSON
{
"actions": [
{
"id": "SHOWTASKPANE",
"type": "ExecuteFunction",
"name": "${resource.SHOWTASKPANE_action_name}"
}
],
"shortcuts": [
{
"action": "SHOWTASKPANE",
"key": {
"default": "${resource.SHOWTASKPANE_default_shortcut}"
}
}
]
}
The resource file, which is also JSON-formatted, has a top-level resources property that
is divided into subproperties by locale. For each locale, a string is assigned to each
token that was used in the extended overrides file. The following is an example which
has strings for en-us and fr-fr . In this example, the keyboard shortcut is the same in
both locales, but that won't always be the case, especially when you are localizing for
locales that have a different alphabet or writing system, and hence a different keyboard.
JSON
{
"resources":{
"en-us": {
"SHOWTASKPANE_default_shortcut": {
"value": "CTRL+SHIFT+A",
},
"SHOWTASKPANE_action_name": {
"value": "Show task pane for add-in",
},
},
"fr-fr": {
"SHOWTASKPANE_default_shortcut": {
"value": "CTRL+SHIFT+A",
},
"SHOWTASKPANE_action_name": {
"value": "Afficher le volet de tâche pour add-in",
}
}
}
}
There is no default property in the file that is a peer to the en-us and fr-fr sections.
This is because the default strings, which are used when the locale of the Office host
application doesn't match any of the ll-cc properties in the resources file, must be
defined in the extended overrides file itself. Defining the default strings directly in the
extended overrides file ensures that Office doesn't download the resource file when the
locale of the Office application matches the default locale of the add-in (as specified in
the manifest). The following is a corrected version of the preceding example of an
extended overrides file that uses resource tokens.
JSON
{
"actions": [
{
"id": "SHOWTASKPANE",
"type": "ExecuteFunction",
"name": "${resource.SHOWTASKPANE_action_name}"
}
],
"shortcuts": [
{
"action": "SHOWTASKPANE",
"key": {
"default": "${resource.SHOWTASKPANE_default_shortcut}"
}
}
],
"resources": {
"default": {
"SHOWTASKPANE_default_shortcut": {
"value": "CTRL+SHIFT+A",
},
"SHOWTASKPANE_action_name": {
"value": "Show task pane for add-in",
}
}
}
}
Match date/time format with client locale
You can get the locale of the user interface of the Office client application by using the
displayLanguage property. You can then display date and time values in a format
consistent with the current locale of the Office application. One way to do that is to
prepare a resource file that specifies the date/time display format to use for each locale
that your Office Add-in supports. At run time, your add-in can use the resource file and
match the appropriate date/time format with the locale obtained from the
displayLanguage property.
You can get the locale of the data of the Office client application by using the
contentLanguage property. Based on this value, you can then appropriately interpret or
display date/time strings. For example, the jp-JP locale expresses data/time values as
yyyy/MM/dd , and the fr-FR locale, dd/MM/yyyy .
You can globalize and use the Date and Number JavaScript type extensions and the
JavaScript Date object in the JavaScript code for an Office Add-in to display values
based on the locale settings on the current browser. For more information, see
Walkthrough: Globalizing a Date by Using Client Script.
You can include localized resource strings directly in standalone JavaScript files to
provide client script files for different locales, which are set on the browser or provided
by the user. Create a separate script file for each supported locale. In each script file,
include an object in JSON format that contains the resource strings for that locale. The
localized values are applied when the script runs in the browser.
7 Note
To download Visual Studio, see the Visual Studio IDE page . During installation
you'll need to select the Office/SharePoint development workload.
To run the sample code provided, configure Office on your computer to use additional
languages so that you can test your add-in by switching the language used for display
in menus and commands, for editing and proofing, or both.
You can use an Office Language pack to install an additional language. For more
information about Language Packs and where to get them, see Language Accessory
Pack for Office .
After you install the Language Accessory Pack, you can configure Office to use the
installed language for display in the UI, for editing document content, or both. The
example in this article uses an installation of Office that has the Spanish Language Pack
applied.
7 Note
If you haven't installed Visual Studio, see the Visual Studio IDE page for
download instructions. During installation you'll need to select the
Office/SharePoint development workload. If you have previously installed Visual
Studio 2019 or later, use the Visual Studio Installer to ensure that the
Office/SharePoint development workload is installed.
2. Using the search box, enter add-in. Choose Word Web Add-in, then select Next.
4. Visual Studio creates a solution and its two projects appear in Solution Explorer.
The Home.html file opens in Visual Studio.
Add-in display name and description. This is controlled by entries in the add-in
manifest file.
Add-in UI. You can localize the strings that appear in your add-in UI by using
JavaScript code, for example, by using a separate resource file that contains the
localized strings.
7 Note
You can replace the Spanish language localized strings used in this example
for the DisplayName and Description elements with the localized strings for
any other language.
XML
3. When you change the display language for Microsoft 365 from English to Spanish,
for example, and then run the add-in, the add-in display name and description are
shown with localized text.
2. Replace the <body> element contents in Home.html with the following HTML, and
save the file.
HTML
<body>
<!-- Page content -->
<div id="content-header" class="ms-bgColor-themePrimary ms-font-
xl">
<div class="padding">
<h1 id="greeting" class="ms-fontColor-white"></h1>
</div>
</div>
<div id="content-main">
<div class="padding">
<div class="ms-font-m">
<p id="about"></p>
</div>
</div>
</div>
</body>
The following figure shows the heading (h1) element and the paragraph (p) element
that will display localized text when you complete the remaining steps and run the add-
in.
To enable localized strings for the heading and paragraph, you place the strings in a
separate resource file. The resource file creates a JavaScript object that contains a
separate JavaScript Object Notation (JSON) object for each set of localized strings. The
resource file also provides a method for getting back the appropriate JSON object for a
given locale.
4. Add the following code to the UIStrings.js file, and save the file.
JavaScript
return text;
};
return UIStrings;
})();
The UIStrings.js resource file creates an object, UIStrings, which contains the localized
strings for your add-in UI.
To use the resource file in your add-in, you'll need to add a script tag for it on
Home.html. When Home.html is loaded, UIStrings.js executes and the UIStrings object
that you use to get the strings is available to your code. Add the following HTML in the
head tag for Home.html to make UIStrings available to your code.
HTML
Now you can use the UIStrings object to set the strings for the UI of your add-in.
If you want to change the localization for your add-in based on what language is used
for display in menus and commands in the Office client application, you use the
Office.context.displayLanguage property to get the locale for that language. For
example, if the application language uses Spanish for display in menus and commands,
the Office.context.displayLanguage property will return the language code es-ES.
If you want to change the localization for your add-in based on what language is being
used for editing document content, you use the Office.context.contentLanguage
property to get the locale for that language. For example, if the application language
uses Spanish for editing document content, the Office.context.contentLanguage
property will return the language code es-ES.
After you know the language the application is using, you can use UIStrings to get the
set of localized strings that matches the application language.
Replace the code in the Home.js file with the following code. The code shows how you
can change the strings used in the UI elements on Home.html based on either the
display language of the application or the editing language of the application.
7 Note
To switch between changing the localization of the add-in based on the language
used for editing, uncomment the line of code const myLanguage =
Office.context.contentLanguage; and comment out the line of code const
myLanguage = Office.context.displayLanguage;
JavaScript
(function () {
"use strict";
// The initialize function must be run each time a new page is loaded.
Office.initialize = function (reason)
{
$(document).ready(function () {
// Get the language setting for editing document content.
// To test this, uncomment the following line and then comment
out the
// line that uses Office.context.displayLanguage.
// const myLanguage = Office.context.contentLanguage;
2. Under Choose Display Language, select the language that you want for display,
for example Spanish, and then choose the up arrow to move the Spanish language
to the first position in the list. Alternatively, to change the language used for
editing, under Choose Editing Languages, choose the language you want to use
for editing, for example, Spanish, and then choose Set as Default.
4. Press F5 in Visual Studio to run the sample add-in, or choose Debug > Start
Debugging from the menu bar.
Once running, the strings in the add-in UI change to match the language used by the
application, as shown in the following figure.
This article provides guidance for using Angular 2+ to create an Office Add-in as a
single page application.
7 Note
For an Office Add-ins sample that's built using the Angular framework, see Word Style
Checking Add-in Built on Angular .
command line
Your Angular bootstrapping code must be called inside the function that you assign
to Office.initialize to ensure that the Office JavaScript libraries have initialized first.
The following is a simple example that shows how to do this. This code should be in the
main.ts file of the project.
JavaScript
JavaScript
@NgModule({
providers: [
{ provide: LocationStrategy, useClass: HashLocationStrategy },
// Other providers suppressed
],
// Other module properties suppressed
})
export class AppModule { }
If you define your routes in a separate routing module, there is an alternative way to
specify the hash location strategy. In your routing module's .ts file, pass a configuration
object to the forRoot function that specifies the strategy. The following code is an
example.
JavaScript
@NgModule({
imports: [RouterModule.forRoot(routes, { useHash: true })],
exports: [RouterModule]
})
export class AppRoutingModule { }
Use the Office dialog API with Angular
The Office Add-in dialog API enables your add-in to open a page in a nonmodal dialog
box that can exchange information with the main page, which is typically in a task pane.
The displayDialogAsync method takes a parameter that specifies the URL of the page
that should open in the dialog box. Your add-in can have a separate HTML page
(different from the base page) to pass to this parameter, or you can pass the URL of a
route in your Angular application.
It is important to remember, if you pass a route, that the dialog box creates a new
window with its own execution context. Your base page and all its initialization and
bootstrapping code run again in this new context, and any variables are set to their
initial values in the dialog box. So this technique launches a second instance of your
single page application in the dialog box. Code that changes variables in the dialog box
does not change the task pane version of the same variables. Similarly, the dialog box
has its own session storage (the Window.sessionStorage property), which is not
accessible from code in the task pane.
JavaScript
myFunction() {
this.zone.run(() => {
// the codes that need update the UI
});
}
}
Use Observable
Angular uses RxJS (Reactive Extensions for JavaScript), and RxJS introduces Observable
and Observer objects to implement asynchronous processing. This section provides a
brief introduction to using Observables ; for more detailed information, see the official
RxJS documentation.
objects (possibly with only a single member). This enables code to call array methods ,
such as concat , map , and filter , on Observable objects.
The Observer is configured to process each new object (called the "next" object) with a
function. (It is also configured to respond to an error and a completion notification. See
the next section for an example.) For this reason, Observable objects can be used in a
wider range of scenarios than Promise objects. For example, in addition to returning an
Observable from an AJAX call, the way you can return a Promise , an Observable can be
returned from an event handler, such as the "changed" event handler for a text box.
Each time a user enters text in the box, all the subscribed Observer objects react
immediately using the latest text and/or the current state of the application as input.
JavaScript
myPromise.all([x, y, z]).then(
// TODO: Callback logic goes here
)
To do the same thing with an Observable object, you use the Observable.forkJoin()
method.
JavaScript
const source = Observable.forkJoin([x, y, z]);
To use the AOT compiler, add --aot to the ng build or ng serve command:
command line
ng build --aot
ng serve --aot
7 Note
To learn more about the Angular Ahead-of-Time (AOT) compiler, see the official
guide .
JavaScript
<script
type="text/javascript">window.history.replaceState=null;window.history.pushS
tate=null;</script>
Create Office Add-in projects using the
Yeoman Generator
Article • 07/27/2023
The Yeoman Generator for Office Add-ins (also called "Yo Office") is an interactive
Node.js-based command line tool that creates Office Add-in development projects. We
recommend that you use this tool to create add-in projects except when you want the
server-side code of the add-in to be in a .NET-based language (such as C# or VB.Net) or
you want the add-in hosted in Internet Information Server (IIS). In either of the latter two
situations, use Visual Studio to create the add-in.
7 Note
Office add-ins can also be created with the Teams Toolkit (Prerelease version). For
more information about how to do this and the limitations, see Create Office Add-
in projects using the Teams Toolkit (preview).
The projects that the tool creates have the following characteristics.
Tip
If you want to deviate from these choices significantly, such as using a different task
runner or a different server, we recommend that when you run the tool you choose
the Manifest-only option.
7 Note
If you aren't familiar with Node.js or npm, you should start by setting up your
development environment.
The latest version of Yeoman and the Yeoman generator for Office Add-ins. To
install these tools globally, run the following command via the command prompt.
command line
7 Note
command line
yo office
A lot needs to load, so it may take 20 seconds before the tool starts. The tool asks you a
series of questions. For some, you just type an answer to the prompt. For others, you're
given a list of possible answers. If given a list, select one and then select Enter.
The first question asks you to choose between several types of projects. The options are:
7 Note
The next question asks you to choose between TypeScript and JavaScript. (This
question is skipped if you chose the manifest-only option in the preceding question.)
You're then prompted to give the add-in a name. The name you specify will be used in
the add-in's manifest, but you can change it later.
You're then prompted to choose which Office application the add-in should run in.
There are six possible applications to choose from: Excel, OneNote, Outlook,
PowerPoint, Project, and Word. You must choose just one, but you can change the
manifest later to support the additional Office applications. The exception is Outlook. A
manifest that supports Outlook cannot support any other Office application.
After you've answered this question, the generator creates the project and installs the
dependencies. You may see WARN messages in the npm output on screen. You can
ignore these. You may also see messages that vulnerabilities were found. You can ignore
these for now, but you'll eventually need to fix them before your add-in is released to
production. For more information about fixing vulnerabilities, open your browser and
search for "npm vulnerability".
Tip
If you want to create the scaffolding of an Office Add-in project, but postpone the
installation of the dependencies, add the --skip-install option to the yo office
command. The following code is an example.
command line
yo office --skip-install
When you're ready to install the dependencies, navigate to the root folder of the
project in a command prompt and enter npm install .
Manifest-only option
This option creates only a manifest for an add-in. The resulting project doesn't have a
Hello World add-in, any of the scripts, or any of the dependencies. Use this option in the
following scenarios.
You want to use different tools from the ones a Yeoman generator project installs
and configures by default. For example, you want to use a different bundler,
transpiler, task runner, or development server.
You want to use a web application development framework, other than React, such
as Vue.
For an example of using the generator with the manifest-only option, see Use Vue to
build an Excel task pane add-in.
yo office --details : This will output brief help about all of the other command
line parameters.
yo office --skip-install : This will prevent the generator from installing the
dependencies.
For detailed reference about the command line parameters, see the readme for the
generator at Yeoman generator for Office Add-ins .
Troubleshooting
If you encounter problems using the tool, your first step should be to reinstall it to be
sure that you have the latest version. (See Install the generator for details.) If doing so
doesn't fix the problem, search the issues of the GitHub repo for the tool to see if
anyone else has encountered the same problem and found a solution. If no one has,
create a new issue .
Create Office Add-in projects with
Teams Toolkit (preview)
Article • 07/27/2023
Extensions to the Microsoft 365 Platform are now included under "Teams Apps", even if
the extension is fully outside of the Teams application itself. A primary tool for
developing Teams Apps is Teams Toolkit. You can create Office Add-ins with Teams
Toolkit, with the following restrictions:
Only Outlook Add-ins can be created at this time and only for Outlook on
Windows. We're working hard to enable support in Teams Toolkit for add-ins to
other Office applications and platforms.
Add-ins created with Teams Toolkit use the unified manifest for Microsoft 365
which is currently in preview. We encourage you to experiment with creating add-
ins using the toolkit but don't use the unified manifest for production add-ins.
Install the latest version of Teams Toolkit into Visual Studio Code as described in Install
Teams Toolkit.
5. In the Workspace folder dialog that opens, select the folder where you want to
create the project.
6. Give a name to the project (with no spaces) when prompted. Teams Toolkit will
create the project with basic files and scaffolding. It will then open the project in a
second Visual Studio Code window. Close the original Visual Studio Code window.
7. In the Visual Studio Code TERMINAL navigate to the root of the project and run
npm install .
8. Before you make changes to the project, verify that you can sideload your Outlook
add-in from Visual Studio Code. Use the following steps:
a. Ensure that your account in your Microsoft 365 developer tenancy is also an
email account in desktop Outlook. If it isn't, follow the guidance in Add an email
account to Outlook .
b. Close Outlook desktop.
c. In Visual Studio Code, open Teams Toolkit.
d. In the ACCOUNTS section, verify that you're signed into Microsoft 365.
e. Select View | Run in Visual Studio Code. In the RUN AND DEBUG drop down
menu, select the option, Outlook Desktop (Edge Chromium), and then press F5.
The project builds and a Node dev-server window opens. This process may take
a couple of minutes. Eventually, Outlook desktop will open.
f. Open the Inbox of your Microsoft 365 account identity and open any message. A
Contoso Add-in tab with two buttons will appear on the Home ribbon (or the
Message ribbon, if you have opened the message in its own window).
g. Click the Show Taskpane button and a task pane opens. Click the Perform an
action button and a small notification appears near the top of the message.
h. To stop debugging and uninstall the add-in, select Run | Stop Debugging in
Visual Studio Code.
Now you can change and develop the project. In places where the guidance in the
Office Add-ins documentation branches depending on what type of manifest is being
used, be sure to follow the guidance for the unified manifest.
Develop Office Add-ins with Visual
Studio Code
Article • 03/14/2023
This article describes how to use Visual Studio Code (VS Code) to develop an Office
Add-in.
7 Note
For information about using Visual Studio to create an Office Add-in, see Develop
Office Add-ins with Visual Studio.
Prerequisites
Visual Studio Code
The latest version of Yeoman and the Yeoman generator for Office Add-ins. To
install these tools globally, run the following command via the command prompt.
command line
7 Note
Tip
On Windows, you can navigate to the root directory of the project via the
command line and then enter code . to open that folder in VS Code. On Mac,
you'll need to add the code command to the path before you can use that
command to open the project folder in VS Code.
The Yeoman generator creates a basic add-in with limited functionality. You can
customize the add-in by editing the manifest, HTML, JavaScript or TypeScript, and CSS
files in VS Code. For a high-level description of the project structure and files in the add-
in project that the Yeoman generator creates, see the Yeoman generator guidance
within the 5-minute quick start that corresponds to the type of add-in you've created.
While you're developing your add-in, you can run the add-in on your local web server
( localhost ), but when you're ready to publish it for other users to access, you'll need to
deploy the web application to a web server or web hosting service (for example,
Microsoft Azure) and update the manifest to specify the URL of the deployed
application.
When your add-in is working as desired and you're ready to publish it for other users to
access, complete the following steps.
1. From the command line, in the root directory of your add-in project, run the
following command to prepare all files for production deployment.
command line
When the build completes, the dist folder in the root directory of your add-in
project will contain the files that you'll deploy in subsequent steps.
2. Upload the contents of the dist folder to the web server that'll host your add-in.
You can use any type of web server or web hosting service to host your add-in.
3. In VS Code, open the add-in's manifest file, located in the root directory of the
project ( manifest.xml ). Replace all occurrences of https://localhost:3000 with the
URL of the web application that you deployed to a web server in the previous step.
4. Choose the method you'd like to use to deploy your Office Add-in, and follow the
instructions to publish the manifest file.
See also
Core concepts for Office Add-ins
Develop Office Add-ins
Design Office Add-ins
Test and debug Office Add-ins
Publish Office Add-ins
Develop Office Add-ins with Visual
Studio
Article • 03/14/2023
This article describes how to use Visual Studio to develop an Office Add-in. If you've
already created your add-in, you can skip ahead to the Develop the add-in using Visual
Studio section.
7 Note
As an alternative to using Visual Studio, you may choose to use the Yeoman
generator for Office Add-ins and VS Code to create an Office Add-in. For more
information about this choice, see Creating an Office Add-in.
Visual Studio doesn't support creating Office Add-ins for OneNote or Project. To create
Office Add-ins for either of these applications, you'll need to use the Yeoman generator
for Office Add-ins, as described in the OneNote quick start or the Project quick start.
Because an Office Add-in is a web application, you'll need at least basic web
development skills to customize your add-in. If you're new to JavaScript, we
recommend reviewing the Mozilla JavaScript tutorial .
To customize your add-in, you'll need to understand concepts described in the Core
concepts > Develop area of this documentation, as well as concepts described in the
application-specific area of documentation that corresponds to the add-in you're
building (for example, Excel).
While you're developing your add-in in Visual Studio, your add-in runs on your local
web server ( localhost ). When your add-in is working as desired and you're ready to
publish it for other users to access, you'll need to complete the following steps.
1. Deploy the web application to a web server or web hosting service (for example,
Microsoft Azure).
2. Update the manifest to specify the URL of the deployed application.
3. Choose the method you'd like to use to deploy your Office Add-in, and follow the
instructions to publish the manifest file.
See also
Core concepts for Office Add-ins
Develop Office Add-ins
Design Office Add-ins
Test and debug Office Add-ins
Publish Office Add-ins
Get JavaScript IntelliSense in Visual
Studio
Article • 03/14/2023
When you use Visual Studio 2019 and later to develop Office Add-ins, you can use
JSDoc to enable IntelliSense for your JavaScript variables, objects, parameters, and
return values. This article provides an overview of JSDoc and how you can use it to
create IntellSense in Visual Studio. For more details, see JavaScript IntelliSense and
JSDoc support in JavaScript .
Have a local copy of the Office.js files in a folder in your solution named
\Office\1\ . The Office Add-in project templates in Visual Studio add this local
Use an online version of Office.js by adding a tsconfig.json file to the root of the
web application project in the add-in solution. The file should include the following
content.
JSON
{
"compilerOptions": {
"allowJs": true, // These settings apply to
JavaScript files also.
"noEmit": true // Do not compile the JS (or
TS) files in this project.
},
"exclude": [
"node_modules", // Don't include any JavaScript
found under "node_modules".
"Scripts/Office/1" // Suppress loading all the
JavaScript files from the Office NuGet package.
],
"typeAcquisition": {
"enable": true, // Enable automatic fetching of
type definitions for detected JavaScript libraries.
"include": [ "office-js" ] // Ensure that the "Office-js"
type definition is fetched.
}
}
JSDoc syntax
The basic technique is to precede the variable (or parameter, and so on) with a
comment that identifies its data type. This allows IntelliSense in Visual Studio to infer its
members. The following are examples.
Variable
JavaScript
Parameter
JavaScript
}
Return value
JavaScript
Complex types
JavaScript
See also
Develop Office Add-ins with Visual Studio
Debug Office Add-ins in Visual Studio
Convert an Office Add-in project in
Visual Studio to TypeScript
Article • 03/14/2023
You can use the Office Add-in template in Visual Studio to create an add-in that uses
JavaScript, and then convert that add-in project to TypeScript. This article describes this
conversion process for an Excel add-in. You can use the same process to convert other
types of Office Add-in projects from JavaScript to TypeScript in Visual Studio.
Prerequisites
Visual Studio 2022 or later with the Office/SharePoint development workload
installed
Tip
If you've previously installed Visual Studio, use the Visual Studio Installer to
ensure that the Office/SharePoint development workload is installed. If this
workload is not yet installed, use the Visual Studio Installer to install it.
2. Using the search box, enter add-in. Choose Excel Web Add-in, then select Next.
4. In the Create Office Add-in dialog window, choose Add new functionalities to
Excel, and then choose Finish to create the project.
5. Visual Studio creates a solution and its two projects appear in Solution Explorer.
The Home.html file opens in Visual Studio.
7 Note
In your TypeScript project, you can have a mix of TypeScript and JavaScript files and
your project will compile. This is because TypeScript is a typed superset of
JavaScript that compiles JavaScript.
2. In the Add New Item dialog, select TypeScript JSON configuration File to create a
tsconfig.json file and then choose Add.
3. Update the tsconfig.json file to also have an include section as shown in the
following JSON.
JSON
{
"compilerOptions": {
"noImplicitAny": false,
"noEmitOnError": true,
"removeComments": false,
"sourceMap": true,
"target": "es5"
},
"exclude": [
"node_modules",
"wwwroot"
],
"include": [
"scripts/**/*",
"**/*"
]
}
4. Save the file. For more information on tsconfig.json settings, see What is a
tsconfig.json?
4. In Home.ts, find the line Office.initialize = function (reason) { and add a line
immediately after it to polyfill the global window.Promise , as shown here.
TypeScript
TypeScript
_onResize();
The JavaScript files generated by Visual Studio do not contain any TypeScript syntax. You
should consider updating them. For example, the following code shows how to update
the parameters to showNotification to include the string types.
TypeScript
function showNotification(header: string, content: string) {
$("#notification-header").text(header);
$("#notification-body").text(content);
messageBanner.showBanner();
messageBanner.toggleExpansion();
}
2. In Excel, choose the Home tab, and then choose the Show Taskpane button on the
ribbon to open the add-in task pane.
4. Press the Highlight button on the task pane to highlight the cell in the selected
range that contains the highest value.
See also
Promise implementation discussion on StackOverflow
Office Add-in samples on GitHub
Special requirements for add-ins on the
iPad
Article • 03/14/2023
If your add-in uses only Office APIs that are supported on the iPad, then customers can
install it on iPads. (See Specify Office applications and API requirements for more
information.) If the add-in will be marketed through AppSource , then there are some
practices you must follow for add-ins that can be installed on iPads, in addition to the
best practices that apply to all Office Add-ins.
7 Note
For information about designing Outlook add-ins that look good and work well in
Outlook on mobile devices, see Add-ins for Outlook on mobile devices.
Update Update the JavaScript files (Office.js and app- Update API and manifest version
your add- specific .js files) and the add-in manifest
in to validation file used in your Office Add-in project
support to version 1.1.
Office.js
version 1.1.
Apply iOS Integrate your add-in UI seamlessly with the iOS See note below.
design experience.
best
practices.
Make your Office on iPad is a channel through which you Certification policy 1120.2
add-in can reach more users and promote your
free. services. These new users have the potential to
become your customers.
Task Description Resources
Make your When it's running on the iPad, your add-in must Certification policy 1100.3
add-in be free of in-app purchases, trial offers, UI that
commerce aims to upsell to a non-free version, or links to Your add-in can still have
free on the any online stores where users can purchase or commerce on other platforms.
iPad. acquire other content, apps, or add-ins. Your To do so, test the
Privacy Policy and Terms of Use pages must also Office.context.commerceAllowed
be free of any commerce UI or AppSource links. property and suppress all
commerce when it returns
false .
Submit In Partner Center, on the Product setup page, Make your solutions available in
your add- select the Make my product available on iOS AppSource and within Office
in to and Android (if applicable) check box, and
AppSource. provide your Apple developer ID in Account
settings. Review the Application Provider
Agreement to make sure you understand the
terms.
7 Note
Your add-in can serve an alternate UI based on the device that it is running on. To
detect whether your add-in is running on an iPad, you can use the following APIs.
For information on the best UI design practices for iPad, see Designing for iOS .
Develop and debug the add-in on Windows or Mac and sideload it to an iPad.
You can't develop the add-in directly on an iPad, but you can develop and debug it
on a Windows or Mac computer and sideload it to an iPad for testing. Because an
add-in that runs in Office on iOS or Mac supports the same APIs as an add-in
running in Office on Windows, your add-in's code should run the same way on
these platforms. For details, see Test and debug Office Add-ins and Sideload Office
Add-ins on iPad for testing.
When you specify API requirements in your add-in's manifest, Office will determine
if the Office client application supports those API members. If the API members are
available in the application, then your add-in will be available. Alternatively, you
can perform a runtime check to determine if a method is available in the
application before using it in your add-in. Runtime checks ensure that your add-in
is always available in the application, and provides additional functionality if the
methods are available. For more information, see Specify Office applications and
API requirements.
Test Office Add-ins
Article • 05/20/2023
This article contains guidance about testing, debugging, and troubleshooting issues
with Office Add-ins.
7 Note
On Windows computers, the version of Windows and Office will determine which
browser or webview control is used by add-ins. For more information, see Browsers
and webview controls used by Office Add-ins. For brevity hereafter, this article
uses "browser control" to mean "browser or webview control".
Office on the web no longer opens in Internet Explorer or Microsoft Edge Legacy
(EdgeHTML). Consequently, AppSource doesn't test Office on the web on these
browsers. Office still supports these browsers for add-in runtimes, so if you think you've
encountered a bug in how add-ins run in them, please create an issue in the office-js
repository. For more information, see Support older Microsoft webviews and Office
versions and Troubleshoot EdgeHTML and WebView2 (Microsoft Edge) issues.
Unit testing
For information about how to add unit tests to your add-in project, see Unit testing in
Office Add-ins.
Debugging Office Add-ins is essentially the same as debugging any web application.
However, a single set of tools won't work for all add-in developers. This is because add-
ins can be developed on different operating systems and run cross-platform. This article
helps you find the detailed debugging guidance for your development environment.
Tip
This article is concerned with debugging in the narrow sense of setting breakpoints
and stepping through code. For guidance on testing and troubleshooting, start
with Test Office Add-ins and Troubleshoot development errors with Office Add-
ins.
7 Note
Although you should test your add-in on all the platforms that you want to support,
you'll only very rarely need to debug on an environment different from your
development computer. For this reason, this article uses "your development
computer" and "your development environment" to refer to the environment on
which you're debugging. If a problem in the code occurs only on a platform other
than the one on your development computer, and you need to set breakpoints or
step through code to solve it, then the environment on which you're debugging
isn't literally your development environment.
Server-side or client-side?
Debugging the server-side code of an Office Add-in is the same as debugging the
server-side of any web application. See the debugging instructions for your IDE or other
tools. The following are examples for some of the most popular tools.
Special cases
There are some special cases in which the debugging process differs from normal for a
given combination of platform, Office application, and development environment. If
you're debugging any of these special cases, use the links in this section to find the
proper guidance. Otherwise, continue to General guidance.
General guidance
To find guidance for debugging client-side code, the first variable is the operating
system of your development computer.
Windows
Mac
Linux or other Unix variant
Debug on Windows
The following provides general guidance to debugging on Windows. Debugging on
Windows depends on your IDE.
Visual Studio: Debug using the browser's F12 tools. See Debug Office Add-ins in
Visual Studio.
Visual Studio Code: Debug using the Add-in Debugger Extension for Visual Studio
Code.
Any other IDE (or you don't want to debug inside your IDE): Use the developer
tools that are associated with the webview control that add-ins use on your
development computer. See one of the following:
For the Trident webview: Debug add-ins using developer tools for Internet
Explorer
For the EdgeHTML webview: Debug add-ins using developer tools for Edge
Legacy
For the WebView2 webview: Debug add-ins using developer tools in Microsoft
Edge (Chromium-based)
For information about which runtime is being used, see Browsers and webview controls
used by Office Add-ins and Runtimes in Office Add-ins.
Tip
In recent versions of Office, one way to identify the webview control that Office is
using is through the personality menu on any add-in where it's available. (The
personality menu isn't supported in Outlook.) Open the menu and select Security
Info. In the Security Info dialog on Windows, the Runtime reports Microsoft Edge,
Microsoft Edge Legacy, or Internet Explorer. The runtime isn't included on the
dialog in older versions of Office.
Debug on Mac
Use the Safari Web Inspector. Instructions are in Debug Office Add-ins on a Mac.
Debug on Linux
There is no desktop version of Office for Linux, so you'll need to sideload the add-in to
Office on the web to test and debug it. Debugging guidance is in Debug add-ins in
Office on the web.
7 Note
We don't recommend that you develop Office Add-ins on a Linux computer except
in the unusual case where you can be sure that all the add-in's users will be
accessing the add-in through Office on the web from a Linux computer.
See also
Runtimes in Office Add-ins
Sideload Office Add-ins for testing from
a network share
Article • 06/23/2023
You can test an Office Add-in in an Office client that's on Windows by publishing the
manifest to a network file share (instructions follow). This deployment option is intended
to be used when you've completed development and testing on a localhost and want to
test the add-in from a non-local server or cloud account.
) Important
Deployment by network share isn't supported for production add-ins. This method
has the following limitations.
7 Note
If your add-in project was created with a sufficiently recent version of the Yeoman
generator for Office Add-ins, the add-in will automatically sideload in the Office
desktop client when you run npm start .
This article applies only to testing Word, Excel, PowerPoint, and Project add-ins and only
on Windows. If you want to test on another platform or want to test an Outlook add-in,
see one of the following topics to sideload your add-in.
The following video walks you through the process of sideloading your add-in in Office
on the web or desktop using a shared folder catalog.
https://www.youtube-nocookie.com/embed/XXsAw2UUiQo
Share a folder
1. In File Explorer on the Windows computer where you want to host your add-in, go
to the parent folder, or drive letter, of the folder you want to use as your shared
folder catalog.
2. Open the context menu for the folder you want to use as your shared folder
catalog (for example, right-click the folder) and choose Properties.
3. Within the Properties dialog window, open the Sharing tab and then choose the
Share button.
4. Within the Network access dialog window, add yourself and any other users
and/or groups with whom you want to share your add-in. You'll need at least
Read/Write permission to the folder. After you've finished choosing people to
share with, choose the Share button.
5. When you see the Your folder is shared confirmation, make note of the full
network path that's displayed immediately following the folder name. (You'll need
to enter this value as the Catalog Url when you specify the shared folder as a
trusted catalog, as described in the next section of this article.) Choose the Done
button to close the Network access dialog window.
3. Choose Trust Center, and then choose the Trust Center Settings button.
6. After you've entered the full network path of the folder into the Catalog Url box,
choose the Add catalog button.
7. Select the Show in Menu check box for the newly-added item, and then choose
the OK button to close the Trust Center dialog window.
8. Choose the OK button to close the Options dialog window.
9. Close and reopen the Office application so your changes will take effect.
text
[HKEY_CURRENT_USER\Software\Microsoft\Office\16.0\WEF\TrustedCatalogs\
{-random-GUID-here-}]
"Id"="{-random-GUID-here-}"
"Url"="\\\\-share-\\-folder-"
"Flags"=dword:00000001
3. Use one of the many online GUID generation tools, such as GUID Generator , to
generate a random GUID, and within the TrustNetworkShareCatalog.reg file,
replace the string "-random-GUID-here-" in both places with the GUID. (The
enclosing {} symbols should remain.)
4. Replace the Url value with the full network path to the folder that you shared
previously. (Note that any \ characters in the URL must be doubled.) If you failed
to note the folder's full network path when you shared the folder, you can get it
from the folder's Properties dialog window, as shown in the following screenshot.
5. The file should now look like the following. Save it.
text
[HKEY_CURRENT_USER\Software\Microsoft\Office\16.0\WEF\TrustedCatalogs\
{01234567-89ab-cedf-0123-456789abcedf}]
"Id"="{01234567-89ab-cedf-0123-456789abcedf}"
"Url"="\\\\TestServer\\OfficeAddinManifests"
"Flags"=dword:00000001
) Important
While not strictly required in all add-in scenarios, using an HTTPS endpoint for
your add-in is strongly recommended. Add-ins that are not SSL-secured
(HTTPS) generate unsecure content warnings and errors during use. If you
plan to run your add-in in Office on the web or publish your add-in to
AppSource, it must be SSL-secured. If your add-in accesses external data and
services, it should be SSL-secured to protect data in transit. Self-signed
certificates can be used for development and testing, so long as the certificate
is trusted on the local machine.
7 Note
For Visual Studio projects, use the manifest built by the project in the
{projectfolder}\bin\Debug\OfficeAppManifests folder.
2. In Excel, Word, or PowerPoint, select My Add-ins on the Insert tab of the ribbon. In
Project, select My Add-ins on the Project tab of the ribbon.
3. Choose SHARED FOLDER at the top of the Office Add-ins dialog box.
4. Select the name of the add-in and choose Add to insert the add-in.
See also
Validate an Office Add-in's manifest
Clear the Office cache
Publish your Office Add-in
Attach a debugger from the task pane
Article • 05/20/2023
The technique described in this article can be used only when the following conditions
are met.
Tip
In recent versions of Office, one way to identify the webview control that Office is
using is through the personality menu on any add-in where it's available. (The
personality menu isn't supported in Outlook.) Open the menu and select Security
Info. In the Security Info dialog on Windows, the Runtime reports Microsoft Edge,
Microsoft Edge Legacy, or Internet Explorer. The runtime isn't included on the
dialog in older versions of Office.
To launch the debugger, choose the top right corner of the task pane to activate the
Personality menu (as shown in the red circle in the following image).
Select Attach Debugger. This launches the Microsoft Edge (Chromium-based) developer
tools. Use the tools as described in Debug add-ins using developer tools in Microsoft
Edge (Chromium-based).
See also
Overview of debugging Office Add-ins
Debug add-ins using developer tools in
Internet Explorer
Article • 05/20/2023
This article shows how to debug the client-side code (JavaScript or TypeScript) of your
add-in when the following conditions are met.
You cannot, or don't wish to, debug using tools built into your IDE; or you are
encountering a problem that only occurs when the add-in is run outside the IDE.
Your computer is using a combination of Windows and Office versions that use the
Internet Explorer webview control, Trident.
To determine which browser or webview is being used on your computer, see Browsers
and webview controls used by Office Add-ins.
Tip
In recent versions of Office, one way to identify the webview control that Office is
using is through the personality menu on any add-in where it's available. (The
personality menu isn't supported in Outlook.) Open the menu and select Security
Info. In the Security Info dialog on Windows, the Runtime reports Microsoft Edge,
Microsoft Edge Legacy, or Internet Explorer. The runtime isn't included on the
dialog in older versions of Office.
7 Note
To install a version of Office that uses Trident or to force your current version to use
Trident, see Switch to the Trident webview.
7 Note
If your add-in has an add-in command that executes a function, the function runs
in a hidden browser runtime process that the F12 tools cannot detect or attach to,
so the technique described in this article cannot be used to debug code in the
function.
The following steps are the instructions for debugging your add-in. If you just want to
test the F12 tools themselves, see Example add-in to test the F12 tools.
2. Launch the F12 development tools that corresponds to your version of Office.
IEChooser opens with a window named Choose target to debug. Your add-in will
appear in the window named by the filename of the add-in's home page. In the
following screenshot, it is Home.html . Only processes that are running in Internet
Explorer, or Trident, appear. The tool cannot attach to processes that are running in
other browsers or webviews, including Microsoft Edge.
3. Select your add-in's process; that is, its home page file name. This action will attach
the F12 tools to the process and open the main F12 user interface.
5. In the upper left of the tab, just below the debugger tool ribbon, there is a small
folder icon. Select this to open a drop down list of the files in the add-in. The
following is an example.
6. Select the file that you want to debug and it opens in the the script (left) pane of
the Debugger tab. If you're using a transpiler, bundler, or minifier, that changes
the name of the file, it will have the final name that is actually loaded, not the
original source file name.
7. Scroll to a line where you want to set a breakpoint and click in the margin to the
left of the line number. You'll see a red dot to the left of the line and a
corresponding line appears in the Breakpoints tab of the bottom right pane. The
following screenshot is an example.
8. Execute functions in the add-in as needed to trigger the breakpoint. When the
breakpoint is hit, a right-pointing arrow appears on the red dot of the breakpoint.
The following screenshot is an example.
Tip
For more information about using the F12 tools, see Inspect running JavaScript
with the Debugger.
Your project was developed with Visual Studio and IIS. It isn't node.js-based.
You want to be absolutely robust in your testing.
If for any reason the command line tool doesn't work.
The tool that's used to force the change in webview is supported only in the Beta
subscription channel of Microsoft 365. Join the Microsoft 365 Insider program
and select the Beta Channel option to access Office Beta builds. See also About
Office: What version of Office am I using? .
Strictly, it's the webview switch of this tool (see Step 2) that requires the Beta
channel. The tool has other switches that don't have this requirement.
1. If your project was not created with the Yeoman generator for Office Add-ins tool,
you need to install the office-addin-dev-settings tool. Run the following command
in a command prompt.
command line
) Important
2. Specify the webview that you want Office to use with the following command in a
command prompt in the root of the project. Replace <path-to-manifest> with the
relative path, which is just the manifest filename if it's in the root of the project.
Replace <webview> with either ie or edge-legacy . Note that the options are
named after the browsers in which the webviews originated. The ie option means
"Trident" and the edge-legacy option means "EdgeHTML".
command line
command line
3. When you're finished, set Office to resume using the default webview for your
combination of Windows and Office versions with the following command.
command line
1. In any Office application, open the File tab on the ribbon, and then select Office
Account or Account. Select the About host-name button (for example, About
Word).
2. On the dialog that opens, find the full xx.x.xxxxx.xxxxx build number and make a
copy of it somewhere.
4. Run the downloaded file to extract the tool. You are prompted to choose where to
install the tool.
5. In the folder where you installed the tool (where the setup.exe file is located),
create a text file with the name config.xml and add the following contents.
XML
<Configuration>
<Add OfficeClientEdition="64" Channel="SemiAnnual"
Version="16.0.xxxxx.xxxxx">
<Product ID="O365ProPlusRetail">
<Language ID="en-us" />
</Product>
</Add>
</Configuration>
command line
This command installs Office. The process may take several minutes.
) Important
After installation, be sure that you turn off automatic updating of Office, so that
Office isn't updated to a version that doesn't use webview you want to work with
before you've completed using it. This can happen within minutes of installation.
Follow these steps.
When you are finished using the old version of Office, reinstall your newer version by
editing the config.xml file and changing the Version to the build number that you
copied earlier. Then repeat the setup.exe /configure config.xml command in an
administrator command prompt. Optionally, re-enable automatic updates.
See also
Inspect running JavaScript with the Debugger
Using the F12 developer tools
Debug add-ins using developer tools in
Microsoft Edge Legacy
Article • 05/20/2023
This article shows how to debug the client-side code (JavaScript or TypeScript) of your
add-in when the following conditions are met.
You cannot, or don't wish to, debug using tools built into your IDE; or you are
encountering a problem that only occurs when the add-in is run outside the IDE.
Your computer is using a combination of Windows and Office versions that use the
original Edge webview control, EdgeHTML.
Tip
For information about debugging with Edge Legacy inside Visual Studio Code, see
Microsoft Office Add-in Debugger Extension for Visual Studio Code.
To determine which browser or webview you're using, see Browsers and webview
controls used by Office Add-ins.
Tip
In recent versions of Office, one way to identify the webview control that Office is
using is through the personality menu on any add-in where it's available. (The
personality menu isn't supported in Outlook.) Open the menu and select Security
Info. In the Security Info dialog on Windows, the Runtime reports Microsoft Edge,
Microsoft Edge Legacy, or Internet Explorer. The runtime isn't included on the
dialog in older versions of Office.
7 Note
To install a version of Office that uses the Edge legacy webview or to force your
current version of Office to use Edge Legacy, see Switch to the Edge Legacy
webview.
7 Note
If your add-in has an add-in command that executes a function, the function
runs in a hidden browser runtime process that the Microsoft Edge DevTools
cannot detect or attach to, so the technique described in this article cannot be
used to debug code in the function.
4. In the tools, open the Local tab. Your add-in will be listed by its name. (Only
processes that are running in EdgeHTML appear on the tab. The tool cannot attach
to processes that are running in other browsers or webviews, including Microsoft
Edge (WebView2) and Internet Explorer (Trident).)
7. Open the file that you want to debug with the following steps.
a. On the debugger task bar, select Show find in files. This will open a search
window.
b. Enter a line of code from the file you want to debug in the search box. It should
be something that's not likely to be in any other file.
c. Select the refresh button.
d. In the search results, select the line to open the code file in the pane above the
search results.
8. To set a breakpoint, select the line in the code file. The breakpoint is registered in
the Call stack (bottom right) pane. There may also be a red dot by the line in the
code file, but this doesn't appear reliably.
Tip
For more information about using the tools, see Microsoft Edge (EdgeHTML)
Developer Tools.
2. Open the dialog and then select the Refresh button in the tools. The dialog
process is shown. Its name comes from the <title> element in the HTML file that
is open in the dialog.
3. Select the process to open it and debug just as described in the section Debug a
task pane add-in using Microsoft Edge DevTools Preview.
Your project was developed with Visual Studio and IIS. It isn't node.js-based.
You want to be absolutely robust in your testing.
If for any reason the command line tool doesn't work.
7 Note
The tool that's used to force the change in webview is supported only in the Beta
subscription channel of Microsoft 365. Join the Microsoft 365 Insider program
and select the Beta Channel option to access Office Beta builds. See also About
Office: What version of Office am I using? .
Strictly, it's the webview switch of this tool (see Step 2) that requires the Beta
channel. The tool has other switches that don't have this requirement.
1. If your project was not created with the Yeoman generator for Office Add-ins tool,
you need to install the office-addin-dev-settings tool. Run the following command
in a command prompt.
command line
) Important
2. Specify the webview that you want Office to use with the following command in a
command prompt in the root of the project. Replace <path-to-manifest> with the
relative path, which is just the manifest filename if it's in the root of the project.
Replace <webview> with either ie or edge-legacy . Note that the options are
named after the browsers in which the webviews originated. The ie option means
"Trident" and the edge-legacy option means "EdgeHTML".
command line
command line
You should see a message in the command line that the webview type is now set
to IE (or Edge Legacy).
3. When you're finished, set Office to resume using the default webview for your
combination of Windows and Office versions with the following command.
command line
1. In any Office application, open the File tab on the ribbon, and then select Office
Account or Account. Select the About host-name button (for example, About
Word).
2. On the dialog that opens, find the full xx.x.xxxxx.xxxxx build number and make a
copy of it somewhere.
4. Run the downloaded file to extract the tool. You are prompted to choose where to
install the tool.
5. In the folder where you installed the tool (where the setup.exe file is located),
create a text file with the name config.xml and add the following contents.
XML
<Configuration>
<Add OfficeClientEdition="64" Channel="SemiAnnual"
Version="16.0.xxxxx.xxxxx">
<Product ID="O365ProPlusRetail">
<Language ID="en-us" />
</Product>
</Add>
</Configuration>
command line
This command installs Office. The process may take several minutes.
) Important
After installation, be sure that you turn off automatic updating of Office, so that
Office isn't updated to a version that doesn't use webview you want to work with
before you've completed using it. This can happen within minutes of installation.
Follow these steps.
When you are finished using the old version of Office, reinstall your newer version by
editing the config.xml file and changing the Version to the build number that you
copied earlier. Then repeat the setup.exe /configure config.xml command in an
administrator command prompt. Optionally, re-enable automatic updates.
Debug add-ins using developer tools in
Microsoft Edge (Chromium-based)
Article • 05/20/2023
This article shows how to debug the client-side code (JavaScript or TypeScript) of your
add-in when the following conditions are met.
You cannot, or don't wish to, debug using tools built into your IDE; or you are
encountering a problem that only occurs when the add-in is run outside the IDE.
Your computer is using a combination of Windows and Office versions that use the
Edge (Chromium-based) webview control, WebView2.
Tip
To determine which webview you're using, see Browsers and webview controls used by
Office Add-ins.
Tip
In recent versions of Office, one way to identify the webview control that Office is
using is through the personality menu on any add-in where it's available. (The
personality menu isn't supported in Outlook.) Open the menu and select Security
Info. In the Security Info dialog on Windows, the Runtime reports Microsoft Edge,
Microsoft Edge Legacy, or Internet Explorer. The runtime isn't included on the
dialog in older versions of Office.
7 Note
If your add-in has an add-in command that executes a function, the function runs
in a hidden browser runtime process that the Microsoft Edge (Chromium-based)
developer tools cannot be launched from, so the technique described in this article
cannot be used to debug code in the function.
Be sure the add-in's task pane has focus and press Ctrl+Shift+I.
Right-click the task pane to open the context menu and select Inspect, or
open the personality menu and select Attach Debugger. (The personality
menu isn't supported in Outlook.)
4. Open the file that you want to debug with the following steps.
a. On the far right of the tool's top menu bar, select the ... button and then select
Search.
b. Enter a line of code from the file you want to debug in the search box. It should
be something that's not likely to be in any other file.
c. Select the refresh button.
d. In the search results, select the line to open the code file in the pane above the
search results.
5. To set a breakpoint, select the line number of the line in the code file. A red dot
appears by the line in the code file. In the debugger window to the right, the
breakpoint is registered in the Breakpoints drop down.
Tip
For more information about using the tools, see Microsoft Edge Developer Tools
overview.
4. Use the tool the same as you would for code in a task pane. See Debug a task
pane add-in using Microsoft Edge (Chromium-based) developer tools earlier in this
article.
Debug add-ins on Windows using Visual
Studio Code and Microsoft Edge
WebView2 (Chromium-based)
Article • 12/12/2022
Office Add-ins running on Windows can debug against the Edge Chromium WebView2
runtime directly in Visual Studio Code.
) Important
This article only applies when Office runs add-ins in the Microsoft Edge Chromium
WebView2 runtime, as explained in Browsers and webview controls used by Office
Add-ins. For instructions about debugging in Visual Studio Code against Microsoft
Edge Legacy with the original WebView (EdgeHTML) runtime, see Office Add-in
Debugger Extension for Visual Studio Code.
Tip
If you cannot, or don't wish to, debug using tools built into Visual Studio Code; or
you are encountering a problem that only occurs when the add-in is run outside
Visual Studio Code, you can debug Edge Chromium WebView2 runtime by using
the Edge (Chromium-based) developer tools as described in Debug add-ins using
developer tools for Microsoft Edge WebView2.
This debugging mode is dynamic, allowing you to set breakpoints while code is running.
See changes in your code immediately while the debugger is attached, all without losing
your debugging session. Your code changes also persist, so you see the results of
multiple changes to your code. The following image shows this extension in action.
Prerequisites
Visual Studio Code
Node.js (version 10+)
Windows 10, 11
A combination of platform and Office application that supports Microsoft Edge
with WebView2 (Chromium-based) as explained in Browsers and webview controls
used by Office Add-ins. If your version of Office from a Microsoft 365 subscription
is earlier than Version 2101, you will need to install WebView2. Use the instructions
for installing it at Microsoft Edge WebView2 / Embed web content ... with
Microsoft Edge WebView2.
1. The first step depends on the project and how it was created.
4. From the RUN AND DEBUG options, choose the Edge Chromium option for your
host application, such as Outlook Desktop (Edge Chromium). Select F5 or choose
Run > Start Debugging from the menu to begin debugging. This action
automatically launches a local server in a Node window to host your add-in and
then automatically opens the host application, such as Excel or Word. This may
take several seconds.
Tip
If you aren't using a project created with Yo Office, you may be prompted to
adjust a registry key. While in the root folder of your project, run the following
in the command line.
command line
) Important
If your project was created with older versions of Yo Office, you may see the
following error dialog box about 10 - 30 seconds after you start debugging
(at which point you may have already gone on to another step in this
procedure) and it may be hidden behind the dialog box described in the next
step.
Select OK.
7 Note
If you select Cancel, the dialog won't be shown again while this instance of
the add-in is running. However, if you restart your add-in, you'll see the dialog
again.
6. You're now able to set breakpoints in your project's code and debug. To set
breakpoints in Visual Studio Code, hover next to a line of code and select the red
circle that appears.
7. Run functionality in your add-in that calls the lines with breakpoints. You'll see that
breakpoints have been hit and you can inspect local variables.
7 Note
) Important
The best way to stop a debugging session is to select Shift+F5 or choose Run >
Stop Debugging from the menu. This action should close the Node server window
and attempt to close the host application, but there will be a prompt on the host
application asking you whether to save the document or not. Make an appropriate
choice and let the host application close. Avoid manually closing the Node window
or host application. Doing so can cause bugs especially when you are stopping and
starting debugging sessions repeatedly.
If debugging stops working; for example, if breakpoints are being ignored; stop
debugging. Then, if necessary, close all host application windows and the Node
window. Finally, close Visual Studio Code and reopen it.
Appendix A
If your project was not created with Yo Office, you need to create a debug configuration
for Visual Studio Code.
1. Create a file named launch.json in the \.vscode folder of the project if there isn't
one there already.
2. Ensure that the file has a configurations array. The following is a simple example
of a launch.json .
JSON
{
// Other properties may be here.
"configurations": [
]
// Other properties may be here.
}
JSON
{
"name": "$HOST$ Desktop (Edge Chromium)",
"type": "pwa-msedge",
"request": "attach",
"useWebView": true,
"port": 9229,
"timeout": 600000,
"webRoot": "${workspaceRoot}",
"preLaunchTask": "Debug: Excel Desktop",
"postDebugTask": "Stop Debug"
},
4. Replace the placeholder $HOST$ with the name of the Office application that the
add-in runs in; for example, Outlook or Word .
Appendix B
1. In the error dialog box, select the Cancel button.
2. If debugging doesn't stop automatically, select Shift+F5 or choose Run > Stop
Debugging from the menu.
3. Close the Node window where the local server is running, if it doesn't close
automatically.
4. Close the Office application if it doesn't close automatically.
5. Open the \.vscode\launch.json file in the project.
6. In the configurations array, there are several configuration objects. Find the one
whose name has the pattern $HOST$ Desktop (Edge Chromium) , where $HOST$ is an
Office application that your add-in runs in; for example, Outlook Desktop (Edge
Chromium) or Word Desktop (Edge Chromium) .
Office Add-ins running on Windows can use the Office Add-in Debugger Extension in
Visual Studio Code to debug against Microsoft Edge Legacy with the original WebView
(EdgeHTML) runtime.
) Important
This article only applies when Office runs add-ins in the original WebView
(EdgeHTML) runtime, as explained in Browsers and webview controls used by
Office Add-ins. For instructions about debugging in Visual Studio code against
Microsoft Edge WebView2 (Chromium-based), see Microsoft Office Add-in
Debugger Extension for Visual Studio Code.
Tip
If you cannot, or don't wish to, debug using tools built into Visual Studio Code; or
you are encountering a problem that only occurs when the add-in is run outside
Visual Studio Code, you can debug Edge Legacy (EdgeHTML) runtime by using the
Edge Legacy developer tools as described in Debug add-ins using developer tools
in Microsoft Edge Legacy.
This debugging mode is dynamic, allowing you to set breakpoints while code is running.
You can see changes in your code immediately while the debugger is attached, all
without losing your debugging session. Your code changes also persist, so you can see
the results of multiple changes to your code. The following image shows this extension
in action.
Prerequisites
Visual Studio Code
Node.js (version 10+)
Windows 10, 11
Microsoft Edge A combination of platform and Office application that supports
Microsoft Edge Legacy with with the original webview (EdgeHTML) as explained in
Browsers and webview controls used by Office Add-ins.
1. The first step depends on the project and how it was created.
3. Within VS Code, select Ctrl+Shift+X to open the Extensions bar. Search for the
"Microsoft Office Add-in Debugger" extension and install it.
5. From the RUN AND DEBUG options, choose the Edge Legacy option for your host
application, such as Outlook Desktop (Edge Legacy). Select F5 or choose Run >
Start Debugging from the menu to begin debugging. This action automatically
launches a local server in a Node window to host your add-in and then
automatically opens the host application, such as Excel or Word. This may take
several seconds.
6. In the host application, your add-in is now ready to use. Select Show Taskpane or
run any other add-in command. A dialog box will appear similar to the following:
Select OK.
7 Note
If you select Cancel, the dialog won't be shown again while this instance of
the add-in is running. However, if you restart your add-in, you'll see the dialog
again.
7. Set a breakpoint in your project's task pane file. To set breakpoints in Visual Studio
Code, hover next to a line of code and select the red circle that appears.
8. Run functionality in your add-in that calls the lines with breakpoints. You'll see that
breakpoints have been hit and you can inspect local variables.
7 Note
) Important
The best way to stop a debugging session is to select Shift+F5 or choose Run >
Stop Debugging from the menu. This action should close the Node server window
and attempt to close the host application, but there will be a prompt on the host
application asking you whether to save the document or not. Make an appropriate
choice and let the host application close. Avoid manually closing the Node window
or host application. Doing so can cause bugs especially when you are stopping and
starting debugging sessions repeatedly.
If debugging stops working; for example, if breakpoints are being ignored; stop
debugging. Then, if necessary, close all host application windows and the Node
window. Finally, close Visual Studio Code and reopen it.
Appendix
If your project was not created with Yo Office, you need to create a debug configuration
for Visual Studio Code.
1. Create a file named launch.json in the \.vscode folder of the project if there isn't
one there already.
2. Ensure that the file has a configurations array. The following is a simple example
of a launch.json .
JSON
{
// Other properties may be here.
"configurations": [
JSON
{
"name": "HOST Desktop (Edge Legacy)",
"type": "office-addin",
"request": "attach",
"url": "https://localhost:3000/taskpane.html?
_host_Info=HOST$Win32$16.01$en-US$$$$0",
"port": 9222,
"timeout": 600000,
"webRoot": "${workspaceRoot}",
"preLaunchTask": "Debug: HOST Desktop",
"postDebugTask": "Stop Debug"
}
4. Replace the placeholder HOST in all three places with the name of the Office
application that the add-in runs in; for example, Outlook or Word .
This article describes how to debug client-side code in Office Add-ins that are created
with one of the Office Add-in project templates in Visual Studio 2022. For information
about debugging server-side code in Office Add-ins, see Overview of debugging Office
Add-ins - Server-side or client-side?.
7 Note
You can't use Visual Studio to debug add-ins in Office on Mac. For information
about debugging on a Mac, see Debug Office Add-ins on a Mac.
1. In Solution Explorer, choose the add-in project (not the web application project).
Property Description
Start Action Specifies the debug mode for your add-in. This should be set to Microsoft
Edge for an Outlook add-in. For all other Office applications, it should be set to
Office Desktop Client.
Start Specifies what document to open when you start the project. In a new project,
Document this is set to [New Excel Workbook], [New Word Document], or [New
(Excel, PowerPoint Presentation]. To specify a particular document, follow the steps in
PowerPoint, and Use an existing document to debug the add-in.
Word add-ins
only)
Property Description
Web Project Specifies the name of the web project associated with the add-in.
Email Address Specifies the email address of the user account in Exchange Server or Exchange
(Outlook add- Online that you want to use to test your Outlook add-in. If left blank, you'll be
ins only) prompted for the email address when you start debugging.
EWS Url Specifies the Exchange Web Services URL (For example:
(Outlook add- https://www.contoso.com/ews/exchange.aspx ). This property can be left blank.
ins only)
OWA Url Specifies the Outlook on the web URL (For example:
(Outlook add- https://www.contoso.com/owa ). This property can be left blank.
ins only)
Use multi- Specifies the boolean value that indicates whether multi-factor authentication
factor auth should be used. The default is false, but the property has no practical effect. If
(Outlook add- you normally have to provide a second factor to login to the email account,
ins only) you'll be prompted to when you start debugging.
User Name Specifies the name of the user account in Exchange Server or Exchange Online
(Outlook add- that you want to use to test your Outlook add-in. This property can be left
ins only) blank.
Project File Specifies the name of the file containing build, configuration, and other
information about the project.
7 Note
For an Outlook add-in, you may choose to specify values for one or more of the
Outlook add-in only properties in the Properties window, but doing so isn't
required.
The following table describes the properties of the web application project that are most
relevant to Office Add-in projects.
Property Description
SSL Specifies whether SSL is enabled on the site. This property should be set to True for
Enabled Office Add-in projects.
SSL URL Specifies the secure HTTPS URL for the site. Read-only.
Project Specifies the name of the file containing build, configuration, and other information
File about the project.
Project Specifies the location of the project file. Read-only. The manifest file that Visual
Folder Studio generates at runtime is written to the bin\Debug\OfficeAppManifests folder in
this location.
When Visual Studio builds the project, it performs the following tasks:
hosts your add-in consumes this copy when you start Visual Studio and debug the
add-in.
2. Creates a set of registry entries on your Windows computer that enables the add-
in to appear in the Office application.
3. Builds the web application project, and then deploys it to the local IIS web server
( https://localhost ).
4. If this is the first add-in project that you have deployed to the local IIS web server,
you may be prompted to install a Self-Signed Certificate to the current user's
Trusted Root Certificate store. This is required for IIS Express to display the content
of your add-in correctly.
7 Note
If Office uses the Edge Legacy webview control (EdgeHTML) to run add-ins on your
Windows computer, Visual Studio may prompt you to add a local network loopback
exemption. This is required for the webview control to be able to access the
website deployed to the local IIS web server. You can also change this setting
anytime in Visual Studio under Tools > Options > Office Tools (Web) > Web Add-
In Debugging. To find out what webview control is used on your Windows
computer, see Browsers and webview controls used by Office Add-ins.
1. Modifies the SourceLocation element of the XML manifest file (that was copied to
the _ProjectName_\bin\Debug\OfficeAppManifests directory) by replacing the
~remoteAppUrl token with the fully qualified address of the start page (for example,
https://localhost:44302/Home.html ).
) Important
The Office manifest XSD files that Visual Studio installs are out-of-date. If you
get validation errors for the manifest, your first troubleshooting step should
be to replace one or more of these files with the latest versions. For detailed
instructions, see Manifest schema validation errors in Visual Studio projects.
2. When the add-in is running, use the add-in's UI to run the code that contains your
breakpoints.
) Important
Tip
2. Launch the add-in in the Office application if it isn't already open. For example, if
it's a task pane add-in, it will have added a button to the Home ribbon (for
example, a Show Taskpane button). Select the button on the ribbon.
7 Note
If your add-in isn't sideloaded by Visual Studio, you can sideload it manually.
In Excel, PowerPoint, or Word, choose the Insert tab, and then choose the
down-arrow located to the right of My Add-ins.
In the list of available add-ins, find the Developer Add-ins section and select
the your add-in to register it.
Tip
The task pane may appear blank when it first opens. If so, it should render
correctly when you launch the debugging tools in a later step.
3. Open the personality menu and then choose Attach a debugger. This will open the
debugging tools for the webview control that Office is using to run add-ins on
your Windows computer. You can set breakpoints and step through code as
described in one of the following articles:
4. To make changes to your code, first stop the debugging session in Visual Studio
and close the Office application. Make your changes, and start a new debugging
session.
When Visual Studio builds the project it performs the following tasks.
1. Prompts you for login credentials. If you're asked to sign in repeatedly or if you
receive an error that you are unauthorized, then Basic Auth may be disabled for
accounts on your Microsoft 365 tenant. In this case, try using a Microsoft account
instead. You can also try setting the property Use multi-factor auth to True in the
Outlook Web Add-in project properties pane. See Add-in project properties.
copy when you start Visual Studio and debug the add-in.
3. Builds the web application project, and then deploys it to the local IIS web server
( https://localhost ).
4. If this is the first add-in project that you have deployed to the local IIS web server,
you may be prompted to install a Self-Signed Certificate to the current user's
Trusted Root Certificate store. This is required for IIS Express to display the content
of your add-in correctly.
7 Note
If Office uses the Edge Legacy webview control (EdgeHTML) to run add-ins on your
Windows computer, Visual Studio may prompt you to add a local network loopback
exemption. This is required for the webview control to be able to access the
website deployed to the local IIS web server. You can also change this setting
anytime in Visual Studio under Tools > Options > Office Tools (Web) > Web Add-
In Debugging. To find out what webview control is used on your Windows
computer, see Browsers and webview controls used by Office Add-ins.
1. Modifies the SourceLocation element of the XML manifest file (that was copied to
the _ProjectName_\bin\Debug\OfficeAppManifests directory) by replacing the
~remoteAppUrl token with the fully qualified address of the start page (for example,
https://localhost:44302/Home.html ).
) Important
The Office manifest XSD files that Visual Studio installs are out-of-date. If you
get validation errors for the manifest, your first troubleshooting step should
be to replace one or more of these files with the latest versions. For detailed
instructions, see Manifest schema validation errors in Visual Studio projects.
4. Opens the Outlook page of your Microsoft 365 tenancy in Microsoft Edge.
1. Set breakpoints, as needed, in the source JavaScript or TypeScript files. You can do
this either before or after you start the add-in as described in the earlier section
Start the Outlook add-in project.
2. When the add-in is running, use the add-in's UI to run the code that contains your
breakpoints.
Tip
Sometimes in Outlook on the web, the Visual Studio debugger doesn't attach.
If you get errors by the breakpoints that indicate they won't be hit, use the
browser developer tools to attach to the Visual Studio debugger: After you
have pressed F5 to start debugging and Outlook on the web has opened,
follow the first four steps in the Use the browser developer tools in Outlook
on the web. (Use the instructions for Microsoft Edge (Chromium-based).)
After you set a breakpoint in the browser tools and it's hit, execution will
pause on the breakpoint in both the browser tools and in Visual Studio. This
indicates that the Visual Studio debugger is attached. At this point, you can
close the browser tools and add breakpoints in Visual Studio as you normally
would.
If you encounter any problems, there's more information at Debug a
JavaScript or TypeScript app in Visual Studio.
3. After the tool is open, launch the add-in. For example, in the toolbar at the top of a
message, select the More apps button, and then select your add-in from the
callout that opens.
4. Use the instructions in one of the following articles to set breakpoints and step
through code. They each have a link to more detailed guidance.
Tip
breakpoints, and then close and reopen the add-in. For more information
about these functions, see Initialize your Office Add-in.
5. To make changes to your code, first stop the debugging session in Visual Studio
and close the Outlook pages. Make your changes, and start a new debugging
session.
1. In Solution Explorer, choose the add-in project (not the web application project).
2. From the menu bar, choose Project > Add Existing Item.
3. In the Add Existing Item dialog box, locate and select the document that you want
to add.
5. In Solution Explorer, choose the add-in project (not the web application project).
7. In the Properties window, choose the Start Document list, and then select the
document that you added to the project. The project is now configured to start the
add-in in that document.
Next steps
After your add-in is working as desired, see Deploy and publish your Office Add-in to
learn about the ways you can distribute the add-in to users.
Test your Office Add-in on Trident
Article • 05/20/2023
If you plan to support older versions of Windows and Office, your add-in must work in
the embeddable browser control called "Trident" that's provided by Internet Explorer 11.
You can use a command line to switch from a more modern webview used by add-ins to
Trident for this testing. For information about which versions of Windows and Office use
the Internet Explorer 11 webview control, see Browsers and webview controls used by
Office Add-ins. In this article, "webview" refers to the combination of a webview control
and a JavaScript engine.
) Important
Webviews from Internet Explorer and Microsoft Edge Legacy are still used in
Office Add-ins
We recommend (but don't require) that you support these combinations, at least in
a minimal way, by providing users of your add-in a graceful failure message when
your add-in is launched in these webviews. Keep these additional points in mind:
) Important
Trident doesn't support JavaScript versions later than ES5. If you want to use the
syntax and features of ECMAScript 2015 or later, you have to use a transpiler or
polyfill or both. For more information about these options, see Support older
Microsoft webviews and Office versions.
Also, Trident doesn't support some HTML5 features such as media, recording, and
location. To learn more, see Determine the webview the add-in is running in at
runtime.
7 Note
Office on the web can't be opened in Internet Explorer 11, so you can't (and
don't need to) test your add-in on Office on the web with Internet Explorer.
Tip
In recent versions of Office, one way to identify the webview control that Office is
using is through the personality menu on any add-in where it's available. (The
personality menu isn't supported in Outlook.) Open the menu and select Security
Info. In the Security Info dialog on Windows, the Runtime reports Microsoft Edge,
Microsoft Edge Legacy, or Internet Explorer. The runtime isn't included on the
dialog in older versions of Office.
There are two ways to switch the Trident webview. You can run a simple command in a
command prompt, or you can install a version of Office that uses Trident by default. We
recommend the first method, but you should use the second in the following scenarios.
Your project was developed with Visual Studio and IIS. It isn't node.js-based.
You want to be absolutely robust in your testing.
You can't use the Beta channel for Microsoft 365 on your development computer.
You're developing on a Mac.
If for any reason the command line tool doesn't work.
7 Note
The tool that's used to force the change in webview is supported only in the Beta
subscription channel of Microsoft 365. Join the Microsoft 365 Insider program
and select the Beta Channel option to access Office Beta builds. See also About
Office: What version of Office am I using? .
Strictly, it's the webview switch of this tool (see Step 2) that requires the Beta
channel. The tool has other switches that don't have this requirement.
1. If your project was not created with the Yeoman generator for Office Add-ins tool,
you need to install the office-addin-dev-settings tool. Run the following command
in a command prompt.
command line
) Important
The office-addin-dev-settings tool is not supported on Mac.
2. Specify the webview that you want Office to use with the following command in a
command prompt in the root of the project. Replace <path-to-manifest> with the
relative path, which is just the manifest filename if it's in the root of the project.
Replace <webview> with either ie or edge-legacy . Note that the options are
named after the browsers in which the webviews originated. The ie option means
"Trident" and the edge-legacy option means "EdgeHTML".
command line
command line
You should see a message in the command line that the webview type is now set
to IE (or Edge Legacy).
3. When you're finished, set Office to resume using the default webview for your
combination of Windows and Office versions with the following command.
command line
1. In any Office application, open the File tab on the ribbon, and then select Office
Account or Account. Select the About host-name button (for example, About
Word).
2. On the dialog that opens, find the full xx.x.xxxxx.xxxxx build number and make a
copy of it somewhere.
3. Download the Office Deployment Tool .
4. Run the downloaded file to extract the tool. You are prompted to choose where to
install the tool.
5. In the folder where you installed the tool (where the setup.exe file is located),
create a text file with the name config.xml and add the following contents.
XML
<Configuration>
<Add OfficeClientEdition="64" Channel="SemiAnnual"
Version="16.0.xxxxx.xxxxx">
<Product ID="O365ProPlusRetail">
<Language ID="en-us" />
</Product>
</Add>
</Configuration>
command line
This command installs Office. The process may take several minutes.
) Important
After installation, be sure that you turn off automatic updating of Office, so that
Office isn't updated to a version that doesn't use webview you want to work with
before you've completed using it. This can happen within minutes of installation.
Follow these steps.
When you are finished using the old version of Office, reinstall your newer version by
editing the config.xml file and changing the Version to the build number that you
copied earlier. Then repeat the setup.exe /configure config.xml command in an
administrator command prompt. Optionally, re-enable automatic updates.
See also
Test and debug Office Add-ins
Sideload Office Add-ins for testing
Debug add-ins using developer tools for Internet Explorer
Attach a debugger from the task pane
Runtimes in Office Add-ins
Window objects that are unsupported in
Office Add-ins
Article • 05/20/2023
For some versions of Windows and Office, add-ins run in a Trident (Internet Explorer 11)
webview runtime. (For details, see Browsers and webview controls used by Office Add-
ins.) Some properties or subproperties of the global window object are not supported in
Trident. These properties are disabled in add-ins to ensure that your add-in provides a
consistent experience to all users, regardless of which browser or webview control the
add-in is using. This also helps AngularJS load properly.
The following is a list of the disabled properties. The list is a work in progress. If you
discover additional window properties that do not work in add-ins, please use the
feedback tool below to tell us.
window.history.pushState
window.history.replaceState
See also
Browsers and webview controls used by Office Add-ins
Sideload Office Add-ins to Office on the
web
Article • 05/20/2023
When you sideload an add-in, you're able to install the add-in without first putting it in
an add-in catalog. This is useful when testing and developing your add-in because you
can see how your add-in will appear and function.
When you sideload an add-in on the web, the add-in's manifest is stored in the
browser's local storage, so if you clear the browser's cache, or switch to a different
browser, you have to sideload the add-in again.
The steps to sideload an add-in on the web vary based on the following factors.
In the following list, go to the section or article that matches your scenario. Note the
first scenario in the list applies to Outlook add-ins. The remaining scenarios apply to
non-Outlook add-ins.
If you're sideloading an Outlook add-in, see the article Sideload Outlook add-ins
for testing.
If you created the add-in using the Yeoman generator for Office Add-ins, see
Sideload a Yeoman-created add-in to Office on the web.
If you created the add-in using Visual Studio, see Sideload an add-in on the web
when using Visual Studio.
1. Open Office on the web or OneDrive. Using the Create option, make a
document in Excel, OneNote, PowerPoint, or Word. In this new document, select
Share, select Copy Link, and copy the URL.
2. In the command line starting at the root directory of your project, run the
following command. Replace "{url}" with the URL that you copied.
command line
https://contoso.sharepoint.com/:t:/g/EZGxP7ksiE5DuxvY638G798BpuhwluxCMfF1
WZQj3VYhYQ?e=F4QM1R
npm run start:web -- --document
https://1drv.ms/x/s!jkcH7spkM4EGgcZUgqthk4IK3NOypVw?e=Z6G1qp
npm run start:web -- --document https://contoso-my.sharepoint-
df.com/:t:/p/user/EQda453DNTpFnl1bFPhOVR0BwlrzetbXvnaRYii2lDr_oQ?
e=RSccmNP
7 Note
If you are developing on a Mac, enclose the {url} in single quotation marks.
Do not do this on Windows.
3. The first time you use this method to sideload an add-in on the web, you'll see a
dialog asking you to enable developer mode. Select the checkbox for Enable
Developer Mode now and select OK.
4. You'll see a second dialog box, asking if you wish to register an Office Add-in
manifest from your computer. Select Yes.
5. Your add-in is installed. If it has an add-in command, it should appear on either the
ribbon or the context menu. If it's a task pane add-in without any add-in
commands, the task pane should appear.
2. In the Solution Explorer, select the web project. This displays properties for the
project in the Properties window.
4. In the add-in project, open the manifest XML file. Be sure you're editing the source
XML. For some project types, Visual Studio will open a visual view of the XML
which won't work for the next step.
5. Search and replace all instances of ~remoteAppUrl/ with the SSL URL you just
copied. You'll see several replacements depending on the project type, and the
new URLs will appear similar to https://localhost:44300/Home.html .
7. In the Solution Explorer, open the context menu of the web project (for example,
by right clicking on it) then choose Debug > Start new instance. This runs the web
project without launching Office.
8. From Office on the web, sideload the add-in using steps described in Manually
sideload an add-in to Office on the web.
3. On the Office Add-ins dialog, select the MY ADD-INS tab, choose Manage My
Add-ins, and then Upload My Add-in.
5. Verify that your add-in is installed. For example, if it has an add-in command, it
should appear on either the ribbon or the context menu. If it's a task pane add-in
that has no add-in commands, the task pane should appear.
7 Note
To test your Office Add-in with EdgeHTML (Microsoft Edge Legacy), an additional
configuration step is required. In a Windows Command Prompt, run the following
line: npx office-addin-dev-settings appcontainer EdgeWebView --loopback --yes .
This isn't required when Office is using the Chromium-based Edge WebView2. For
more information, see Browsers and webview controls used by Office Add-ins.
) Important
2. Open the App Launcher on the left end of the toolbar and select Excel, OneNote,
PowerPoint, or Word, and then create a new document.
4. Follow steps 3 - 5 of the section Manually sideload an add-in to Office on the web.
See also
Sideload Office Add-ins on Mac
Sideload Office Add-ins on iPad
Sideload Outlook add-ins for testing
Clear the Office cache
Debug add-ins in Office on the web
Article • 06/27/2023
This article describes how to use Office on the web to debug your add-ins. Use this
technique:
To debug add-ins on a computer that isn't running Windows or the Office desktop
client—for example, if you're developing on a Mac or Linux.
As an alternative debugging process if you can't, or don't wish to, debug in an IDE,
such as Visual Studio or Visual Studio Code.
This article assumes that you have an add-in project that needs to be debugged. If you
just want to practice debugging on the web, create a new project using one of the quick
starts for specific Office applications, such as this quick start for Word.
1. Run the project on localhost and sideload it to a document in Office on the web.
For detailed sideloading instructions, see Manually sideload Office Add-ins on the
web.
2. Open the browser's developer tools. This is usually done by pressing F12. Open the
debugger tool and use it to set breakpoints and watch variables. For detailed help
in using your browser's tool, see one of the following:
Firefox
Safari
Debug add-ins using developer tools in Microsoft Edge (Chromium-based)
Debug add-ins using developer tools for Edge Legacy
7 Note
Potential issues
The following are some issues that you might encounter as you debug.
Some JavaScript errors that you see might originate from Office on the web.
The browser might show an invalid certificate error that you'll need to bypass. The
process for doing this varies with the browser and the various browsers' UIs for
doing this change periodically. You should search the browser's help or search
online for instructions. (For example, search for "Microsoft Edge invalid certificate
warning".) Most browsers will have a link on the warning page that enables you to
click through to the add-in page. For example, Microsoft Edge has a "Go on to the
webpage (Not recommended)" link. But you'll usually have to go through this link
every time the add-in reloads. For a longer lasting bypass, see the help as
suggested.
If you set breakpoints in your code, Office on the web might throw an error
indicating that it's unable to save.
See also
Best practices for developing Office Add-ins
Troubleshoot user errors with Office Add-ins
Sideload Office Add-ins on Mac for
testing
Article • 02/22/2023
To see how your add-in will run on Office on Mac, you can sideload your add-in's
manifest. This action won't enable you to set breakpoints and debug your add-in's code
while it's running, but you can see how it behaves and verify that the UI is usable and
rendering appropriately.
7 Note
The manifest .xml file for the add-in you want to test.
2. Enter one of the following filepaths, based on the application you want to use for
sideloading. If the wef folder doesn't exist on your computer, create it.
For Word:
/Users/<username>/Library/Containers/com.microsoft.Word/Data/Documents/w
ef
For Excel:
/Users/<username>/Library/Containers/com.microsoft.Excel/Data/Documents/
wef
For PowerPoint:
/Users/<username>/Library/Containers/com.microsoft.Powerpoint/Data/Docum
ents/wef
7 Note
4. Open Word (or restart Word if it's already running), then open a document.
5. On the Word ribbon, choose the Insert tab, and then select My Add-ins
(dropdown menu) in the Add-ins group. On the dropdown menu, choose your
add-in.
) Important
Sideloaded add-ins will not show up in the My Add-ins dialog box. They are
only visible within the drop-down menu (small down-arrow to the right of My
Add-ins on the Insert tab). Sideloaded add-ins are listed under the Developer
Add-ins heading in this menu.
See also
Sideload Office Add-ins on iPad for testing
Debug Office Add-ins on a Mac
Sideload Outlook add-ins for testing
Sideload Office Add-ins on iPad for
testing
Article • 07/11/2022
To see how your add-in will run in Office on iOS, you can sideload your add-in's
manifest onto an iPad using iTunes. This action won't enable you to set breakpoints and
debug your add-in's code while it's running, but you can see how it behaves and verify
that the UI is usable and rendering appropriately.
7 Note
) Important
An iPad running iOS 8.2 or later with Excel or Word installed, and a sync cable.
The manifest .xml file for the add-in you want to test.
5. At the bottom of the Excel or Word Documents column, choose Add File, and
then select the manifest .xml file of the add-in you want to sideload.
6. Open the Excel or Word app on your iPad. If the Excel or Word app is already
running, choose the Home button, and then close and restart the app.
7. Open a document.
8. Choose Add-ins on the Insert tab. (On the Insert tab, you may need to scroll
horizontally until you see the Add-ins button.) Your sideloaded add-in is available
to insert under the Developer heading in the Add-ins UI.
) Important
2. In Finder, under Locations, choose the iPad icon below the menu bar.
3. On the top of the Finder window, click on Files, and then locate Excel or Word.
4. From a different Finder window, drag and drop the manifest.xml file of the add-in
you want to side load onto the Excel or Word file in the first Finder window.
5. Open the Excel or Word app on your iPad. If the Excel or Word app is already
running, choose the Home button, and then close and restart the app.
6. Open a document.
7. Choose Add-ins on the Insert tab. (On the Insert tab, you may need to scroll
horizontally until you see the Add-ins button.) Your sideloaded add-in is available
to insert under the Developer heading in the Add-ins UI.
See also
Sideload Office Add-ins on Mac for testing
Debug Office Add-ins on a Mac
Sideload Outlook add-ins for testing
Debug Office Add-ins on a Mac
Article • 04/11/2023
Because add-ins are developed using HTML and JavaScript, they are designed to work
across platforms, but there might be subtle differences in how different browsers render
the HTML. This article describes how to debug add-ins running on a Mac.
) Important
Debugging add-ins with Office on Mac is only possible if Office is installed on the
Mac from Office.com , not the Apple app store.
To be able to debug Office Add-ins on Mac, you must have Mac OS High Sierra AND
Mac Office Version 16.9.1 (Build 18012504) or later. If you don't have an Office on Mac
build, you can get one by joining the Microsoft 365 developer program .
To start, open a terminal and set the OfficeWebAddinDeveloperExtras property for the
relevant Office application as follows:
true
) Important
Then, open the Office application and sideload your add-in. Right-click the add-in and
you should see an Inspect Element option in the context menu. Select that option and it
will pop the Inspector, where you can set breakpoints and debug your add-in.
7 Note
If you're trying to use the inspector and the dialog flickers, update Office to the
latest version. If that doesn't resolve the flickering, try the following workaround.
7 Note
You must run macOS Version 10.13.6 or later to see the personality menu.
Clear the cache manually
You can also clear the cache manually by deleting the contents of the
~/Library/Containers/com.Microsoft.OsfWebHost/Data/ folder. Look for this folder via
terminal.
7 Note
If that folder doesn't exist, check for the following folders via terminal and if found,
delete the contents of the folder.
~/Library/Containers/com.microsoft.{host}/Data/Library/Caches/ where
~/Library/Containers/com.microsoft.{host}/Data/Library/Application
(e.g., Excel )
~/Library/Containers/com.microsoft.Office365ServiceV2/Data/Caches/com.mic
rosoft.Office365ServiceV2/
~/Library/Containers/com.microsoft.Office365ServiceV2/Data/Library/Caches
/com.microsoft.Office365ServiceV2/
To look for these folders via Finder, you must set Finder to show hidden files. Finder
displays the folders inside the Containers directory by product name, such as
Microsoft Excel instead of com.microsoft.Excel.
Clear the Office cache
Article • 03/14/2023
To remove an add-in that you've previously sideloaded on Windows, Mac, or iOS, you
need to clear the Office cache on your computer.
Additionally, if you make changes to your add-in's manifest (for example, update file
names of icons or text of add-in commands), you should clear the Office cache and then
re-sideload the add-in using an updated manifest. Doing so allows Office to render the
add-in as it's described by the updated manifest.
7 Note
Automatically
This method is recommended for add-in development computers. If your Office on
Windows version is 2108 or later, the following steps configure the Office cache to be
cleared the next time Office is reopened.
7 Note
1. From the ribbon of any Office host except Outlook, navigate to File > Options >
Trust Center > Trust Center Settings > Trusted Add-in Catalogs.
2. Select the checkbox Next time Office starts, clear all previously-started web add-
ins cache.
Manually
The manual method for Excel, Word, and PowerPoint is different from Outlook.
To remove all sideloaded add-ins from Excel, Word, and PowerPoint, delete the contents
of the following folder.
%LOCALAPPDATA%\Microsoft\Office\16.0\Wef\
%userprofile%\AppData\Local\Packages\Microsoft.Win32WebViewHost_cw5n1h2txyew
y\AC\#!123\INetCache\
If this add-in removal doesn't work, then delete the contents of the Wef folder as noted
previously for Excel, Word, and PowerPoint.
If your Outlook add-in uses the Unified manifest for Microsoft 365 (preview), also delete
the following folder.
%userprofile%\AppData\Local\Microsoft\Outlook\HubAppFileCache
If you only want the sideloaded add-in to reflect recent changes to its HTML or
JavaScript source files, you shouldn't need to clear the cache. Instead, just put focus
in the add-in's task pane (by clicking anywhere within the task pane) and then press
Ctrl+F5 to reload the add-in.
7 Note
To clear the Office cache using the following steps, your add-in must have a task
pane. If your add-in is a UI-less add-in -- for example, one that uses the on-send
feature -- you'll need to add a task pane to your add-in that uses the same domain
for SourceLocation, before you can use the following steps to clear the cache.
4. In the Microsoft Edge DevTools, open the Local tab. Your add-in will be listed by its
name.
5. Select the add-in name to attach the debugger to your add-in. A new Microsoft
Edge DevTools window will open when the debugger attaches to your add-in.
7. If completing these steps doesn't produce the desired result, try selecting Always
refresh from server.
7 Note
You must run macOS Version 10.13.6 or later to see the personality menu.
terminal.
7 Note
If that folder doesn't exist, check for the following folders via terminal and if found,
delete the contents of the folder.
~/Library/Containers/com.microsoft.{host}/Data/Library/Caches/ where
(e.g., Excel )
~/Library/Containers/com.microsoft.Office365ServiceV2/Data/Caches/com.mic
rosoft.Office365ServiceV2/
~/Library/Containers/com.microsoft.Office365ServiceV2/Data/Library/Caches
/com.microsoft.Office365ServiceV2/
To look for these folders via Finder, you must set Finder to show hidden files. Finder
displays the folders inside the Containers directory by product name, such as
Microsoft Excel instead of com.microsoft.Excel.
See also
Troubleshoot development errors with Office Add-ins
Debug add-ins using developer tools for Internet Explorer
Debug add-ins using developer tools for Edge Legacy
Debug add-ins using developer tools in Microsoft Edge (Chromium-based)
Debug your add-in with runtime logging
Sideload Office Add-ins for testing
Office Add-ins manifest
Validate an Office Add-in's manifest
Debug your add-in with runtime
logging
Article • 05/05/2023
You can use runtime logging to debug your add-in's manifest as well as several
installation errors. This feature can help you identify and fix issues with your manifest
that are not detected by XSD schema validation, such as a mismatch between resource
IDs. Runtime logging is particularly useful for debugging add-ins that implement add-in
commands and Excel custom functions.
7 Note
The runtime logging feature is currently available for Office 2016 or later on
desktop.
) Important
Runtime Logging affects performance. Turn it on only when you need to debug
issues with your add-in manifest.
) Important
command line
command line
command line
command line
command line
7 Note
registry
[HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\16.0\Wef\Developer\Runtime
Logging]
@="C:\\ClientLogs\\log.txt"`
7 Note
The directory in which the log file will be written must already exist, and you
must have write permissions to it.
The following image shows what the registry should look like. To turn the feature off,
remove the RuntimeLogging key from the registry.
command line
<bundle id> identifies which the host for which to enable runtime logging.
<file_name> is the name of the text file to which the log will be written.
Set <bundle id> to one of the following values to enable runtime logging for the
corresponding application.
com.microsoft.Word
com.microsoft.Excel
com.microsoft.Powerpoint
com.microsoft.Outlook
The following example enables runtime logging for Word and then opens the log file.
command line
7 Note
You'll need to restart Office after running the defaults command to enable
runtime logging.
command line
The following example will turn off runtime logging for Word.
command line
7 Note
We recommend that you sideload only the add-in that you are testing to
minimize the number of messages in the log file.
2. If nothing happens and you don't see your add-in (and it's not appearing in the
add-ins dialog box), open the log file.
3. Search the log file for your add-in ID, which you define in your manifest. In the log
file, this ID is labeled SolutionId .
The message Medium Current host not in add-in's host list followed by
Unexpected Parsed manifest targeting different host is incorrectly classified as
an error.
If you see the message Unexpected Add-in is missing required manifest fields
DisplayName and it doesn't contain a SolutionId, the error is most likely not related
Any Monitorable messages are expected errors from a system point of view.
Sometimes they indicate an issue with your manifest, such as a misspelled element
that was skipped but didn't cause the manifest to fail.
See also
Office Add-ins manifest
Validate an Office Add-in's manifest
Clear the Office cache
Sideload Office Add-ins for testing
Debug add-ins using developer tools for Internet Explorer
Debug add-ins using developer tools for Edge Legacy
Debug add-ins using developer tools in Microsoft Edge (Chromium-based)
Runtimes in Office Add-ins
Debug a function command with a non-
shared runtime
Article • 08/23/2022
) Important
If your add-in is configured to use a shared runtime, you debug the code behind
the function command just as you would the code behind a task pane. See Debug
Office Add-ins and note that a function command in an add-in with a shared
runtime is not a special case as described in that article.
7 Note
This article assumes that you are familiar with function commands.
Function commands don't have a UI, so a debugger can't be attached to the process in
which the function runs on desktop Office. (Outlook add-ins being developed on
Windows are an exception to this. See Debug function commands in Outlook add-ins on
Windows later in this article.) So function commands, in add-ins with a non-shared
runtime, must be debugged on Office on the web where the function runs in the overall
browser process. Use the following steps.
1. Sideload the add-in in Office on the web, and then select the button or menu item
that runs the function command. This is necessary to load the code file for the
function command.
2. Open the browser's developer tools. This is usually done by pressing F12. The
debugger in the tools attaches to the browser process.
3. Apply breakpoints to the code as needed for the function command.
4. Rerun the function command. The process stops on your breakpoints.
Tip
For more detailed information, see Debug add-ins in Office on the web.
See also
Runtimes in Office Add-ins
Debug the initialize and onReady
functions
Article • 08/23/2022
7 Note
This article assumes that you are familiar with Initialize your Office Add-in.
Fortunately, there is an exception. You can debug these functions using Office on the
web, with the following steps.
1. Sideload and run the add-in in Office on the web. This is usually done by opening
an add-in's task pane or running a function command. The add-in runs in the
overall browser process, not a separate process as it would in desktop Office.
2. Open the browser's developer tools. This is usually done by pressing F12. The
debugger in the tools attaches to the browser process.
3. Apply breakpoints as needed to the code in the Office.initialize or
Office.onReady function.
4. Relaunch the add-in's task pane or the function command just as you did in step 1.
This action does not close the browser process or the debugger. The
Office.initialize or Office.onReady function runs again and processing stops on
your breakpoints.
Tip
For more detailed information, see Debug add-ins in Office on the web.
See also
Runtimes in Office Add-ins
Error handling with the application-
specific JavaScript APIs
Article • 06/27/2023
When you build an add-in using the application-specific Office JavaScript APIs, be sure
to include error handling logic to account for runtime errors. Doing so is critical, due to
the asynchronous nature of the APIs.
Best practices
In our code samples and Script Lab snippets, you'll notice that every call to Excel.run ,
PowerPoint.run , or Word.run is accompanied by a catch statement to catch any errors.
We recommend that you use the same pattern when you build an add-in using the
application-specific APIs.
JavaScript
API errors
When an Office JavaScript API request doesn't run successfully, the API returns an error
object that contains the following properties.
code: The code property of an error message contains a string that is part of
OfficeExtension.ErrorCodes or {application}.ErrorCodes where {application}
represents Excel, PowerPoint, or Word. For example, the error code
"InvalidReference" indicates that the reference is not valid for the specified
operation. Error codes are not localized.
debugInfo: When present, the debugInfo property of the error message provides
additional information that you can use to understand the root cause of the error.
7 Note
If you use console.log() to print error messages to the console, those messages
are only visible on the server. End users don't see those error messages in the add-
in task pane or anywhere in the Office application. To report errors to the user, see
Error notifications.
7 Note
The following tables list error messages you may encounter while using the
application-specific APIs. If you're working with the Common API, see Office
Common API error codes to learn about relevant error messages.
NotImplemented The requested feature isn't This could mean the API is
implemented. in preview or only
supported on a particular
platform (such as online-
only). See Office client
application and platform
availability for Office Add-
ins for more information.
RequestPayloadSizeLimitExceeded The request payload size has This error only occurs in
exceeded the limit. See the Office on the web.
Resource limits and
performance optimization for
Office Add-ins article for
more information.
FormulaLengthExceedsLimit The bytecode of the This error occurs in both Excel on the
applied formula web and on desktop.
exceeds the
maximum length
limit. For Office on
32-bit machines, the
bytecode length limit
is 16384 characters.
On 64-bit machines,
the bytecode length
limit is 32768
characters.
Error notifications
How you report errors to users depends on the UI system you're using.
If you're using React as the UI system, use the Fluent UI components and design
elements. We recommend that error messages be conveyed with a Dialog
component. If the error is in the user's input, configure the Input component to
display the error as bold red text.
7 Note
The Alert component can also be used to report errors to users, but it's
currently in preview and shouldn't be used in a production add-in. For
information about its release status, see the Fluent UI React v9 Component
Roadmap .
If you're not using React for the UI, consider using the older Fabric UI components
implemented directly in HTML and JavaScript. Some example templates are in the
Office-Add-in-UX-Design-Patterns-Code repository. Take a look especially in the
dialog and navigation subfolders. The sample Excel-Add-in-SalesLeads uses a
message banner.
See also
OfficeExtension.Error object
Office Common API error codes
Office Common API error codes
Article • 12/27/2022
This article documents the error messages you might encounter while using the
Common API model. These error codes don't apply to application-specific APIs, such as
the Excel JavaScript API or the Word JavaScript API.
See API models to learn more about the differences between the Common API and
application-specific API models.
Error codes
The following table lists the error codes, names, and messages displayed, and the
conditions they indicate.
1000 Invalid The specified The coercion type is not supported in the Office
Coercion coercion type is application. (For example, OOXML and HTML
Type not supported coercion types are not supported in Excel.)
1001 Data Read The current The user's current selection is not supported
Error selection is not (that is, it is something different than the
supported. supported coercion types).
1003 Data Read The specified The user supplies invalid column or row counts.
Error rowCount or
columnCount
values are
invalid.
1004 Data Read The current The current selection is not supported for the
Error selection is not specified coercion type by this application.
compatible for
the specified
coercion type.
Error.code Error.name Error.message Condition
1005 Data Read The specified The user supplies invalid startRow or startCol
Error startRow or values.
startColumn
values are
invalid.
1006 Data Read Coordinate The user tries to get partial data from a non-
Error parameters uniform table (that is, a table that has merged
cannot be used cells).
with coercion
type "Table"
when the table
contains merged
cells.
1007 Data Read The size of the The user tries to get a document larger than the
Error document is too size currently supported.
large.
1008 Data Read The requested The user requests to read data beyond the data
Error data set is too limits defined by the Office application.
large.
1009 Data Read The specified file The user sends an invalid file type.
Error type is not
supported.
2001 Data Write Cannot write to The user's current selection is not supported for
Error the current a write operation. (For example, when the user
selection. selects an image.)
2002 Data Write The supplied Multiple cells are selected (and the selection
Error data object is shape does not match the shape of the data).
not compatible Multiple cells are selected (and the selection
with the shape dimensions do not match the dimensions of the
or dimensions of data).
the current
selection.
Error.code Error.name Error.message Condition
2003 Data Write The set A single cell is selected and the supplied data
Error operation failed object overwrites data in the worksheet.
because the
supplied data
object will
overwrite data.
2004 Data Write The supplied The user supplies an object larger than the
Error data object does current selection size.
not match the
size of the
current selection.
2005 Data Write The specified The user supplies invalid startRow or startCol
Error startRow or values.
startColumn
values are
invalid.
2006 Invalid The format of The solution developer supplies an invalid HTML
Format Error the specified or OOXML string, a malformed HTML string, or
data object is an invalid OOXML string.
not valid.
2007 Invalid Data The type of the The solution developer supplies a data object
Object specified data not compatible with the specified coercion type.
object is not
compatible with
the current
selection.
2009 Data Write The specified The user tries to set data beyond the data limits
Error data object is defined by the Office application.
too large.
2010 Data Write Coordinate The user tries to set partial data from a non-
Error parameters uniform table (that is, a table that has merged
cannot be used cells).
with coercion
type Table when
the table
contains merged
cells.
Error.code Error.name Error.message Condition
3000 Binding Cannot bind to The user's selection is not supported for binding.
Creation the current (For example, the user is selecting an image or
Error selection. other non-supported object.)
3004 Binding A binding There are several conditions under which this
Creation cannot be might happen. Please see the "Binding creation
Error created with the error conditions" section later in this article.
current selection
and the specified
binding type.
3005 Invalid Operation is not The developer sends an add row or add column
Binding supported on operation on a binding type that is not of
Operation this binding coercion type table .
type.
3006 Binding The named item The named item cannot be found. No content
Creation does not exist. control or table with that name exists.
Error
3007 Binding Multiple objects Collision error: more than one content control
Creation with the same with the same name exists, and fail on collision is
Error name were set to true .
found.
3008 Binding The specified Named item can't be bound to type. For
Creation binding type is example, a content control contains text, but the
Error not compatible developer tried to bind by using coercion type
with the table .
supplied named
item.
3010 Unsupported The selected The developer is trying to use the addRowsAsync
Binding content needs to or deleteAllDataValuesAsync method of the
Operation be in table TableBinding object on data of coercion type
format. Format matrix .
the data as a
table and try
again.
4002 Settings Settings could Settings are stale and developer indicated not to
Stale Error not be saved override settings.
because they are
stale.
5000 Settings The operation is The operation is not supported in the current
Stale Error not supported. Office application. For example,
document.getSelectionAsync is called from
Outlook.
5001 Internal Error An internal error Refers to an internal error condition, which can
has occurred. occur for any of the following reasons.
5002 Permission The requested The solution developer submits a set operation,
Denied operation is not but the document is in a mode that does not
allowed on the allow modifications, such as 'Restrict Editing'.
current
document mode.
5004 Invalid API Invalid API call in An invalid call is made for the context, for
call the current example, trying to use a CustomXMLPart object in
context. Excel.
5005 Data Stale Operation failed The data on the server needs to be refreshed.
because the data
is stale on the
server.
5007 Invalid API The enumeration The enumeration is not supported in the current
call is not supported context.
in the current
context.
5009 Permission Access Denied The add-in does not have permission to call the
Denied specific API.
5012 Invalid Or Your Office The session between the Office client and server
Timed Out browser session has expired or the date, time, or time zone is
Session has expired or is incorrect on your computer.
invalid. To
continue, refresh
the page.
Error.code Error.name Error.message Condition
6000 Invalid node The specified The CustomXmlPart node was not found.
node was not
found.
7001 Invalid The object is The user can find the object, but cannot navigate
navigation located in a to it. (For example, in Word, the binding is to the
place where header, footer, or a comment.)
navigation is not
supported.
7004 Invalid The operation The user is trying to navigate to an index that is
navigation failed because out of range.
the Index is out
of range.
8010 Invalid value One or more of The common cells reference enumeration is not
the cells defined. For example, All, Data, Headers.
parameters have
values that aren't
allowed. Double-
check the values
and try again.
Error.code Error.name Error.message Condition
8011 Invalid value One or more of One of the values in tableOptions is invalid.
the tableOptions
parameters have
values that aren't
allowed. Double-
check the values
and try again.
8012 Invalid value One or more of One of the values in the format is invalid.
the format
parameters have
values that aren't
allowed. Double-
check the values
and try again.
8020 Out of range The row index The row index is more than the biggest row
value is out of index of the table or less than 0.
the allowed
range. Use a
positive value (0
or higher) that's
less than the
number of rows.
8021 Out of range The column The column index is more than the biggest
index value is column index of the table or less than 0.
out of the
allowed range.
Use a positive
value (0 or
higher) that's
less than the
number of
columns.
8022 Out of range The value is out Some of the values in the format are out of the
of the allowed supported ranges.
range.
9020 Generic An internal error Refers to an internal error condition, which can
Response has occurred. occur for any number of reasons.
Error
Error.code Error.name Error.message Condition
9021 Save Error Connection error The item couldn't be saved. This could be due to
occurred while a server connection error if using Online Mode in
trying to save Outlook desktop, or due to an attempt to re-
the item on the save a draft item that was deleted from the
server. Exchange server.
9022 Message In The EWS ID The EWS ID for the current message couldn't be
Different cannot be retrieved as the message may have been moved
Store Error retrieved or the sending mailbox may have changed.
because the
message is
saved in another
store.
9041 Network The user is no The user no longer has network or internet
error longer access.
connected to the
network. Please
check your
network
connection and
try again.
9043 Attachment The attachment The API doesn't support the attachment type.
Type Not type is not For example, item.getAttachmentContentAsync
Supported supported. throws this error if the attachment is an
embedded image in Rich Text Format, or if it's an
item type other than an email or calendar item
(such as a contact or task item).
12003 Not Not applicable. The dialog box was directed to a URL with the
applicable. HTTP protocol. HTTPS is required. Thrown within
the dialog and triggers a DialogEventReceived
event in the host page.
12005 Not Not applicable. The URL passed to displayDialogAsync uses the
applicable. HTTP protocol. HTTPS is required. Thrown by call
of displayDialogAsync . (In some versions of
Office, the error message returned with 12005 is
the same one returned for 12004.)
12006 Not Not applicable. The dialog box was closed, usually because the
applicable. user chooses the X button. Thrown within the
dialog and triggers a DialogEventReceived event
in the host page.
12007 Not Not applicable. A dialog box is already opened from this host
applicable. window. A host window, such as a task pane, can
only have one dialog box open at a time. Thrown
by call of displayDialogAsync .
12009 Not Not applicable. The user chose to ignore the dialog box. This
applicable. error can occur in online versions of Office,
where users may choose not to allow an add-in
to present a dialog. Thrown by call of
displayDialogAsync .
12011 Not Not applicable. The user's browser is configured in a way that
applicable. blocks popups. This error can occur in Office on
the web if the browser is Safari and it's
configured to block popups or the browser is
Edge Legacy and the add-in domain is in a
different security zone from the domain the
dialog is trying to open. Thrown by call of
displayDialogAsync .
13nnn Not Not applicable. See Causes and handling of errors from
applicable. getAccessToken.
Behavior in Excel
The following table summarizes binding behavior in Excel.
Matrix Range of cells (including within a table, A binding of type matrix is created on
and single cell) the selected cells. No modification in
the document is expected.
Table Range of cells (includes single cell) The binding cannot be created.
Table Range of cell within a table (includes single A binding is created in the whole table.
cell within a table, or the whole table, or
text within a cell in a table)
Table Half selection in a table and half selection The binding cannot be created.
outside the table
Table Text selected in the cell (not in the table.) The binding cannot be created.
Text Text selected in the cell A binding of type text in the whole cell
is created.
Behavior in Word
The following table summarizes binding behavior in Word.
Text Multiple selection The last selection will be wrapped with a content control
and a binding to that control. A content control of type
text is created.
See also
Office Add-ins development lifecycle
Understanding the Office JavaScript API
Error handling with the application-specific JavaScript APIs
Troubleshoot error messages for single sign-on (SSO)
Troubleshoot development errors with Office Add-ins
Troubleshoot user errors with Office
Add-ins
Article • 03/21/2023
At times your users might encounter issues with Office Add-ins that you develop. For
example, an add-in fails to load or is inaccessible. Use the information in this article to
help resolve common issues that your users encounter with your Office Add-in.
You can also use Fiddler to identify and debug issues with your add-ins.
App error: Catalog could not be Verify firewall settings."Catalog" refers to AppSource.
reached This message indicates that the user cannot access
AppSource.
APP ERROR: This app could not be Verify that the latest Office updates are installed, or
started. Close this dialog to ignore the update with the Windows Installer.
problem or click "Restart" to try again.
Error: Object doesn't support property Confirm that Internet Explorer is not running in
or method 'defineProperty' Compatibility Mode. Go to Tools > Compatibility View
Settings.
Sorry, we couldn't load the app Make sure that the browser supports HTML5 local
because your browser version is not storage, or reset your Internet Explorer settings. For
supported. Click here for a list of information about supported browsers, see
supported browser versions. Requirements for running Office Add-ins.
We recommend that you uncheck these settings only to troubleshoot the issue. If you
leave them unchecked, you will get prompts when you browse. After the issue is
resolved, check Disable script debugging (Internet Explorer) and Disable script
debugging (Other) again.
3. Verifies their identity when prompted when they try to insert an add-in.
Verify that the latest Office updates are installed, or update with the Windows Installer.
"The security settings in your browser prevent us from creating a dialog box. Try a
different browser, or configure your browser so that [URL] and the domain shown in
your address bar are in the same security zone."
Affected browsers Affected platforms
To resolve the issue, end users or administrators can add the domain of the add-in to
the list of trusted sites in the Microsoft Edge browser.
) Important
Do not add the URL for an add-in to your list of trusted sites if you don't trust the
add-in.
This issue occurs when the Dialog API is used in pop-up mode. To prevent this issue
from occurring, use the displayInFrame flag. This requires that your page support
display within an iframe. The following example shows how to use the flag.
JavaScript
Office.context.ui.displayDialogAsync(startAddress, {displayInIFrame:true},
callback);
When you add features or fix bugs in your add-in, you'll need to deploy the updates. If
your add-in is deployed by one or more admins to their organizations, some manifest
changes will require the admin to consent to the updates. Users will be blocked from
the add-in until consent is granted. The following manifest changes will require the
admin to consent again.
See also
Troubleshoot development errors with Office Add-ins
Troubleshoot development errors with
Office Add-ins
Article • 08/01/2023
Here's a list of common issues you may encounter while developing an Office Add-in.
Tip
Clearing the Office cache often fixes issues related to stale code. This guarantees
the latest manifest is uploaded, using the current file names, menu text, and other
command elements. To learn more, see Clear the Office cache.
If you develop add-ins on more than one computer and your user settings are
synchronized across the computers, try clearing the Office cache on all the
computers. Shut down all Office applications on all the computers, and then clear
the cache on all of them before you open any Office application on any of them.
If you published the manifest of the old add-in to a network share, shut down all
Office applications, clear the cache, and then be sure that the manifest for the add-
in is removed from the shared folder.
For an example of doing this in an Node.JS Express server, see this app.js file . For an
example in an ASP.NET project, see this cshtml file .
If your add-in is hosted in Internet Information Server (IIS), you could also add the
following to the web.config.
XML
<system.webServer>
<staticContent>
<clientCache cacheControlMode="UseMaxAge"
cacheControlMaxAge="0.00:00:00" cacheControlCustom="must-revalidate" />
</staticContent>
If these steps don't seem to work at first, you may need to clear the browser's cache. Do
this through the UI of the browser. Sometimes the Edge cache isn't successfully cleared
when you try to clear it in the Edge UI. If that happens, run the following command in a
Windows Command Prompt.
Bash
del /s /f /q
%LOCALAPPDATA%\Packages\Microsoft.Win32WebViewHost_cw5n1h2txyewy\AC\#!123\IN
etCache\
Changes made to property values don't happen
and there is no error message
Check the reference documentation for the property to see if it is read-only. Also, the
TypeScript definitions for Office JS specify which object properties are read-only. If you
attempt to set a read-only property, the write operation will fail silently, with no error
thrown. The following example erroneously attempts to set the read-only property
Chart.id. See also Some properties cannot be set directly.
JavaScript
If you are using Visual Studio, there may be a problem with the sideloading. Close
all instances of the Office host and Visual Studio. Restart Visual Studio and try
pressing F5 again.
The add-in's manifest has been removed from its deployment location, such as
Centralized Deployment, a SharePoint catalog, or a network share.
The value of the ID element in the manifest has been changed directly in the
deployed copy. If for any reason, you want to change this ID, first remove the add-
in from the Office host, then replace the original manifest with the changed
manifest. You many need to clear the Office cache to remove all traces of the
original. See the Clear the Office cache article for instructions on clearing the cache
for your operating system.
The add-in's manifest has a resid that is not defined anywhere in the Resources
section of the manifest, or there is a mismatch in the spelling of the resid
between where it is used and where it is defined in the <Resources> section.
There is a resid attribute somewhere in the manifest with more than 32
characters. A resid attribute, and the id attribute of the corresponding resource
in the <Resources> section, cannot be more than 32 characters.
The add-in has a custom Add-in Command but you are trying to run it on a
platform that doesn't support them. For more information, see Add-in commands
requirement sets.
If this occurs, you can update the XSD files that Visual Studio uses to the latest versions.
The latest schema versions are at [MS-OWEMXML]: Appendix A: Full XML Schema.
You can repeat the previous process for any additional schemas that are out-of-date.
Visual Studio: See Update to the latest Office JavaScript API library.
Any other IDE: See the npm packages @microsoft/office-js and @types/office-
js .
See also
Debug add-ins in Office on the web
Sideload an Office Add-in on Mac
Sideload an Office Add-in on iPad
Debug Office Add-ins on a Mac
Microsoft Office Add-in Debugger Extension for Visual Studio Code
Validate an Office Add-in's manifest
Debug your add-in with runtime logging
Troubleshoot user errors with Office Add-ins
Runtimes in Office Add-ins
Microsoft Q&A (office-js-dev)
Avoid using the context.sync method in
loops
Article • 03/14/2023
7 Note
This article assumes that you're beyond the beginning stage of working with at
least one of the four application-specific Office JavaScript APIs—for Excel, Word,
OneNote, and Visio—that use a batch system to interact with the Office document.
In particular, you should know what a call of context.sync does and you should
know what a collection object is. If you're not at that stage, please start with
Understanding the Office JavaScript API and the documentation linked to under
"application-specific" in that article.
For some programming scenarios in Office Add-ins that use one of the application-
specific API models (for Excel, Word, OneNote, and Visio), your code needs to read,
write, or process some property from every member of a collection object. For example,
an Excel add-in that needs to get the values of every cell in a particular table column or
a Word add-in that needs to highlight every instance of a string in the document. You
need to iterate over the members in the items property of the collection object; but, for
performance reasons, you need to avoid calling context.sync in every iteration of the
loop. Every call of context.sync is a round trip from the add-in to the Office document.
Repeated round trips hurt performance, especially if the add-in is running in Office on
the web because the round trips go across the internet.
7 Note
All examples in this article use for loops but the practices described apply to any
loop statement that can iterate through an array, including the following:
for
for of
while
do while
They also apply to any array method to which a function is passed and applied to
the items in the array, including the following:
Array.every
Array.forEach
Array.filter
Array.find
Array.findIndex
Array.map
Array.reduce
Array.reduceRight
Array.some
7 Note
It's generally a good practice to put have a final context.sync just before the
closing "}" character of the application run function (such as Excel.run , Word.run ,
etc.). This is because the run function makes a hidden call of context.sync as the
last thing it does if, and only if, there are queued commands that have not yet been
synchronized. The fact that this call is hidden can be confusing, so we generally
recommend that you add the explicit context.sync . However, given that this article
is about minimizing calls of context.sync , it is actually more confusing to add an
entirely unnecessary final context.sync . So, in this article, we leave it out when
there are no unsynchronized commands at the end of the run .
JavaScript
// Record the system time again then calculate how long the operation
took.
endTime = performance.now();
console.log("The operation took: " + (endTime - startTime) + "
milliseconds.");
})
The preceding code took 1 full second to complete in a document with 200 instances of
"the" in Word on Windows. But when the await context.sync(); line inside the loop is
commented out and the same line just after the loop is uncommented, the operation
took only a 1/10th of a second. In Word on the web (with Edge as the browser), it took 3
full seconds with the synchronization inside the loop and only 6/10ths of a second with
the synchronization after the loop, about five times faster. In a document with 2000
instances of "the", it took (in Word on the web) 80 seconds with the synchronization
inside the loop and only 4 seconds with the synchronization after the loop, about 20
times faster.
7 Note
Just as the commands in a synchronization batch job are queued, the batch
jobs themselves are queued in Office, but Office supports no more than 50
batch jobs in the queue. Any more triggers errors. So, if there are more than
50 iterations in a loop, there is a chance that the queue size is exceeded. The
greater the number of iterations, the greater the chance of this happening.
"Concurrently" does not mean simultaneously. It would still take longer to
execute multiple synchronization operations than to execute one.
Concurrent operations are not guaranteed to complete in the same order in
which they started. In the preceding example, it doesn't matter what order the
word "the" gets highlighted, but there are scenarios where it's important that
the items in the collection be processed in order.
JavaScript
In this scenario, to avoid having a context.sync in a loop, you should use a pattern we
call the split loop pattern. Let's see a concrete example of the pattern before we get to a
formal description of it. Here's how the split loop pattern can be applied to the
preceding code snippet. Note the following about this code.
There are now two loops and the context.sync comes between them, so there's
no context.sync inside either loop.
The first loop iterates through the items in the collection object and loads the text
property just as the original loop did, but the first loop cannot log the paragraph
text because it no longer contains a context.sync to populate the text property
of the paragraph proxy object. Instead, it adds the paragraph object to an array.
The second loop iterates through the array that was created by the first loop, and
logs the text of each paragraph item. This is possible because the context.sync
that came between the two loops populated all the text properties.
JavaScript
await context.sync();
The preceding example suggests the following procedure for turning a loop that
contains a context.sync into the split loop pattern.
You don't need to actually produce an add-in with this UI to experiment with the code.
You can use the Script Lab tool to prototype the important code. Use the following
assignment statement to create the mapping array.
JavaScript
const jobMapping = [
{ job: "{Coordinator}", person: "Sally" },
{ job: "{Deputy}", person: "Bob" },
{ job: "{Manager}", person: "Kim" }
];
The following code shows how you might replace each placeholder with its assigned
name if you used context.sync inside loops.
JavaScript
await context.sync();
await context.sync();
}
}
});
In the preceding code, there is an outer and an inner loop. Each of them contains a
context.sync . Based on the very first code snippet in this article, you probably see that
the context.sync in the inner loop can simply be moved after the inner loop. But that
would still leave the code with a context.sync (two of them actually) in the outer loop.
The following code shows how you can remove context.sync from the loops. We
discuss the code below.
JavaScript
await context.sync()
await context.sync();
});
The outer loop from the preceding example has been split into two. (The second
loop has an inner loop, which is expected because the code is iterating over a set
of jobs (or placeholders) and within that set it is iterating over the matching
ranges.)
There is a context.sync after each major loop, but no context.sync inside any
loop.
The second major loop iterates through an array that is created in the first loop.
But the array created in the first loop does not contain only an Office object as the first
loop did in the section Reading values from the document with the split loop pattern.
This is because some of the information needed to process the Word Range objects is
not in the Range objects themselves but instead comes from the jobMapping array.
So, the objects in the array created in the first loop are custom objects that have two
properties. The first is an array of Word Ranges that match a specific job title (that is, a
placeholder string) and the second is a string that provides the name of the person
assigned to the job. This makes the final loop easy to write and easy to read because all
of the information needed to process a given range is contained in the same custom
object that contains the range. The name that should replace
correlatedObject.rangesMatchingJob.items[ j] is the other property of the same object:
correlatedObject.personAssignedToJob.
We call this variation of the split loop pattern the correlated objects pattern. The
general idea is that the first loop creates an array of custom objects. Each object has a
property whose value is one of the items in an Office collection object (or an array of
such items). The custom object has other properties, each of which provides information
needed to process the Office objects in the final loop. See the section Other examples of
these patterns for a link to an example where the custom correlating object has more
than two properties.
One further caveat: sometimes it takes more than one loop just to create the array of
custom correlating objects. This can happen if you need to read a property of each
member of one Office collection object just to gather information that will be used to
process another collection object. (For example, your code needs to read the titles of all
the columns in an Excel table because your add-in is going to apply a number format to
the cells of some columns based on that column's title.) But you can always keep the
context.sync s between the loops, rather than in a loop. See the section Other examples
of these patterns for an example.
loop over a collection object. Instead, define subsets of the items in the collection and
loop over each subset in turn, with a context.sync between the loops. You could
structure this with an outer loop that iterates over the subsets and contains the
context.sync in each of these outer iterations.
Resource limits and performance
optimization for Office Add-ins
Article • 04/11/2023
To create the best experience for your users, ensure that your Office Add-in performs
within specific limits for CPU core and memory usage, reliability, and, for Outlook add-
ins, the response time for evaluating regular expressions. These run-time resource usage
limits apply to add-ins running in Office clients on Windows and OS X, but not on
mobile apps or in a browser.
You can also optimize the performance of your add-ins on desktop and mobile devices
by optimizing the use of resources in your add-in design and implementation.
CPU core usage - A single CPU core usage threshold of 90%, observed three times
in default 5-second intervals.
The default interval for an Office client to check CPU core usage is every 5 seconds.
If the Office client detects the CPU core usage of an add-in is above the threshold
value, it displays a message asking if the user wants to continue running the add-
in. If the user chooses to continue, the Office client does not ask the user again
during that edit session. Administrators might want to use the AlertInterval
registry key to raise the threshold to reduce the display of this warning message if
users run CPU-intensive add-ins.
By default, when a Office client detects that physical memory usage on a device
exceeds 80% of the available memory, the client starts monitoring the add-in's
memory usage, at a document level for content and task pane add-ins, and at a
mailbox level for Outlook add-ins. At a default interval of 5 seconds, the client
warns the user if physical memory usage for a set of add-ins at the document or
mailbox level exceeds 50%. This memory usage limit uses physical rather than
virtual memory to ensure performance on devices with limited RAM, such as
tablets. Administrators can override this dynamic setting with an explicit limit by
using the MemoryAlertThreshold Windows registry key as a global setting, ir
adjust the alert interval by using the AlertInterval key as a global setting.
This affects the user's experiences of the add-in and the Office application. When
this occurs, the Office application automatically restarts all the active add-ins for a
document or mailbox (where applicable), and warns the user as to which add-in
became unresponsive. Add-ins can reach this threshold when they do not regularly
yield processing while performing long-running tasks. There are techniques to
ensure that blocking does not occur. Administrators cannot override this threshold.
Outlook add-ins
If any Outlook add-in exceeds the preceding thresholds for CPU core or memory usage,
or tolerance limit for crashes, Outlook disables the add-in. The Exchange Admin Center
displays the disabled status of the app.
7 Note
Even though only the Outlook rich clients and not Outlook on the web or mobile
devices monitor resource usage, if a rich client disables an Outlook add-in, that
add-in is also disabled for use in Outlook on the web and mobile devices.
In addition to the CPU core, memory, and reliability rules, Outlook add-ins should
observe the following rules on activation.
Excel add-ins
If you're building an Excel add-in, be aware of the following size limitations when
interacting with the workbook.
Excel on the web has a payload size limit for requests and responses of 5MB.
RichAPI.Error will be thrown if that limit is exceeded.
A range is limited to five million cells for get operations.
If you expect user input to exceed these limits, be sure to check the data before calling
context.sync() . Split the operation into smaller pieces as needed. Be sure to call
together again.
These limitations are typically exceeded by large ranges. Your add-in might be able to
use RangeAreas to strategically update cells within a larger range. For more information
about working with RangeAreas , see Work with multiple ranges simultaneously in Excel
add-ins. For additional information about optimizing payload size in Excel, see Payload
size limit best practices.
%Users%\<Current user>\AppData\Local\Microsoft\Office\16.0\Telemetry
For each event that the Telemetry Log tracks for an add-in, there is a date/time of the
occurrence, event ID, severity, and short descriptive title for the event, the friendly name
and unique ID of the add-in, and the application that logged the event. You can refresh
the Telemetry Log to see the current tracked events. The following table shows examples
of Outlook add-ins that were tracked in the Telemetry log.
The following table lists the events that the Telemetry Log tracks for Office Add-ins in
general.
7 Add-in Not The manifest of the Office Add-in was successfully loaded
manifest applicable and read by the Office application.
downloaded
successfully
8 Add-in Critical The Office application was unable to load the manifest file for
manifest did the Office Add-in from the SharePoint catalog, corporate
not catalog, or AppSource.
download
Event Title Severity Description
ID
9 Add-in Critical The Office application loaded the Office Add-in manifest, but
markup could not read the HTML markup of the app.
could not be
parsed
10 Add-in used Critical The Office Add-in used more than 90% of the CPU resources
too much over a finite period of time.
CPU
15 Add-in Not Outlook add-ins search the subject line and message of an e-
disabled applicable mail to determine whether they should be displayed by using
due to a regular expression. The Outlook add-in listed in the File
string search column was disabled by Outlook because it timed out
time-out repeatedly while trying to match a regular expression.
18 Add-in Not The Office application was able to close the Office Add-in
closed applicable successfully.
successfully
19 Add-in Critical The Office Add-in had a problem that caused it to fail. For
encountered more details, look at the Microsoft Office Alerts log using
runtime the Windows Event Viewer on the computer that
error encountered the error.
20 Add-in Critical The licensing information for the Office Add-in could not be
failed to verified and may have expired. For more details, look at the
verify Microsoft Office Alerts log using the Windows Event Viewer
licensing on the computer that encountered the error.
For more information, see Deploying Telemetry Dashboard and Troubleshooting Office
files and custom solutions with the telemetry log.
If your add-in uses a CPU-intensive algorithm but you can divide the data input or
output into smaller sets, consider creating a web service, passing the data to the
web service to off-load the CPU, and wait for an asynchronous callback.
Test your add-in against the highest volume of data you expect, and restrict your
add-in to process up to that limit.
7 Note
The following Excel code sample fills a selected range with data, one cell at a time. After
the value is added to the cell, the range representing that cell is untracked. Run this
code with a selected range of 10,000 to 20,000 cells, first with the cell.untrack() line,
and then without it. You should notice the code runs faster with the cell.untrack() line
than without it. You may also notice a quicker response time afterwards, since the
cleanup step takes less time.
JavaScript
await context.sync();
});
Note that needing to untrack objects only becomes important when you're dealing with
thousands of them. Most add-ins will not need to manage proxy object tracking.
See also
Privacy and security for Office Add-ins
Limits for activation and JavaScript API for Outlook add-ins
Performance optimization using the Excel JavaScript API
Unit testing in Office Add-ins
Article • 02/22/2023
Unit tests check your add-in's functionality without requiring network or service
connections, including connections to the Office application. Unit testing server-side
code, and client-side code that does not call the Office JavaScript APIs, is the same in
Office Add-ins as it is in any web application, so it requires no special documentation.
But client-side code that calls the Office JavaScript APIs is challenging to test. To solve
these problems, we have created a library to simplify the creation of mock Office objects
in unit tests: Office-Addin-Mock . The library makes testing easier in the following
ways:
The Office JavaScript APIs must initialize in a webview control in the context of an
Office application (Excel, Word, etc.), so they cannot be loaded in the process in
which unit tests run on your development computer. The Office-Addin-Mock
library can be imported into your test files, which enables the mocking of Office
JavaScript APIs inside the node.js process in which the tests run.
The application-specific APIs have load and sync methods that must be called in a
particular order relative to other functions and to each other. Moreover, the load
method must be called with certain parameters depending on what what
properties of Office objects are going to be read in by code later in the function
being tested. But unit testing frameworks are inherently stateless, so they cannot
keep a record of whether load or sync was called or what parameters were passed
to load . The mock objects that you create with the Office-Addin-Mock library have
internal state that keeps track of these things. This enables the mock objects to
emulate the error behavior of actual Office objects. For example, if the function
that is being tested tries to read a property that was not first passed to load , then
the test will return an error similar to what Office would return.
The library doesn't depend on the Office JavaScript APIs and it can be used with any
JavaScript unit testing framework, such as:
Jest
Mocha
Jasmine
The examples in this article use the Jest framework. There are examples using the Mocha
framework at the Office-Addin-Mock home page .
Prerequisites
This article assumes that you are familiar with the basic concepts of unit testing and
mocking, including how to create and run test files, and that you have some experience
with a unit testing framework.
Tip
If you are working with Visual Studio, we recommend that you read the article Unit
testing JavaScript and TypeScript in Visual Studio for some basic information
about JavaScript unit testing in Visual Studio and then return to this article.
command line
Basic usage
1. Your project will have one or more test files. (See the instructions for your test
framework and the example test files in Examples below.) Import the library, with
either the require or import keyword, to any test file that has a test of a function
that calls the Office JavaScript APIs, as shown in the following example.
JavaScript
2. Import the module that contains the add-in function that you want to test with
either the require or import keyword. The following is an example that assumes
your test file is in a subfolder of the folder with your add-in's code files.
JavaScript
3. Create a data object that has the properties and subproperties that you need to
mock to test the function. The following is an example of an object that mocks the
Excel Workbook.range.address property and the Workbook.getSelectedRange
method. This isn't the final mock object. Think of it as a seed object that is used by
OfficeMockObject to create the final mock object.
JavaScript
const mockData = {
workbook: {
range: {
address: "C2:G3",
},
getSelectedRange: function () {
return this.range;
},
},
};
4. Pass the data object to the OfficeMockObject constructor. Note the following
about the returned OfficeMockObject object.
tries to read a property without first loading the property and calling sync ,
then the test will fail with an error similar to what would be thrown in
production runtime: "Error, property not loaded".
JavaScript
7 Note
5. In the syntax of your test framework, add a test of the function. Use the
OfficeMockObject object in place of the object that it mocks, in this case the
JavaScript
6. Run the test in accordance with documentation of the test framework and your
development tools. Typically, there is a package.json file with a script that executes
the test framework. For example, if Jest is the framework, package.json would
contain the following:
JSON
"scripts": {
"test": "jest",
-- other scripts omitted --
}
To run the test, enter the following in a command prompt in the root of the
project.
command line
npm test
Examples
The examples in this section use Jest with its default settings. These settings support
CommonJS modules. See the Jest documentation for how to configure Jest and
node.js to support ECMAScript modules and to support TypeScript. To run any of these
examples, take the following steps.
1. Create an Office Add-in project for the appropriate Office host application (for
example, Excel or Word). One way to do this quickly is to use the Yeoman
generator for Office Add-ins.
2. In the root of the project, install Jest .
3. Install the office-addin-mock tool.
4. Create a file exactly like the first file in the example and add it to the folder that
contains the project's other source files, often called \src .
5. Create a subfolder to the source file folder and give it an appropriate name, such
as \tests .
6. Create a file exactly like the test file in the example and add it to the subfolder.
7. Add a test script to the package.json file, and then run the test, as described in
Basic usage.
JavaScript
const myCommonAPIAddinFeature = {
module.exports = myCommonAPIAddinFeature;
The OfficeMockObject constructor does not add all of the Office enum classes to
the mock Office object, so the CoercionType.Text value that is referenced in the
add-in method must be added explicitly in the seed object.
Because the Office JavaScript library isn't loaded in the node process, the Office
object that is referenced in the add-in code must be declared and initialized.
JavaScript
/* Code that calls the test framework goes below this line. */
// Jest test
test("Text of selection in document should be set to 'Hello World'", async
function () {
await myCommonAPIAddinFeature.addHelloWorldText();
expect(officeMock.context.document.data).toBe("Hello World!");
});
JavaScript
const myOutlookAddinFeature = {
The host property on the mock object is used internally by the mock library to
identify the Office application. It's mandatory for Outlook. It currently serves no
purpose for any other Office application.
Because the Office JavaScript library isn't loaded in the node process, the Office
object that is referenced in the add-in code must be declared and initialized.
JavaScript
/* Code that calls the test framework goes below this line. */
// Jest test
test("Text of selection in message should be set to 'Hello World'", async
function () {
await myOutlookAddinFeature.addHelloWorldText();
expect(officeMock.context.mailbox.item.data).toBe("Hello World!");
});
Mocking the Office application-specific APIs
When you are testing functions that use the application-specific APIs, be sure that you
are mocking the right type of object. There are two options:
Mock a Host object, such as Excel or Word. Do this when the preceding option isn't
possible.
7 Note
Excel.run .
JavaScript
const myExcelAddinFeature = {
await context.sync();
return range.address;
}
}
module.exports = myExcelAddinFeature;
JavaScript
/* Code that calls the test framework goes below this line. */
// Jest test
test("getSelectedRangeAddress should return address of selected range",
async function () {
expect(await
myOfficeAddinFeature.getSelectedRangeAddress(contextMock)).toBe("C2:G3");
});
JavaScript
const myWordAddinFeature = {
await context.sync();
});
}
}
module.exports = myWordAddinFeature;
When the OfficeMockObject constructor creates the final mock object, it will
ensure that the child ClientRequestContext object has sync and load methods.
The OfficeMockObject constructor does not add a run function to the mock Word
object, so it must be added explicitly in the seed object.
The OfficeMockObject constructor does not add all of the Word enum classes to
the mock Word object, so the InsertLocation.end value that is referenced in the
add-in method must be added explicitly in the seed object.
Because the Office JavaScript library isn't loaded in the node process, the Word
object that is referenced in the add-in code must be declared and initialized.
JavaScript
/* Code that calls the test framework goes below this line. */
expect(wordMock.context.document.body.paragraph.font.color).toBe("blue");
});
7 Note
See also
Office-Addin-Mock npm page installation point.
The open source repo is Office-Addin-Mock .
Jest
Mocha
Jasmine
Usability testing for Office Add-ins
Article • 11/01/2022
A great add-in design takes user behaviors into account. Because your own
preconceptions influence your design decisions, it’s important to test designs with real
users to make sure that your add-ins work well for your customers.
You can run usability tests in different ways. For many add-in developers, remote,
unmoderated usability studies are the most time and cost effective. Several popular
testing services make this easy; the following are some examples.
UserTesting.com
Optimalworkshop.com
Userzoom.com
These testing services help you to streamline test plan creation and remove the need to
seek out participants or moderate the tests.
You need only five participants to uncover most usability issues in your design.
Incorporate small tests regularly throughout your development cycle to ensure that your
product is user-centered.
7 Note
We recommend that you test the usability of your add-in across multiple platforms.
To publish your add-in to AppSource, it must work on all platforms that support
the methods that you define.
Specific
Broad
What are the biggest pain points for the user in our add-in?
Do users understand the meaning of the icons in our command bar, before they
click on them?
Can users easily find the settings menu?
It’s important to get data on the entire user journey – from discovering your add-in, to
installing and using it. Consider research questions that address the following aspects of
the add-in user experience.
For more information, see Gathering factual responses vs. subjective data .
For example, if you want to find participants who are familiar with GitHub, to filter out
users who might misrepresent themselves, include fakes in the list of possible answers.
Which of the following source code repositories are you familiar with?
a. SourceShelf [Reject]
b. CodeContainer [Reject]
c. GitHub [Must select]
d. BitBucket [May select]
e. CloudForge [May select]
If you are planning to test a live build of your add-in, the following questions can screen
for users who will be able to do this.
This test requires you to have the latest version of Microsoft PowerPoint. Do you have
the latest version of PowerPoint?
a. Yes [Must select]
b. No [Reject]
c. I don’t know [Reject]
This test requires you to install a free add-in for PowerPoint, and create a free account
to use it. Are you willing to install an add-in and create a free account?
a. Yes [Must select]
b. No [Reject]
Try to observe participant behaviors instead of asking about them, whenever possible. If
you need to ask about behaviors, ask about what participants have done in the past,
rather than what they would expect to do in a situation. This tends to give more reliable
results.
The main challenge in unmoderated testing is making sure your participants understand
your tasks and scenarios. Your directions should be clear and concise. Inevitably, if there
is potential for confusion, someone will be confused.
Don't assume that your user will be on the screen they’re supposed to be on at any
given point during the test. Consider telling them what screen they need to be on to
start the next task.
On average, it takes about 5 minutes to walk users through how to install an add-in. The
following is an example of clear, concise installation steps. Adjust the steps based on the
specifics of your test.
Please install the (insert your add-in name here) add-in for PowerPoint, using the
following instructions.
You can test a prototype at any level of interaction and visual fidelity. For more complex
linking and interactivity, consider a prototyping tool like InVision . If you just want to
test static screens, you can host images online and send participants the corresponding
URL, or give them a link to an online PowerPoint presentation.
9. Analyze results
This is the part where you try to make sense of the data you’ve collected. While
watching the test videos, record notes about problems and successes the user has.
Avoid trying to interpret the meaning of the data until you have viewed all the results.
A single participant having a usability issue is not enough to warrant making a change
to the design. Two or more participants encountering the same issue suggests that
other users in the general population will also encounter that issue.
In general, be careful about how you use your data to draw conclusions. Don’t fall into
the trap of trying to make the data fit a certain narrative; be honest about what the data
actually proves, disproves, or simply fails to provide any insight about. Keep an open
mind; user behavior frequently defies designer’s expectations.
See also
How to Conduct Usability Testing
Best Practices for UserTesting
Minimizing Bias
Validate an Office Add-in's manifest
Article • 04/14/2023
You may want to validate your add-in's manifest file to ensure that it's correct and
complete. Validation can also identify issues that are causing the error "Your add-in
manifest is not valid" when you attempt to sideload your add-in. This article describes
multiple ways to validate the manifest file.
7 Note
For details about using runtime logging to troubleshoot issues with your add-in's
manifest, see Debug your add-in with runtime logging.
command line
To access this functionality, your add-in project must be created using the Yeoman
generator for Office Add-ins version 1.1.17 or later.
1. Install Node.js .
2. Open a command prompt and install the validator with the following command.
command line
command line
If this command is not available or not working, run the following command
instead to force the use of the latest version of the office-addin-manifest tool
(replacing MANIFEST_FILE with the name of the manifest file).
command line
command line
If you're having trouble with that command, try the following (replacing MANIFEST_FILE
with the name of the manifest file).
command line
command line
See also
Office Add-ins manifest
Clear the Office cache
Debug your add-in with runtime logging
Sideload Office Add-ins for testing
Debug add-ins using developer tools for Internet Explorer
Debug add-ins using developer tools for Edge Legacy
Debug add-ins using developer tools in Microsoft Edge (Chromium-based)
Deploy and publish Office Add-ins
Article • 08/15/2023
You can use one of several methods to deploy your Office Add-in for testing or
distribution to users. The deployment method can also affect which platforms surface
your add-in.
Method Use...
Network share As part of your development process, to test your add-in running on Windows
after you have published the add-in to a server other than localhost. (Not for
production add-ins or for testing on iPad, Mac, or the web.)
Microsoft 365 In a cloud deployment, to distribute your add-in to users in your organization
admin center by using the Microsoft 365 admin center. This is done through Integrated
Apps or Centralized Deployment.
7 Note
If you plan to publish your add-in to AppSource and make it available within the
Office experience, make sure that you conform to the Commercial marketplace
certification policies. For example, to pass validation, your add-in must work across
all platforms that support the methods that you define (for more information, see
section 1120.3 and the Office Add-in application and availability page).
Deploy updates
When you add features or fix bugs in your add-in, you'll need to deploy the updates. If
your add-in is deployed by one or more admins to their organizations, some manifest
changes will require the admin to consent to the updates. Users will be blocked from
the add-in until consent is granted. The following manifest changes will require the
admin to consent again.
Changes to requested permissions. See Requesting permissions for API use in add-
ins and Understanding Outlook add-in permissions.
Additional or changed Scopes. (Not applicable if the add-in uses the unified
manifest for Microsoft 365.)
Additional or changed Outlook events.
7 Note
Whenever you make a change to the manifest, you must raise the version number
of the manifest.
For information about how end users acquire, insert, and run add-ins, see Start using
your Office Add-in .
When you link your Office Add-ins, Teams apps, SPFx apps, and other apps together,
you create a single software as a service (SaaS) offering for your customers. For general
information about this process, see How to plan a SaaS offer for the commercial
marketplace. For specifics on how to create Integrated Apps, see Configure Microsoft
365 App integration.
For more information on the Integrated Apps deployment process, see Test and deploy
Microsoft 365 Apps by partners in the Integrated apps portal.
) Important
7 Note
SharePoint catalogs do not support Office on Mac. To deploy Office Add-ins to Mac
clients, you must submit them to AppSource.
To assign add-ins to tenants, use the Exchange admin center to upload a manifest
directly, either from a file or a URL, or add an add-in from AppSource. To assign add-ins
to individual users, you must use Exchange PowerShell. For details, see Add-ins for
Outlook in Exchange Server.
See also
Sideload Outlook add-ins for testing
Submit to AppSource
AppSource
Design guidelines for Office Add-ins
Create effective AppSource listings
Troubleshoot user errors with Office Add-ins
What is the Microsoft commercial marketplace?
Microsoft Dev Center app publishing page
Publish an add-in developed with Visual
Studio Code
Article • 03/28/2023
This article describes how to publish an Office Add-in that you created using the
Yeoman generator and developed with Visual Studio Code (VS Code) or any other
editor.
7 Note
For information about publishing an Office Add-in that you created using
Visual Studio, see Publish your add-in using Visual Studio.
For information about publishing an Office Add-in that you created using
Teams Toolkit, see Deploy Teams app to the cloud and Deploy your first
Teams app. This article is about Teams tab apps, but it is applicable to Office
Add-ins created with Teams Toolkit.
While you're developing, you can run the add-in on your local web server ( localhost ).
When you're ready to publish it for other users to access, you'll need to deploy the web
application and update the manifest to specify the URL of the deployed application.
When your add-in is working as desired, you can publish it directly through Visual
Studio Code using the Azure Storage extension.
7 Note
These steps only work for projects created with the Yeoman generator, and that use
the XML-formatted manifest. They do not apply if you created the add-in using the
Teams Toolkit or created it with the Yeoman generator and it uses the unified
manifest for Microsoft 365.
1. Open your project from its root folder in Visual Studio Code (VS Code).
4. Once installed, an Azure icon is added to the Activity Bar. Select it to access the
extension. If the Activity Bar is hidden, open it by selecting View > Appearance >
Activity Bar.
5. Select Sign in to Azure to sign in to your Azure account. If you don't already have
an Azure account, create one by selecting Create an Azure Account. Follow the
provided steps to set up your account.
6. Once you're signed in, you'll see your Azure storage accounts appear in the
extension. If you don't already have a storage account, create one using the Create
Storage Account option in the command palette. Name your storage account a
globally unique name, using only 'a-z' and '0-9'. Note that by default, this creates a
storage account and a resource group with the same name. It automatically puts
the storage account in West US. This can be adjusted online through your Azure
account .
7. Right-click your storage account and select Configure Static Website. You'll be
asked to enter the index document name and the 404 document name. Change
the index document name from the default index.html to taskpane.html . You may
also change the 404 document name but are not required to.
8. Right-click your storage account again and this time select Browse Static Website.
From the browser window that opens, copy the website URL.
9. Open your project's manifest file ( manifest.xml ) and change all references to your
localhost URL (such as https://localhost:3000 ) to the URL you've copied. This
endpoint is the static website URL for your newly created storage account. Save
the changes to your manifest file.
10. Open a command line prompt or terminal window and go to the root directory of
your add-in project. Run the following command to prepare all files for production
deployment.
command line
When the build completes, the dist folder in the root directory of your add-in
project will contain the files that you'll deploy in subsequent steps.
11. In VS Code, go to the Explorer and Right-click the dist folder, and select Deploy to
Static Website via Azure Storage. When prompted, select the storage account you
created previously.
12. When deployment is complete, right-click the storage account that you created
previously and select Browse Static Website. This opens the static web site and
displays the task pane.
13. Finally, sideload the manifest file and the add-in will load from the static web site
you just deployed.
2. In the Settings group, select Resource sharing (CORS). You can also use the search
box to find this.
3. Create a new CORS rule with the following settings.
Property Value
Allowed origins *
Allowed headers *
4. Select Save.
U Caution
This CORS configuration assumes all files on your server are publicly available to all
domains.
XML
<?xml version="1.0"?>
<configuration>
<system.webServer>
<staticContent>
<mimeMap fileExtension=".json" mimeType="application/json" />
</staticContent>
</system.webServer>
</configuration>
4. Add the following code in the list of plugins to copy the web.config into the
bundle when the build runs.
JavaScript
new CopyWebpackPlugin({
patterns: [
{
from: "src/web.config",
to: "src/web.config",
},
],
}),
5. Open a command line prompt and go to the root directory of your add-in project.
Then, run the following command to prepare all files for deployment.
command line
When the build completes, the dist folder in the root directory of your add-in
project will contain the files that you'll deploy.
6. To deploy, in the VS Code Explorer, Right-click the dist folder, and select Deploy
to Static Website via Azure Storage. When prompted, select the storage account
you created previously. If you already deployed the dist folder, you'll be prompted
if you want to overwrite the files in the Azure storage with the latest changes.
Deploy updates
When you add features or fix bugs in your add-in, you'll need to deploy the updates. If
your add-in is deployed by one or more admins to their organizations, some manifest
changes will require the admin to consent to the updates. Users will be blocked from
the add-in until consent is granted. The following manifest changes will require the
admin to consent again.
See also
Develop Office Add-ins with Visual Studio Code
Deploy and publish your Office Add-in
Cross-Origin Resource Sharing (CORS) support for Azure Storage
Deploy a single sign-on (SSO) Office
Add-in to Microsoft Azure App Service
Article • 03/28/2023
Office Add-ins that use SSO require server-side code. To support server-side code in
deployment you need to use Azure App Service. Follow the steps in this article to deploy
your Office Add-in to Azure App Service for staging or deployment.
Prerequisites
The steps in this article work for an Office Add-in created by the Yeoman Generator for
Office Add-ins using the Office Add-in Task Pane project supporting single sign-on
(localhost) project type. Be sure you have configured the add-in project so that it runs
on localhost successfully. For more information, see the Single sign-on (SSO) quick start.
7 Note
For information about deploying an Office Add-in that you created using Teams
Toolkit, see Deploy Teams app to the cloud and Deploy your first Teams app. Add-
ins created with the Teams Toolkit use the unified manifest for Microsoft 365
(preview). At this time, SSO-enabled add-ins that use this manifest can be
published only by sideloading. For more information about publication of add-ins
and sideloading, see Deploy and publish Office Add-ins.
Sign in to Azure
1. Open your Office Add-in project in VS Code.
2. Select the Azure logo in the Activity Bar . If the Activity Bar is hidden, open it by
selecting View > Appearance > Activity Bar.
3. In the App Service explorer, select Sign in to Azure... and follow the instructions.
Deploy to Windows
1. Right-click on App Services and select Create new Web App... Advanced.
2. Type a globally unique name for your web app and press Enter. The name
must be unique across all of Azure and use only alphanumeric characters ('A-
Z', 'a-z', and '0-9') and hyphens ('-').
3. Select the resource group you want to use. If you don't have a resource group,
select Create a new resource group, then enter a name for the resource
group, such as AppServiceQS-rg.
6. Select the location you want to serve your app from. For example, West
Europe.
7. Select the App Service plan you want to use. If you don't have an App Service
plan, select Create new App Service plan, then enter a name for the plan
(such as AppServiceQS-plan), then select F1 Free.
8. For Select an Application Insights resource for your app, select Skip for now
and wait the resources to be provisioned in Azure. When prompted to deploy,
don't deploy the add-in yet. You'll do that in a later step.
9. In the App Service explorer in Visual Studio code, expand the node for the
new app, right-click Application Settings, and select Add New Setting:
This app setting enables build automation at deploy time, which automatically
detects the start script and generates the web.config with it.
Update package.json
1. Open the package.json file. Then replace the start command in the "scripts"
section with the following entry.
JSON
2. Find the "prestart" entry in the '"scripts"' section and delete it. This section is not
needed for this deployment.
Update webpack.config.js
1. Open the webpack.config.js file.
2. Set the urlDev and urlProd constants to the following values. (Note that the
https protocol is not specified.) This will cause webpack to replace localhost:3000
JavaScript
3. Find the first CopyWebpackPlugin section and update it to also copy the
package.json file to the dist folder as shown in the following example.
JavaScript
new CopyWebpackPlugin({
patterns: [
{
from: "assets/*",
to: "assets/[name][ext][query]",
},
{
from: "package.json",
to: "package.json",
},
{
from: "manifest*.xml",
to: "[name]" + "[ext]",
transform(content) {
if (dev) {
return content;
} else {
return content.toString().replace(new RegExp(urlDev,
"g"), urlProd);
}
},
},
],
}),
Update manifest
1. Open the manifest.xml file.
4. In the <Scopes> section near the bottom of the file, add the openid scope as
shown in the following XML.
XML
<Scopes>
<Scope>User.Read</Scope>
<Scope>profile</Scope>
<Scope>openid</Scope>
</Scopes>
Update .ENV
The .ENV file contains a client secret. For the purposes of learning in this article you can
deploy the .ENV file to Azure. However for a production deployment, you should move
the secret and any other confidential data into Azure Key Vault.
JavaScript
/*
* Copyright (c) Microsoft. All rights reserved. Licensed under the MIT
license. See full license in root of repo. -->
*
* This file is the main Node.js server file that defines the express
middleware.
*/
require("dotenv").config();
import * as createError from "http-errors";
import * as path from "path";
import * as cookieParser from "cookie-parser";
import * as logger from "morgan";
import express from "express";
import { getUserData } from "./msgraph-helper";
import { validateJwt } from "./ssoauth-helper";
app.set("port", port);
app.use(logger("dev"));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
// Route APIs
indexRouter.get("/getuserdata", validateJwt, getUserData);
app.use("/", indexRouter);
// error handler
app.use(function (err, req, temp, res) {
// set locals, only providing error in development
console.log("error 500");
res.locals.message = err.message;
res.locals.error = req.app.get("env") === "development" ? err : {};
1. In the Azure portal, open your app registration. Note that the app registration may
be in a different account than your App Service app. Be sure to sign in to the
correct account.
6. Edit the Application ID URI field and replace localhost:3000 with the domain from
the App Service app URL you saved previously.
1. In VS Code open the terminal and run the command npm run build . This will build
a folder named dist that you can deploy.
2. In the VS Code Explorer browse to the dist folder. Right-click the dist folder and
select Deploy to Web App...
3. When prompted to select a resource, select the App Service app you created
previously.
4. When prompted if you are sure, select Deploy.
5. When prompted to always deploy the workspace, choose Yes.
If you make additional code changes, you'll need to run npm run build again and
redeploy the project.
Deploy updates
When you add features or fix bugs in your add-in, you'll need to deploy the updates. If
your add-in is deployed by one or more admins to their organizations, some manifest
changes will require the admin to consent to the updates. Users will be blocked from
the add-in until consent is granted. The following manifest changes will require the
admin to consent again.
7 Note
If your app registration is on a different tenant than where you sideload the add-in,
the add-in will not have admin consent for Microsoft Graph. To test in this scenario
you need an admin to centrally deploy the add-in on the Microsoft 365 tenant. For
more information, see Deploy add-ins in the Microsoft 365 admin center
If you encounter any deployment issues, see the Azure App Service troubleshooting
documentation. If you use central deployment, or plan to deploy to App Source, we
recommend you validate the Office Add-in's manifest using the '-p' option for
production.
Next steps
Deploy to App Service using GitHub Actions
Deployment Best Practices
App Service documentation
Azure community support
Create a Node.js web app in Azure
Publish your add-in using Visual Studio
Article • 02/09/2023
Your Office Add-in package contains an XML manifest file that you'll use to publish the
add-in. You'll have to publish the web application files of your project separately. This
article describes how to deploy your web project and package your add-in by using
Visual Studio 2019.
7 Note
For information about publishing an Office Add-in that you created using the
Yeoman generator and developed with Visual Studio Code or any other editor, see
Publish an add-in developed with Visual Studio Code.
2. In the Pick a publish target window, choose one of the options to publish to your
preferred target. Each publish target requires you to include more information to
get started, such as an Azure Virtual Machine or folder location. Once you have
specified a publish location and filled in all of the information required, select
Publish
7 Note
Picking a publish target specifies the server you are deploying to, the
credentials needed to sign in to the server, the databases to deploy, and other
deployment options.
3. For more information about deployment steps for each publish target option, see
First look at deployment in Visual Studio.
To package and publish your add-in using IIS,
FTP, or Web Deploy using Visual Studio 2019
Complete the following steps to package your add-in using Visual Studio 2019.
2. In the Pick a publish target window, choose IIS, FTP, etc, and select Configure.
Next, select Publish.
3. A wizard appears that will help guide you through the process. Ensure the publish
method is your preferred method, such as Web Deploy.
4. In the Destination URL box, enter the URL of the website that will host the content
files of your add-in, and then select Next. If you plan to submit your add-in to
AppSource, you can choose the Validate Connection button to identify any issues
that will prevent your add-in from being accepted. You should address all issues
before you submit your add-in to the store.
5. Confirm any settings desired including File Publish Options and select Save.
) Important
While not strictly required in all add-in scenarios, using an HTTPS endpoint for
your add-in is strongly recommended. Add-ins that are not SSL-secured
(HTTPS) generate unsecure content warnings and errors during use. If you
plan to run your add-in in Office on the web or publish your add-in to
AppSource, it must be SSL-secured. If your add-in accesses external data and
services, it should be SSL-secured to protect data in transit. Self-signed
certificates can be used for development and testing, so long as the certificate
is trusted on the local machine. Azure websites automatically provide an
HTTPS endpoint.
You can now upload your XML manifest to the appropriate location to publish your add-
in. You can find the XML manifest in OfficeAppManifests in the app.publish folder. For
example:
%UserProfile%\Documents\Visual Studio
2019\Projects\MyApp\bin\Debug\app.publish\OfficeAppManifests
Deploy updates
When you add features or fix bugs in your add-in, you'll need to deploy the updates. If
your add-in is deployed by one or more admins to their organizations, some manifest
changes will require the admin to consent to the updates. Users will be blocked from
the add-in until consent is granted. The following manifest changes will require the
admin to consent again.
See also
Publish your Office Add-in
Make your solutions available in AppSource and within Office
Host an Office Add-in on Microsoft
Azure
Article • 02/09/2023
The simplest Office Add-in is made up of an XML manifest file and an HTML page. The
XML manifest file describes the add-in's characteristics, such as its name, what Office
desktop clients it can run in, and the URL for the add-in's HTML page. The HTML page is
contained in a web app that users interact with when they install and run your add-in
within an Office client application. You can host the web app of an Office Add-in on any
web hosting platform, including Azure.
This article describes how to deploy an add-in web app to Azure and sideload the add-
in for testing in an Office client application.
Prerequisites
1. Install Visual Studio 2019 and choose to include the Azure development
workload.
7 Note
If you've previously installed Visual Studio 2019, use the Visual Studio
Installer to ensure that the Azure development workload is installed.
2. Install Office.
7 Note
If you don't already have Office, you can register for a free 1-month trial .
7 Note
If don't already have an Azure subscription, you can get one as part of your
Visual Studio subscription or register for a free trial .
Step 1: Create a shared folder to host your add-
in XML manifest file
1. Open File Explorer on your development computer.
2. Right-click the C:\ drive and then choose New > Folder.
4. Right-click the AddinManifests folder and then choose Share with > Specific
people.
5. In File Sharing, choose the drop-down arrow and then choose Everyone > Add >
Share.
7 Note
In this walkthrough, you're using a local file share as a trusted catalog where you'll
store the add-in XML manifest file. In a real-world scenario, you might instead
choose to deploy the XML manifest file to a SharePoint catalog or publish the
add-in to AppSource.
7 Note
Although this example uses Word, you can use any Office application that
supports Office Add-ins such as Excel, Outlook, PowerPoint, or Project.
3. In the Word Options dialog box, choose Trust Center and then choose Trust
Center Settings.
4. In the Trust Center dialog box, choose Trusted Add-in Catalogs. Enter the
universal naming convention (UNC) path for the file share you created earlier as
the Catalog URL (for example, \\YourMachineName\AddinManifests), and then
choose Add catalog.
5. Select the check box for Show in Menu.
7 Note
When you store an add-in XML manifest file on a share that is specified as a
trusted web add-in catalog, the add-in appears under Shared Folder in the
Office Add-ins dialog box when the user navigates to the Insert tab on the
ribbon and chooses My Add-ins.
6. Close Word.
Choose the Resource Group for your site. If you create a new group, you also
need to name it.
Enter a unique App name for your site. Azure verifies that the site name is
unique across the azureweb apps.net domain.
Choose a Region.
Choose the App Service plan to use for creating this site.
Choose Create.
4. The next page will let you know that your deployment is underway and when it
completes. When it is completed, select Go to resource.
5. In the Overview section, choose the URL that is displayed under URL. Your browser
opens and displays a webpage with the message "Your App Service app is up and
running."
) Important
While not strictly required in all add-in scenarios, using an HTTPS endpoint for
your add-in is strongly recommended. Add-ins that are not SSL-secured
(HTTPS) generate unsecure content warnings and errors during use. If you
plan to run your add-in in Office on the web or publish your add-in to
AppSource, it must be SSL-secured. If your add-in accesses external data and
services, it should be SSL-secured to protect data in transit. Self-signed
certificates can be used for development and testing, so long as the certificate
is trusted on the local machine. Azure websites automatically provide an
HTTPS endpoint.
4. Choose Word Web Add-in as the project type, and then choose Next to accept
the default settings.
Visual Studio creates a basic Word add-in that you'll be able to publish as-is, without
making any changes to its web project. To make an add-in for a different Office
application, such as Excel, repeat the steps and choose a project type with your desired
Office application.
2. Right-click the web project and then choose Publish. The web project contains
Office Add-in web app files so this is the project that you publish to Azure.
3. On the Publish tab:
Choose Publish.
4. Visual Studio publishes the web project for your Office Add-in to your Azure web
app. When Visual Studio finishes publishing the web project, your browser opens
and shows a webpage with the text "Your App Service app has been created." This
is the current default page for the web app.
2. Expand the Office Add-in project (for example WordWebAddIn), right-click the
manifest folder, and then choose Open. The add-in XML manifest file opens.
3. In the XML manifest file, find and replace all instances of "~remoteAppUrl" with
the root URL of the add-in web app on Azure. This is the URL that you copied
earlier after you published the add-in web app to Azure (for example:
https://YourDomain.azurewebsites.net ).
4. Choose File and then choose Save All. Next, Copy the add-in XML manifest file (for
example, WordWebAddIn.xml).
5. Using the File Explorer program, browse to the network file share that you created
in Step 1: Create a shared folder and paste the manifest file into the folder.
4. Choose the icon for your add-in and then choose Add. A Show Taskpane button
for your add-in is added to the ribbon.
5. On the ribbon of the Home tab, choose the Show Taskpane button. The add-in
opens in a task pane to the right of the current document.
6. Verify that the add-in works by selecting some text in the document and choosing
the Highlight! button in the task pane.
Deploy updates
When you add features or fix bugs in your add-in, you'll need to deploy the updates. If
your add-in is deployed by one or more admins to their organizations, some manifest
changes will require the admin to consent to the updates. Users will be blocked from
the add-in until consent is granted. The following manifest changes will require the
admin to consent again.
Changes to requested permissions. See Requesting permissions for API use in add-
ins and Understanding Outlook add-in permissions.
Additional or changed Scopes. (Not applicable if the add-in uses the unified
manifest for Microsoft 365.)
Additional or changed Outlook events.
7 Note
Whenever you make a change to the manifest, you must raise the version number
of the manifest.
See also
Publish your Office Add-in
Publish your add-in using Visual Studio
Make your solutions available in
Microsoft AppSource and within Office
Article • 03/03/2023
Microsoft AppSource provides a convenient location for you to upload new Office and
SharePoint Add-ins, Microsoft Teams apps, and Power BI visuals that provide solutions
for both consumers and businesses. When you add your app solution to Microsoft
AppSource, you also make it available in the in-product experience within Office. To
include your solution in Microsoft AppSource and within Office, you submit it to Partner
Center . You need to create an individual or company account and, if applicable, add
payout information. For details, see the following:
Create a developer account . After you create your account, it goes through an
approval process.
For details about the registration process, see Opening a developer account.
For details about managing settings and additional users in your Partner Center
account, see Manage account users.
Submit your solution to Microsoft AppSource via Partner Center.
7 Note
For information about how to submit, validate, and publish Microsoft Teams apps, see
Teams apps submission details.
For information about how to submit, validate, and publish your SharePoint Framework
(SPFx) solution apps, see SPFx solutions submission details.
For information about how to submit Power BI custom visuals to Microsoft AppSource,
see Publish custom visuals.
Approval process
After your account is approved, you can submit your solution to Partner Center. You can
make changes at any point before you submit your solution for approval. During the
approval process, you can make changes to your submission, but you can’t submit them
for publishing until your current submission is complete.
7 Note
If you're submitting a Microsoft Teams app, see Tips for a successful app
submission. This will help to ensure timely approval of your submission.
It must be free of viruses. If you need virus detection software, see the Microsoft
Safety & Security Center .
It must not contain inadmissible or offensive material.
It must be stable and functional.
Any material that you associate with your apps or add-ins, such as descriptions and
support documentation, must be accurate. Use correct spelling, capitalization,
punctuation, and grammar in your descriptions and materials.
If you want a tailored experience for users in a regional store, you can add
additional languages so that your add-in appears in another language store with
localized metadata. Your service and your add-in manifest must be updated
appropriately. You must also provide descriptions for each language you add.
If your free app or add-in contains an in-app purchase, the Microsoft AppSource
listing for your add-in will reflect this by stating 'Additional purchase may be
required' under the pricing options.
For more details about Microsoft AppSource requirements, see the Certification policies.
Certification process
After you submit your solution:
2. The validation team reviews your submission. This can take 3-5 working days,
depending on the volume of submissions in the queue. (Teams and SPFx apps
submissions are validated in 24 hours.)
7 Note
The validation team tests Office Add-ins on all the platforms that the add-in is
required to support. For details about supported platforms, see the Office
Add-ins host and platform availability page.
For a seamless certification experience, provide detailed test notes with your
submission, including:
7 Note
Because our team is located in multiple time zones, we request that you do
not configure test accounts that require developer interaction before we can
test.
3. When the certification process is complete, you receive a message to let you know
that either your submission is approved, or you need to make changes and
resubmit it.
2. In the Offer alias column, select the Office add-in or app you want.
3. On the Product overview page, the status of your submission will be one of the
following:
Pre-processing
Certification
Published
7 Note
If you make changes after your submission is certified, it must go through the
certification process again.
If you have general questions about policies, processes, or validation requirements, you
can engage with the Microsoft AppSource validation team via Stack Overflow . Tag
your question with "Office-Store". Please be aware that the validation team will not be
able to discuss individual submission results on Stack Overflow.
See also
Office Add-ins
SharePoint Add-ins
Microsoft Teams developer platform
Visuals in Power BI
Microsoft 365 App Compliance
Commercial marketplace certification
policies
Article • 03/14/2023
7 Note
Table of contents
100 General
1140 Teams
1160.1 Security
1160.2 Functionality
100 General
These General policies apply to all offer types. Additional policies for each specific offer
type are listed below by offer type. Please be sure you review both policy sections for
the type of offer you are developing for the marketplace.
The types of offer types supported by the marketplace can be found in the publishing
guide by offer type and the Microsoft 365 AppSource documentation. All offers and
your publisher activities on Partner Center are subject to the Microsoft Publisher
Agreement .
100.1.1 Title
All offers and plans must have an accurate and descriptive title. If your offer is promoted
on a website outside of the commercial marketplace, the title on the promotional
website should match the title in the marketplace. If your product includes repackaged
open-source software or software that was originally created by a vendor other than
you, the product title must indicate the value added by your repackaging that
distinguishes it. If there is no additional intellectual property added to the product, the
product title must include the seller’s name (for example: <Product> with support by
<Seller>).
100.1.2 Summary
Offers must have a concise, well written summary of the offer and its intended use. This
summary will be shown on the commercial marketplace search results screen and is
limited to 100 characters.
100.1.3 Description
All offers and plans must have a description that identifies the intended audience, briefly
and clearly explains its unique and distinct value, identifies supported Microsoft
products and other supported software, and includes any prerequisites or requirements
for its use. The description should not simply repeat the offer summary.
You must clearly describe any limitations, conditions or exceptions to the functionality,
features, and deliverables described in the listing and related materials before the
customer acquires your offer. The capabilities you declare must relate to the core
functions and description of your offer.
Your listing, including the description, metadata, and any other provided content, should
describe your offer’s capabilities, strengths, and what makes it desirable, including any
compatibility with other offers. Comparative marketing, including using competitor
logos or trademarks in your offer listing, or including tags or other metadata referencing
competing offers or marketplaces, is not allowed.
If your offer supports multiple languages, all offer and marketplace listing content
should be localized for each supported language. Offers listed in multiple languages
must be easily identified and understood.
Each offer submitted to the marketplace must have at least one public plan, which may
be Contact Me, Bring Your Own License (BYOL), or Get It Now (Transact). Private plans
are not allowed without a corresponding public plan.
100.2 Discoverability
To help customers discover offers, categories, industries, keywords, and consulting
service competencies must accurately identify your expertise. The description of your
listing must be relevant to the selected categories and industries.
100.2.2 Keywords
Keywords must be relevant to the offer and any supported products. Adding competitor
names or products as keywords is not permitted. Categories and titles should not be
added as keywords.
Products from a single publisher with multiple or related versions of the same product
must be grouped under a single listing and the multiple or related versions captured as
distinct plans.
Logo
Logos are uploaded as a .png file between 216- and 350-pixels square. This
logo appears on the offer listing page in Azure Marketplace or AppSource.
An optional 48-pixel square logo may be added later to replace the
autogenerated small logo. This logo appears in Azure Marketplace search
results or on the AppSource main page and search results.
Images, including screenshots
Images must be 1280x720 pixel .png files.
Images should be of good quality: high resolution, sharp, with legible and
readable text.
Comparative marketing, including using competitor logos or trademarks, is not
allowed.
Videos
Videos must be hosted on YouTube or Vimeo; no other video hosts are allowed.
Videos must be publicly viewable and embeddable.
Videos and their thumbnail images should be of good quality: high resolution,
understandable, and related to the offer.
Video links must lead directly to the individual video page. No short URLs,
"human readable" redirects, or other obfuscating services may be used. Account
pages, playlists, or other collection pages are not allowed.
How you are providing your offer (for example, as a limited time trial or as a
purchase)
Pricing, including currency
Variable pricing structures
Features or content that require an extra charge, whether through in-app or add-in
purchases or through other means. Your description must also disclose any
dependencies on additional services, accounts, or hardware. Offers cannot have
any dependencies on any product or component that is no longer supported or
commercially available.
Pricing models must conform to the pricing models supported by the marketplace.
All purchase transactions associated with your offer must begin by using a starting point
in the commercial marketplace listing, such as the Contact Me or Get It Now buttons.
Within the offer listing, you may not redirect or up-sell customers to software or services
outside the marketplace. This restriction does not apply to support services that
publishers sell outside the marketplace.
You may not promote the availability of your offer on other cloud marketplaces within
the offer listing.
The commercial marketplace does not currently support the sale of hardware or
professional services. Any offers for hardware must be transacted outside of the
marketplace. Charges for services such as support included with your offer and billed
through the marketplace may only amount to an ancillary component (less than 10%) of
the total price charged to end customers.
Links must be functional, accurate, and must not jeopardize or compromise user
security. For example, a link must not spontaneously download a file.
When referring to Microsoft trademarks and the names of Microsoft software, products,
and services, follow Microsoft Trademark and Brand Guidelines .
References to Business Programs participation or eligibility are not allowed. Example
(but not limited to) references to Microsoft Azure Consumption Commitment (MACC),
Partner Co-sell, Co-sell Prioritized, IP Co-sell, MPN Competency, Cloud Solution Partner
Designation. Such references must not be included anywhere in the metadata of your
offer.
100.11 Security
Customers want to be confident that offers are safe and secure. Your offer must not
jeopardize or compromise user security, the security of the Azure service, or related
services or systems. These are related criteria:
100.12 Functionality
Customers expect offers to deliver what they promise. Your offer must provide the
functionality, features, and deliverables described in your listing and related materials.
If your offer has trial and paid versions, trial functionality must reasonably resemble the
paid version.
Offer user interfaces should not look unfinished. All UI should be intuitive and obvious
in purpose, without requiring users to read support documentation for basic tasks.
Your offer should be reasonably responsive. Long wait or processing times should be
accompanied by some form of warning or loading indicator.
100.14 Testability
Your offer submission must include any necessary instructions and resources for
successful certification of your offer.
200 Virtual Machines
To ensure that customers have a clear and accurate understanding of your offer, please
follow these additional listing requirements for Virtual Machines (VM) offers.
The Azure Resource Manager (RM) module may still be used but is being
deprecated. We recommend using the Azure PowerShell Az module instead.
In addition to your solution domain, your engineering team should have knowledge on
the following Microsoft technologies:
The App Description must match the application included in the Virtual Machine and
must have been tested for primary functionality after deployment of the VM image in
Microsoft Azure.
200.3.1 General
VM image must be provided in the form of a VHD file and built on an Azure-approved
base image.
VM image must be deployable and able to provision on Azure from either the Azure
Portal or PowerShell scripts.
Must support deployment of the image with at least the publisher recommended Azure
VM Size.
Disk count in a new image version cannot be changed. A new SKU must be defined to
reconfigure data disks in the image. Publishing a new image version with different disk
counts will have the potential of breaking subsequent deployments based on the new
image version in cases of auto-scaling, automatic deployments of solutions through
Azure Resource Manager templates, and other scenarios.
VHD image must be submitted via a valid and available Shared Access Signature (SAS)
URI.
Choose one or both of the Azure PowerShell or Azure command-line interface (CLI)
scripting environments to help manage VHDs and VMs.
Image must have been deprovisioned. See Configure the Azure-Hosted VM: Generalize
the Image.
200.3.2 Windows
Application must not have a dependency on the D: drive for persistent data. Azure offers
the D: drive as temporary storage only and data could be lost.
Application usage of the data drive must not have a dependency on C: or D: drive letter
designations. Azure reserves C: and D: drive letter designations.
Build lean and limit possible cloud compatibility issues by avoiding dependency and not
including specialized Windows Server roles and features such as Failover Cluster, DHCP,
Hyper-V, Remote Access, Rights Management Services, Windows Deployment Services,
BitLocker Drive Encryption on OS disk, and Network Load Balancing Windows Internet
Name Service.
200.3.3 Linux
No swap partition on the OS disk. Swap can be requested for creation on the local
resource disk by the Linux Agent. It is recommended that a single root partition is
created for the OS disk.
The latest Azure Linux Agent should be installed using the repair manager (RPM) or
Debian package. You may also use the manual install process, but the installer packages
are recommended and preferred.
No swap partition on the OS disk. Swap can be requested for creation on the local
resource disk by the Linux Agent. It is recommended that a single root partition is
created for the OS disk.
Choose one or both of the Azure PowerShell or Azure command-line interface (CLI)
scripting environments to help manage VHDs and VMs.
VM image should not contain any pre-existing users and password keys for them.
Microsoft Hyper-V virtual network driver 'hv_netvsc' should be loaded and reloaded
gracefully.
If you are installing an OS manually, then you must size your primary VHD in your VM
image. For Windows, the operating system VHD should be created as a 127-128 GB
fixed-format VHD. For Linux, this VHD should be created as a 30-50 GB fixed-format
VHD.
Windows OS disks are generalized with the sysprep tool. If you subsequently update or
reconfigure the OS, you must rerun sysprep .
Ensure that Azure Support can provide our partners with serial console output when
needed and provide adequate timeout for OS disk mounting from cloud storage.
Images must have the following parameters added to the Kernel Boot Line:
console=ttyS0 earlyprintk=ttyS0 rootdelay=300 .
200.5 Security
Ensure that you have updated the OS and all installed services with all the latest security
and maintenance patches. Your offer should maintain a high level of security for your
solution images in the Marketplace.
All the latest security patches for the Linux distribution must be installed and industry
guidelines to secure the VM image for the specific Linux distribution must be followed.
It is recommended that Logical Volume Manager (LVM) should not be used.
Images should not include significant Common Vulnerability and Exposures. Verify the
following:
The VHD used for the source of any image based on Windows Server must be
from the Windows Server OS images provided through Microsoft Azure.
Do not use the solution VHD (such as the C: drive) to store persistent information.
The VHD image must only include necessary locked accounts that do not have
default passwords that would allow interactive login; no back doors are allowed.
All sensitive information, such as test SSH keys, known hosts file, log files, and
unnecessary certificates, must be removed from the VHD image.
During the publishing process, you must provide a uniform resource identifier (URI) for
each virtual hard disk (VHD) associated with your SKUs. Microsoft needs access to these
VHDs during the certification process. When generating shared access signature (SAS)
URIs for your VHDs, adhere to the following requirements:
Only unmanaged VHDs are supported.
List and Read permissions are sufficient; do not provide Write or Delete access.
The duration for access (expiry date) should be a minimum of three weeks from
when the SAS URI is created.
To safeguard against Coordinated Universal Time (UTC) variations, set the start
date to one day before the current date; for example, if the current date is October
6, 2019, select 10/5/2019.
Review and verify each generated SAS URI by using the following checklist. Verify that:
The URI contains your VHD image filename, including the filename extension
" .vhd "
Towards the middle of the URI, sp=rl appears; this string indicates that Read and
List access is specified
After that point, sr=c also appears; this string indicates that container-level access
is specified
You can use the VM Self-test Service API to pre-validate that a Virtual Machine (VM)
meets the latest Azure Marketplace publishing requirements.
Preview images are stored during the testing and preview phase of the offer publication
process and are not visible to customers. Microsoft may remove inactive images from
storage.
Container offers are not supported for Azure applications in the commercial
marketplace.
Custom meters may only be used for the consumption or usage of software (for
example, counting messages sent through an email platform or consuming credits that
indicate software usage).
300.3 Functionality
VMs must be built on Windows or Linux.
300.4.1 Code
Code must address any comments provided as part of the code review in the
certification process.
300.4.2 Security
All firewall rules and network security groups (NSGs) must be reasonable for the
application.
Role-based access control (RBAC) assignments should use the least privilege required
and must have a justification for "owner".
Managed Service Identity (MSIs) must be assigned a role. Unused MSIs must be
removed.
300.4.3 Variables
Any declared variables must be used.
300.4.4 Parameters
Any declared parameters must be used.
Any defaultValue supplied for a parameter must be valid for all users in the default
deployment configuration.
Do not provide default values for user names, passwords (or anything that requires
a SecureString , or anything that will increase the attack surface area of the
application.
Templates must have a parameter named location for the primary location of resources.
The default value of this parameter must be [ resourceGroup().location ].
The location parameter must not contain allowedValues . Location values may be
restricted in CUID but not the template.
Do not use allowedValues for lists of things that are meant to be inclusive (for example,
all VM SKUs). allowedValues should only be used for exclusive scenarios. Overusing
allowedValues will block deployment in some scenarios. Resources without built-in
controls in createUIDef may only be populated with values that can be validated in
createUIDef .
300.4.5 Resources
Top-level template properties must be in the following order:
JSON
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/...",
"contentVersion": "1.0.0.0",
"apiProfile": "...",
"parameters": {},
"functions": {},
"variables": {},
"resources": [],
"outputs": {},
}
All empty or null properties that are not required must be excluded from the templates.
Any reference to a property of a resource must be done using the reference() function.
The apiVersion specified for a resource type must be no more than 24 months old. A
preview apiVersion must not be used if a later version (preview or non-preview) is
available.
Regex validation of textbox controls must match the intent of the control and properly
validate the input.
All of the artifacts needed for deployment must be included in the zip file submitted for
publishing.
_artifactsLocation – The base URI where all artifacts for the deployment will be
VM sizes in allowed values must match the storage type selection (premium, standard,
or standard SSD).
Ensure your container product is deployable on AKS clusters and Azure Container
Instance.
400.3 Security
Your product must not jeopardize or compromise user security, or the security or
functionality. You are solely responsible for all product safety testing, and the
implementation of any appropriate feature safeguards.
Your product must not contain or enable malware as defined by the Microsoft
criteria for Unwanted and Malicious Software.
Manifest and image tags must be properly formatted and consistent. The "latest"
tag must be listed.
The "latest" tag must be a manifest tag available in the container registry.
All image tags referred to by manifest tags must be present in the registry.
All version tags must be immutable.
The module must start, run, and remain stable with the default options.
The "latest" tag must run with the default configuration options on all claimed
supported OS/architectures. For general-purpose modules, this means supporting x64,
arm32, and arm64 under both Linux and Windows (x64 platform only).
Modules that include the IoT SDK and are set to the PartnerId.OfferIdPlanId must send
telemetry.
Managed services offers must have the primary purpose of providing services that
manage customers' use of Azure. Offerings, with the primary purpose of selling licenses
or subscriptions to software or a platform, must instead be listed as an application.
OR,
The billing model for plans must be "Bring your own license".
Data & AI (Azure), Infrastructure (Azure), Digital & App Innovation (Azure),
Security
OR
Retained benefits in the following competency based on competencies held as
of September 30, 2022:
Silver or Gold competency in at least one of the following areas:
Application Development, Application Integration, Application Lifecycle
Management, Cloud Platform, Data Analytics, Data Center, Data Platform,
DevOps or Security.
Dynamics 365 Business Central Solutions Partner designation for Business Applications OR
at least two associated Business Central customer
deployments
OR
Retained benefits in the following competency based on
competencies held as of September 30, 2022:
Silver or Gold competency in Enterprise Resource Planning
and serving at least three customers
OR
Must have published a Business Central application in
Microsoft AppSource.
Dynamics 365 Customer Insights Solutions Partner designation for Business Applications
OR
Have at least two associated Customer Insights customer
deployments.
Dynamics 365 Customer Voice Solutions Partner designation for Business Applications
OR
Primary Product: Dynamics 365 Eligibility Requirement(s)
Dynamics 365 Finance and Solutions Partner designation for Business Applications
Operations Applications (Finance, OR
Supply Chain Management, At least two associated Finance and Operations, Retail,
Commerce, Project Service and/or Core HR customer deployments
Automation) OR
Retained benefits in the following competency based on
competencies held as of September 30, 2022:
Silver or Gold competency in Cloud Business Applications –
Unified Operations Option.
OR
Retained benefits in the following competency based on
competencies held as of September 30, 2022:
Silver or Gold competency in Enterprise Mobility Management
or Windows & Devices.
OR
Retained benefits in the following competency based on
competencies held as of September 30, 2022:
Silver or Gold competency in Security.
For more information on meeting these prerequisites, see the Consulting Services
prerequisites.
The following sections provide more detail on publishing requirements for "Power" offer
types noted in the table above.
OR
Have at least two associated Common Data Service customer deployments in the
trailing 12 months (either through DPOR, CPOR, or OSU).
For more on information on how to become a Solutions Partner please see Solutions
Partner for Business Applications
OR,
Alternatively, you may have retained benefits listed below. Please note we will be
retiring the below legacy competencies starting September 1st, 2023. From this date on,
all partners will be required to become a Solutions Partner. You can learn more here
Introduction to the Solutions partner program - Partner Center | Microsoft Learn.
Retained benefits in the legacy Competency [silver or gold status in Cloud Business
Applications Competency in Customer Engagement option] as described in the
800.2.2 Eligibility requirements, based on your competency held as of September
30, 2022.
OR
Have at least two associated Finance and Operations, Retail, and/or Core HR customer
deployments in the trailing 12 months (either through DPOR, CPOR, or OSU).
For more on information on how to become a Solutions Partner please see Solutions
Partner for Business Applications.
OR,
Alternatively, you may have retained benefits in the Legacy Competency [silver or gold
status in Cloud Business Applications Competency in Unified Operations option] as
described in the 800.2.3 Eligibility requirements, based on your competency held as of
September 30, 2022.
Have at least one associated Customer Insights customer deployments via PAL in the
trailing 12 months.
For more on information on how to become a Solutions Partner please see Solutions
Partner for Business Applications.
For more information on validating your customer deployment projects using PAL,
please see Link a partner ID to your account that’s used to manage customers.
OR,
Alternatively, you may meet the legacy requirements listed below. Please note we will be
retiring the below legacy requirements starting September 1st, 2023. From this date on,
all partners will be required to become a Solutions Partner. You can learn more here
Introduction to the Solutions partner program - Partner Center | Microsoft Learn
For more on information on how to become a Solutions Partner please see Solutions
Partner for Business Applications. OR Alternatively, you may have retained benefits listed
below. Please note we will be retiring the below legacy competencies starting
September 1st, 2023. From this date on, all partners will be required to become a
Solutions Partner. You can learn more here Introduction to the Solutions partner
program - Partner Center | Microsoft Learn.
- Retained benefits in the legacy Competency (silver or gold Enterprise Resource
Planning) along with at least three customers or a published Business Central
application in Microsoft AppSource.
800.2.6 Power BI
To publish a Power BI consulting service offer in the marketplace, you must Enrolled in
the Microsoft Cloud Partner Program as a Solutions Partner for Business Applications OR
Solutions Partner for Data & AI.
OR
Have at least two associated Power BI customer deployments via PAL in the trailing 12
months.
For more on information on how to become a Solutions Partner please see Solutions
Partner for Business Applications.
OR,
Alternatively, you may meet the legacy requirements listed below. Please note we will be
retiring the below legacy requirements starting September 1st, 2023. From this date on,
all partners will be required to become a Solutions Partner. You can learn more here
Introduction to the Solutions partner program - Partner Center | Microsoft Learn.
Legacy partner requirements include attaining the Showcase Partner status in the
Business Intelligence Partner Program . Below are the requirements:
Your company must have an active Silver or Gold Microsoft Data Analytics
Competency
OR Solutions Partner for Data & AI or Solutions Partner for Business
Applications.
2. Get certified
Read more details about Announcing a new name for the Data Analyst Associate
certification
OR
Have at least two PAL associated Power Apps customer deployments in the trailing 12
months.
For more on information on how to become a Solutions Partner please see Solutions
Partner for Business Applications.
For more information on validating your customer deployment projects using PAL,
please seeLink a partner ID to your Power Platform and Dynamics Customer Insights
accounts.
OR,
Alternatively, you may meet the legacy requirements below. Please note we will be
retiring the below legacy requirements starting September 1st, 2023. From this date on,
all partners will be required to become a Solutions Partner. You can learn more here
Introduction to the Solutions partner program - Partner Center | Microsoft Learn.
Legacy partner requirements include: at least one associated Power Apps customer
deployment project validated using the Partner Admin Link (PAL).
OR
Competency: Your company must have at least one of the following active Gold
competencies: - Cloud Business Applications - Cloud Platform - Small and Mid-Market
Cloud Solutions - Cloud Productivity - Application Integration - Application
Development - Data Analytics AND Certification: Your company must have individuals
pass the following certifications: - Five must achieve MSFT Certified: Power Platform
Functional Consultant Associate AND - Two must achieve MSFT Certified: Power
Platform Developer Associate AND - One must achieve MSFT Certified: Power Platform
Solution Architect Expert*.
Certifications can be held by the same or different individuals.
Exam MB-600: Microsoft Dynamics 365 + Power Platform Solution Architect will be
accepted until June 30, 2022.
OR
Have at least two PAL associated Power Automate customer deployments in the trailing
12 months.
For more on information on how to become a Solutions Partner please see Solutions
Partner for Business Applications.
For more information on validating your customer deployment projects using PAL,
please see Link a partner ID to your Power Platform and Dynamics Customer Insights
accounts.
OR,
Alternatively, you may meet the legacy requirements below. Please note we will be
retiring the below legacy requirements starting September 1st, 2023. From this date on,
all partners will be required to become a Solutions Partner. You can learn more here
Introduction to the Solutions partner program - Partner Center | Microsoft Learn.
Cloud Platform
Small and Mid-Market Cloud Solutions
Cloud Productivity
Application Integration
Application Development
Data Analytics AND Certification: Your company must have individuals pass the
following certifications:
Five must achieve MSFT Certified: Power Platform Functional Consultant
Associate AND · - Two must achieve MSFT Certified: Power Platform Developer
Associate AND · - One must achieve MSFT Certified: Power Platform Solution
Architect Expert*.
Exam MB-600: Microsoft Dynamics 365 + Power Platform Solution Architect will be
accepted until June 30, 2022
Have at least two PAL associated Power Automate customer deployments in the trailing
12 months.
For more on information on how to become a Solutions Partner please see Solutions
Partner for Business Applications.
OR,
Alternatively, you may meet the legacy requirements below. Please note we will be
retiring the below legacy requirements starting September 1st, 2023. From this date on,
all partners will be required to become a Solutions Partner. You can learn more here
Introduction to the Solutions partner program - Partner Center | Microsoft Learn.
Competency: Your company must have at least one of the following active Gold
competencies: - Cloud Business Applications - Cloud Platform - Small and Mid-Market
Cloud Solutions - Cloud Productivity - Application Integration - Application
Development - Data Analytics AND Certification: Five individuals must achieve MSFT
Certified: Power Platform Functional Consultant Associate.
OR
Have at least two associated Common Data Service customer deployments in the
trailing 12 months (either through DPOR, CPOR, or OSU).
For more on information on how to become a Solutions Partner please see Solutions
Partner for Business Applications
OR,
Alternatively, you may meet the legacy requirements listed below. Please note we will be
retiring the below legacy requirements starting September 1st, 2023. From this date on,
all partners will be required to become a Solutions Partner. You can learn more here
Introduction to the Solutions partner program - Partner Center | Microsoft Learn.
OR
If the offer is focused on Guides, you should have at least one associated Guides
customer deployment in the trailing 12 months. If the offer is Remote Assist, you must
have at least one associated Remote Assist customer deployment in the trailing 12
months.
For more on information on how to become a Solutions Partner please see Solutions
Partner for Business Applications
800.3 Title
Your Title must follow the format "Offer Name: Duration Service type." For example,
"CompanyX - Database Security: 2-wk Implementation."
Your offer Title must not include your company name unless it is also a product name.
For example, "CompanyX 3-Wk Assessment."
The offer type must match the type specified during submission.
Any Applicable Products and keywords defined during submission must be directly
relevant to the offer.
If mentioned in the summary or description, the offer type must match the type
specified during submission.
800.4.1 Quality
Duplicate Description The descriptions cannot be the same for multiple offers. Each
description should accurately represent and differentiate the services associated with
the offers. 7For more information, please see:
800.4.2 Content
Summary
Please briefly describe the purpose or goal of your offer in 200 characters or fewer. Your
summary cannot be the same text as the title of the offer. This will be displayed in the
search box and must be different from the name of the offer.
Example: Free 2 hour assessment on how to use Office 365 and SharePoint with Power
Apps, Power Automate, Dataverse, and Power BI by industry leading partner, trainer, and
thought leaders. See Offer Listings.
Explain how the primary product is part of this offer by specifically mentioning it and
making it clear. Our goal is not to just publish your offer, but to drive more leads that
will help move your business forward. It needs to be clear to the potential customer how
your service is going to help their business. See Primary products and online stores.
Your description needs to have deliverables and outcomes using Markdown language
for bullet points. Examples:
markdown
### Deliverables
* List of applicable solutions that can be built using Office 365,
SharePoint, Power Apps, Flow, Power BI, > and Dataverse
* Skill gap assessment of your current staff
* License review
* Recommendations on where and how to start using Power Apps, Flow, CDS, and
Power BI with SharePoint and > Office 365
You may format your description using Markdown formatting (### Header, *
Bullet, *Italics*, **Bold**) or simple HTML. Partner Center also allows rich
text formatting.
If you are using HTML, check the PREVIEW before you go live. You may want to switch to
Markdown formatting if the bullets aren’t rendering properly.
Workshops longer than a day should include a clear daily or weekly agenda in the
description. Please see examples below:
markdown
### Agenda
* Day 1: Dashboard-in-a-Day using Power BI
* Day 2: Design the reporting platform for your enterprise
* Day 3: Develop and deploy the relevant visualizations on the Power BI
reporting platform
* Day 4 & 5: Remote Support
Or
You may format your description using Markdown formatting (### Header, *
Bullet, *Italics*, **Bold**) or simple HTML. Partner Center also allows
rich text formatting.
If you are using HTML, check the PREVIEW before you go live. You may want to switch to
Markdown formatting if the bullets aren’t rendering properly. See Offer Listings.
Briefings should include at least four bullets with information on topics to be covered,
using Markdown formatting for the bullet points. Examples:
markdown
The description of your offer must clearly state how it leverages or relates to [Choose
one: Microsoft Azure, Microsoft Power BI, etc.] cloud services value propositions, and
state how the offer is providing a professional service for the selected primary product.
Update the description and resubmit your offer.
The description of your offer should not contain contact information. However, it may
direct customers to the "Contact Me" button on the offer page to start a discussion.
Update the description and resubmit your offer
Hosted - your entire product and all components are hosted in your Azure
infrastructure for Azure customers.
Migrations to Azure - your product migration tooling has Azure as its only
destination for migration, but can run on-premises or on another cloud as a
migration source.
Backup or data replication to Azure - your backup, replication, or data product
replicates data only to Azure, while the product’s control plane can run on-
premises or on other clouds.
Azure platformed SaaS with external dependencies - your product compute
and/or data plane runs on Azure, but smaller control planes or support
infrastructure, such as logging, run on-premises or on another cloud. In this case,
your Azure-hosted compute and/or data plane must be the resource whose
consumption increases the fastest when your users increase their consumption
Azure platformed SaaS with smaller, peripheral agents - your product's compute
and/or data plane runs on Azure. Your product's monitoring or security agents can
run on-premises or on another cloud or on the customer’s tenant, but they must
send data to an Azure-hosted environment for storage and analysis.
If your product requires components to be deployed in the customer’s Azure tenant, the
following requirements apply:
For your SaaS offer to be listed on AppSource, it must meet these criteria:
Integrate with or extend a Microsoft service or product and your offer must
describe how it does so.
Accept single sign-on from work accounts from any company or organization that
has Azure Active Directory (AAD). More information is at Get AppSource certified
for Azure Active Directory.
Offers must support both Azure AD and Microsoft Account (MSA) types.
You must limit your Microsoft Graph API request(s) to use only the "User.Read"
permissions during the marketplace subscription activation process. Requests requiring
additional permissions can be made after the subscription activation process has been
completed. See Microsoft’s guidance on incremental consent to learn more.
Please bear in mind that while SaaS metering is optional, the fulfillment API docs do not
include the metering service docs. You must additionally integrate with the metering API
if you have a SaaS offer that uses meters.
You must be the publisher of both the SaaS offer and the app or add-in(s), or
You must provide written authorization from the publisher of the SaaS offer or app
or add-in to which you are trying to link your offer.
If your product offers in-app purchases, you must select the "My product requires
purchase of a service or offers additional in-app purchases" check box on the Product
Setup tab when submitting your offer via Partner Center.
Office Add-ins must have a clear value proposition and provide a seamless first run
experience (FRE). If users must sign in or sign up to use the add-in, the value proposition
must be clear to the user before they do so.
Your app or add-in must not launch functionality outside of the app or add-in
experience without the explicit permission of the user.
Your app experience must not prompt a user to disclose the credentials of a Microsoft
identity (for example, Microsoft 365 (formerly called Office 365) or Microsoft Azure
Organizational Account, Microsoft Account, or Windows Domain Account) except
through Microsoft approved OAuth flow, where your app is authorized to act on behalf
of the user.
Your app or add-in must not obtain, store, pass, or transmit customer information or
content without notifying the user.
Your app or add-in must be secured with a valid and trusted SSL certificate (HTTPS).
Your app or add-in may not open pop-up windows unless they are triggered by explicit
user action. Pop-up windows must not be blocked by the browser's pop-up blocker
when the blocker is set to the default value.
Your app or add-in may not request unreasonably high permissions or full-control
permission.
Your app or add-in must have a correctly sized and formatted icon specified in the
package or manifest.
Add-ins that depend on external accounts or services must provide a clear and simple
sign in/sign out and sign-up experience.
Do not require a sign-in experience for external accounts or services if sign-ups are
managed by the enterprise outside of the app or add-in and not by the individual
user.
Do not require a seamless first run experience and value proposition but must
include an email contact or link in the UI so users can learn more about your
services.
Please refer to this blog post to learn more.
The title may not include your brand or service unless your offer targets a larger
organization or enterprise.
Microsoft Teams apps may not include the brand or service in the title.
Your app or add-in must not be a duplicate of an app or add-in you have already
submitted.
If you update your pricing from free to paid, existing users must receive the same
level of functionality as before the update.
If you update site license pricing from free to paid or not supported, existing users
must continue to be supported for free.
Apps or add-ins may convert from free to subscription pricing as long as existing
users receive the same level of functionality as before the update. Converting from
paid to subscription pricing is not currently supported.
Specify a valid Support URL in the SupportURL element of your add-in manifest.
Must not include any in-app purchases, trial offers, UI that aims to up-sell to paid
versions, or links to any online stores where users can purchase or acquire other
content, apps, or add-ins.
The iOS or Android version of the add-in must not show any UI or language or
link to any other apps, add-ins, or website that ask the user to pay. If the add-in
requires an account, accounts may only be created if there is no charge; the use
of the term "free" or "free account" is not allowed. You may determine whether
the account is active indefinitely or for a limited time, but if the account expires,
no UI, text, or links indicating the need to pay may be shown.
The associated Privacy Policy and Terms of Use pages must also be free of any
commerce UI or Store links.
Must comply with the Outlook add-in design guidelines.
You must accept Apple's Terms and Conditions by selecting the appropriate
checkbox on the Partner Center app submission form.
Your add-in must be compliant with all relevant Apple App Store policies.
You must provide a valid Apple ID.
Outlook add-ins with mobile support receive additional design review during validation,
which adds to the required validation time. Outlook add-in design guidelines (link
above) describes how your offer will be evaluated during the design review.
1120.3 Functionality
Add-ins must follow design guidelines without impeding the customer experience
within the host application.
Your app or add-in must be fully functional with the supported operating systems,
browsers, and devices for Office 2016, SharePoint 2013, and Office 365.
Your add-in will be tested and evaluated on Windows 10 (build 1903+ on Edge
Legacy and earlier builds prior to 1903 with Internet Explorer 11).
All features must work on a touch-only device without a physical keyboard or
mouse.
Your app or add-in must not utilize deprecated functionality.
Your add-in may not alter or promote the alteration of Office or SharePoint except
via the Office and SharePoint add-ins model.
Add-ins must be compatible with the latest versions of Microsoft Edge, Google Chrome,
Mozilla Firefox, and Apple Safari (macOS). Internet Explorer (IE) in Windows is still used
in many Office configurations as noted in Browsers used by Office Add-ins. We
recommend supporting IE, but if your add-in does not, you should advise users to install
the latest Office version. For details, see Determine at runtime if the add-in is running in
Internet Explorer.
Add-ins must work in all Office applications specified in the Hosts element in the add-in
manifest.
Add-ins must work across all platforms that support methods defined in the
Requirements element in the add-in manifest, with the following platform-specific
requirements.
Add-ins must support Office on web and Mac applications compatible with the
APIs listed in the Requirements element.
Add-ins that support iOS must be fully functional on the latest iPad device using
the latest version of iOS.
Add-ins that use the task pane manifest must support add-in commands.
Content add-ins for PowerPoint may not activate their content (such as play audio
or video) until after the JavaScript API for Office Office.initialize event has been
called. This ensures that content display will correctly synchronize with
presentations.
To help ensure an efficient validation process, if your add-in supports Single Sign-On,
you must provide certification test notes explaining how your add-in uses SSO and what
functionality in the add-in uses it. This information is required to ensure the validation
team can test the fallback implementation. Offers that support Single Sign-On (SSO)
must follow the SSO guidelines and include a fallback authentication method.
Outlook add-ins that support mobile must allow users to log on separately for
each email account added to the Outlook app.
Add-in commands must be supported if your add-in is shown on every message or
appointment, whether in read or compose mode.
If your add-in manifest includes the SupportPinning element for read mode of a
message and/or appointment, the pinned content of the add-in must not be static
and must clearly display data related to the message and/or appointment that is
open or selected in the mailbox.
Outlook add-ins must not include the ItemSend event in the Events extension
point.
If your add-in can use the AppendOnSend feature, you must include a disclosure in
your offer description noting in what conditions the option is used and what
information is being inserted (for example, "If configured to do so, this add-in
appends legal disclaimers to email sent by the user").
If your add-in uses the Event-based Activation feature, you must include a
disclosure in your offer description noting what information is being inserted in
what events or conditions (for example, "Defined Signature will be inserted in Mail
subject on composing new e-mail"). To help ensure an efficient validation process,
when submitting your offer you must provide certification test notes explaining
how to configure and test scenarios for auto launch events in your add-in.
Add-ins must not include the "Block" SendMode when using LaunchEvents
"OnMessageSend" and/or "onAppointmentSend".
Your custom functions metadata must have the helpUrl property set.
1120.5.2 Security
To help to ensure the security of your app and users, your custom functions HTML,
JavaScript, and JSON metadata files must be hosted on the same domain.
1120.5.3 Functionality
Add-ins that contain custom functions must support add-in commands. This is to ensure
that users can easily discover your add-in.
Your add-in must work across all platforms that support custom functions.
After an add-in is approved using the EquivalentAddins tag in the manifest, all future
updates to the add-in must include this tag. This tag ensures that your custom functions
save in XLL-compatible mode.
1120.5.4 Validation
To help ensure an efficient validation process, if your add-in contains custom functions,
you must provide certification test notes for at least one custom function to validate
them on submission.
1140 Teams
The policies listed in this section apply only to Teams offers.
Refer to the Teams store validation guidelines to get a better understanding of these
policies and to increase the likelihood of your app passing the Microsoft Teams store
validation process.
Common nouns must be prefixed or suffixed with the publisher’s name (for example,
"XYZ Tasks" rather than "Tasks").
No payment shall be made through an app for goods or services prohibited by General
policy 100.10 Inappropriate content.
1140.4 Functionality
1140.4.1 General
App packages must be correctly formatted and conform to the latest release of the
manifest schema.
Apps may not launch functionality outside of the Microsoft Teams app experience
without the explicit permission of the user.
Graph API permissions requested by apps should align with business scenarios.
Compatibility: Teams apps must be fully functional on the latest versions of the
following operating systems and browsers:
Microsoft Windows
macOS
Microsoft Edge
Google Chrome
iOS
Android
For other unsupported operating systems and browsers, apps must provide a graceful
failure message.
Response time: Teams apps must respond within a reasonable time frame.
Tabs must load within two seconds or display a loading message or warning.
Bots must respond to user commands within two seconds or display a typing
indicator.
Messaging extensions must respond to user commands within two seconds.
Notifications based on user actions must be displayed within two seconds.
App listing must contain a minimum of 3 screenshots depicting the app functionality in
Teams. Screenshots must also depict app functionality in the Teams mobile clients,
where supported.
Videos provided in the app listing must not be more than 90 seconds in duration and
must only show how the app works in Teams. You must turn off ads in YouTube/Vimeo
settings before submitting the video link in Partner Center.
You must provide test accounts and / or fully configured test environments that are valid
in perpetuity (till app is live on the Teams store) for continuous health evaluation of your
app.
Apps from the same developer offering the same functionality must share an app listing
unless;
App must not allow use of facial recognition capabilities to identify an individual to
be used by or for a police department in the United States.
Developers of apps utilizing facial recognition or emotional inference technologies
must provide a prominent tag or indication of each of these capabilities in the app
description.
This policy pertains only to apps that use facial expressions or facial movements
to infer emotional states, such as anger, disgust, happiness, sadness, surprise,
fear, or other terms commonly used to describe the emotional state of a person.
It does not pertain to apps that use facial expressions and movements to detect
and classify only individual facial elements, such as smiles or raised eyebrows.
The key distinction is between the detection of facial expressions or movements
as visual signals versus the inference of an emotional state.
1140.4.2 Tabs
Teams apps must follow Teams tab design guidelines without impeding the customer
experience within the host application.
1140.4.3 Bots
Teams apps must follow Teams bot design guidelines without impeding the customer
experience within the host application.
Bot information in the app manifest must be consistent with the bot's Bot Framework
metadata (bot name, logo, privacy link, and terms of service link).
Bots must not spam users by sending multiple messages in short succession. Avoid
multi turn conversations in a bot response.
Bots in collaborative scope must send a welcome message on first launch if the app has
a complex configuration workflow.
Bots in collaborative scope must provide user interaction value in the same scope.
At least one bot command must be listed in the manifest for each scope supported by
the bot. Listed bot commands must contain clear command title and description.
Teams apps must follow Teams messaging extension design guidelines without
impeding the customer experience within the host application.
Action Commands:
For action commands triggered from a chat message or channel post, calls to
action in apps must incorporate the host app name instead of only using a generic
verb (for example, "Start a Skype Meeting" rather than "Start Meeting", "Upload file
to DocuSign" rather than "Upload file", and so on).
Action commands triggered from a chat message or channel post should leverage
the context of the conversation and must not ask users to re-enter this
information.
Search commands:
Do not add domains that are outside your control (either absolute URLs or wildcards).
For example, yourapp.onmicrosoft.com is valid but *.onmicrosoft.com is not valid. Top-
level domains are also prohibited (for example, *.com or *.org ).
Teams apps must follow Teams task module design guidelines without impeding the
customer experience within the host application.
Task modules should not embed an entire app. Task modules should only display the
components required to complete a specific action.
Apps must not spam users by sending multiple notifications in quick succession.
Must not include any in-app purchases, trial offers, UI that aims to up-sell to paid
versions, or links to any online stores where users can purchase or acquire other
content, apps, or add-ins.
Must not show any UI or language or link to any other apps, add-ins, or websites
that ask the user to pay. If the add-in requires an account, accounts may only be
created if there is no charge; the use of the term "free" or "free account" is not
allowed. You may determine whether the account is active indefinitely or for a
limited time, but if the account expires, no UI, text, or links indicating the need to
pay may be shown.
The associated Privacy Policy and Terms of Use pages must also be free of any
commerce UI or Store links.
You must provide a valid Apple App Store Connect Team ID in your Partner Center
account to enable users to acquire and install your app from the Teams App Store on
Teams mobile clients.
Admin users must be able to complete end-to-end bulk purchase flows from the
Microsoft Teams Admin Center.
After successful purchase and assignment of licenses, your offer must provide enough
value to justify the purchase and users must have access to the subscribed plan features
in Teams.
The offer must meet all the technical requirements for Teams apps linked to a SaaS offer.
1140.7 Advertising
Teams apps may not include advertising.
Teams apps extensible across Microsoft 365 must be fully responsive and fully
functional on the latest versions of these clients:
Screenshots in the app listing must depict app functionality in all the supported clients.
The app’s listing description must be relevant to all the supported clients (Microsoft
Teams, Microsoft Outlook and Microsoft Office)
The app’s support URL content must be relevant to all the supported clients (Microsoft
Teams, Microsoft Outlook and Microsoft Office)
1160.1 Security
Add-ins must not have any unauthenticated pages or APIs, except for the error page.
An unauthenticated error page should not link to other pages or other protected
resources of the add-in.
If the solution requires full trust (formerly known as high trust) permissions, you will
need to follow the guidelines from this Developer Blog post.
1160.2 Functionality
SharePoint add-ins must be fully functional with Windows 7, Windows 10, all versions of
Internet Explorer 11 and later, and the latest versions of Microsoft Edge, Google
Chrome, and Mozilla Firefox.
Add-ins designed for the modern SharePoint experience are not required to support the
classic SharePoint experience. If your add-in supports only the classic experience, you
must include that limitation in your add-in description.
Add-ins must not have remote debugging settings enabled. The manifest for your add-
in must not include the DebugInfo element.
1170.2 Security
SharePoint Framework solutions can request any permissions with the solution manifest.
High permissions requests will need to be justified and clarified as part of the solution
submission process.
1170.3 Functionality
SharePoint Framework (SPFx) solutions must be correctly formatted and conform to the
latest SPFx versions.
Solutions must be fully functional with Windows 10 and the latest versions of Microsoft
Edge, Google Chrome, and Mozilla Firefox. Solutions are only required to be tested in
the non-root site of a modern SharePoint site. Test SPFx solutions on /appsmod only.
Response times must be reasonable. Responses that take more than three seconds must
display a loading message or warning.
Offers should include the E2E functional document. Alternatively, SPFx solution
functionality demonstration video links can be included in the Notes for Certification.
If your Power BI visual offers additional purchases, it must comply with the In-App
Purchase (IAP) guidelines.
1180.2 Functionality
Your visual must support Power BI Desktop, Power BI Online, Power BI mobile apps, and
Power BI Windows universal apps. It must be compatible with supported operating
systems, browsers, and devices for Power BI, including touch-only devices without a
physical keyboard or mouse.
All visuals must support the context menu (right click menu). You can learn more about
the context menu here.
Your visual must support the core functions of Power BI for that visual type, including
but not limited to pinning to dashboard, filtering focus mode, and formatting various
data types.
String values
Empty values
Negative values
Lots of rows (at least 20,000 rows)
Large numbers of 16 digits
Your visual must not launch functionality outside of the visual experience without the
explicit permission of the user.
Your visual and its description must not prompt the user to install any additional files.
Your visual must not prompt a user to disclose the credentials of a Microsoft identity (for
example, Microsoft 365 (formerly called Office 365) or Microsoft Azure Organizational
Account, Microsoft Account, or Windows Domain Account) except through Microsoft
approved OAuth flow, where your visual is authorized to act on behalf of the user.
Your visual may not open pop-up windows unless they are triggered by explicit user
action. Pop-up windows must not be blocked by the browser's pop-up blocker when the
blocker is set to the default value.
Your visual may not request unreasonably high permissions or full-control permission.
Visuals that depend on external accounts or services must provide a clear and simple
sign in/sign out and sign-up experience.
Power BI visuals must be accompanied by a sample file in .pbix format. The version and
content of the .pbiviz file should match the corresponding visual contained in the
.pbix sample file. For the best user experience, consider adding Hits and Tips for using
The code repository for your visual should be available and correctly formatted.
Your source code should comply with all security and privacy policies. Source code must
be safe and not pass or transmit customer data externally.
1200.1.4 Code functionality
Running visual development related commands on top of your visual source code
should not return any errors.
Visual consumption should not expose any errors or failures and must ensure the
functionality of any previous version is preserved.
You may submit duplicate versions of visuals to the Marketplace: a non-certified version
that uses external services or resources, and a certified version that does not use
external services or resources. The offer that accesses external services or resources
must clearly state so in the description.
Descriptions and summaries should not use the deprecated term "content packs". New
app offers may use the term "template apps".
Offer updates should use the same Power BI tenant and workspace as previous offer
versions.
Power BI apps may not be published more than once via different offers.
Offers should successfully install within two minutes and load within thirty seconds.
Sample data is not supported for new (not yet published) offers. Offers must be able to
connect with customer data.
See Supported countries, languages, app Version, and app release date.
1420.4 Functionality
Any feature changes between updates must be re-certified when the offer is re-
submitted. The entire solution package must be submitted with each update to ensure
dependency issues are covered. The version number must be incremented with each
update.
The end-to-end (E2E) functional document must be updated with functional scenarios
and the user/admin journey.
Commercial marketplace offers must be recertified within six months of their last
successful publish.
Custom code provided inside Package Deployer will be validated before offer approval
and checked for retrieval of customer data from the target environment.
The Offer Description field must be in HTML format and must include the full
product name.
The Contact Email and Phone Number fields must have valid, working values.
The Storefront Details > App Choice field must be set to "Contact me".
The CAR file must be uploaded using the Technical Info > Validation asset(s) field.
Commercial marketplace offers must be recertified within six months of their last
successful publish.
Your offer must include a complete set of collateral documents (bill of materials),
including a solution/offer pitch deck and a solution/offer one-pager.
Services partners must be enrolled in the Microsoft Cloud Partner Program and
completed a Solutions Partner Designation .
Azure Applications, Azure Containers, IoT Edge Modules, SaaS, and VMs must meet the
following requirements:
Your organization must meet or exceed $100,000 USD of Azure consumed revenue
over a trailing 12-month period, or your offer must have a cumulative marketplace
billed revenue of $100,000 USD.
For SaaS offers: your product must be primarily platformed on Microsoft Azure.
For non-SaaS offers: must be deployed in Azure.
Your offer must be transactable and listed as a "Sell through Microsoft” on the
Azure Marketplace.
3000.3.1 Segmentation
3000.3.4 Timeline
Completed deals must be registered within 60 days after signing.
The deal must be at least $25,000 USD in annual revenue, including your products,
licenses, and IP solution related services, and should exclude any trial component, EA,
and hardware components.
Start and end dates are required for the contract duration. If the contract term is 6 or
more years or there is no defined term or end date, the perpetual partner license should
be selected.
Next steps
Visit the commercial marketplace publishing guide.
) Important
Once you have created the app catalog follow the steps to publish an Office Add-in.
7 Note
2. Open the app catalog site by selecting its URL in the URL column.
7 Note
If you just created the app catalog site in the previous section, it can take a
few minutes for the site to finish setting up.
6. Locate and specify the manifest file to upload and choose Open.
For Office applications on the desktop, you can find Office Add-ins from the app catalog
by completing the following steps.
2. Choose File > Options > Trust Center > Trust Center Settings > Trusted Add-in
Catalogs.
3. Enter the URL of the SharePoint app catalog in the Catalog Url box and choose
Add catalog. Use the shorter form of the URL. For example, if the URL of the
SharePoint app catalog is:
https://<domain>/sites/<AddinCatalogSiteCollection>/AgaveCatalog
https://<domain>/sites/<AddinCatalogSiteCollection>
6. In the Office Add-ins dialog, choose the MY ORGANIZATION tab. The Office Add-
ins are listed.
Microsoft provides the government cloud options for our privacy-sensitive customers in
local, state, and national government organizations. This gives partners opportunities to
target critical customers with their Office Add-ins. Due to the more restricted nature of
these environments, which is important for the customers’ privacy and security needs,
not all resources that are typically available in a standard production environment are
available within these clouds.
For partners providing their Office Add-ins to customers in these restricted cloud
environments, there are important differences from the standard public cloud
environment that must be considered. The following information gives the details that
require special handling by developers writing Office Add-ins that target customers in
these environments.
The required resources and services for your solution are available inside the cloud
boundary. Either you work with the tenant administrators to provision your service
and resources inside of the cloud boundary, or you work with the network
administrator to enable access to your resources that reside outside of the cloud
boundary.
The resources the Office Add-in accesses conform to the requirements of the
government cloud from which they are being accessed. They also must conform to
any additional requirements from the customer tenant for which the solution is
being provisioned. These requirements include the transfer, management, and
storage of potentially sensitive data, as well as code and resource security and
access vetting procedures.
The Office Add-in manifest that describes the solution and its source location as
applicable to the particular government cloud deployment is obtained from the
partner and ingested for deployment to the appropriate users via the Admin
Portal.
GCC High:
https://appsforoffice.gcch.cdn.office.net/appsforoffice/lib/1/hosted/office.js
DOD: https://appsforoffice.dod.cdn.office.net/appsforoffice/lib/1/hosted/office.js
After you publish your add-in, you should keep it up to date with any important
changes from upstream libraries. Patching security issues is critical to building customer
trust. Since these changes have no effect on the published manifest, your customers
won't need to take any actions to get the latest versions of your add-in.
Deprecation policy
APIs or tools with better alternatives may be deprecated. Microsoft undergoes a best
effort to declare something as deprecated at least 24 months in advance of retiring it.
Similarly, for individual APIs that are generally available (GA), Microsoft declares an API
as deprecated at least 24 months in advance of removing it from the GA version.
Deprecation doesn't necessarily mean the feature or API will be removed and unusable
by developers. It does show that after the 24-month time period, Microsoft will no
longer support the API or feature.
When an API is marked as deprecated, we strongly recommend that you migrate to the
latest version as soon as possible. In some cases, we'll announce that new applications
must start to use the new APIs a short time after the original APIs are deprecated. In
those cases, only active applications that currently use the deprecated APIs can continue
to use them.
) Important
The 24-month deprecation period will be accelerated if waiting that long poses a
security risk for your add-in or Microsoft.
App Assure
Microsoft’s App Assure service fulfills Microsoft’s promise of application compatibility:
your apps will work on Windows and Microsoft 365 Apps. App Assure engineers are
available to help resolve any issues you might experience at no additional cost.
If you do encounter an app compatibility issue, App Assure engineers will work with you
to help you resolve the issue. Our experts will:
To learn more about App Assure, watch Bring your apps to Microsoft Edge with App
Assure: tips and tricks . To submit your request for app compatibility with App Assure,
complete the Microsoft FastTrack Registration form or send an email to
achelp@microsoft.com.
npm audit
Dependabot and other GitHub security features
This guidance also applies to copies of samples taken from the Office Add-in code
samples and other sources.
office.js NPM package
The office-js NPM package is a copy of what is hosted on the Office.js content
delivery network (CDN). It's intended for scenarios where direct access to the CDN isn't
possible. The NPM package isn't intended to provide versioned references to office.js.
We strongly recommend always using the CDN to ensure you're using the latest version
of the Office JavaScript APIs.
Deploy updates
When you add features or fix bugs in your add-in, you'll need to deploy the updates. If
your add-in is deployed by one or more admins to their organizations, some manifest
changes will require the admin to consent to the updates. Users will be blocked from
the add-in until consent is granted. The following manifest changes will require the
admin to consent again.
Community engagement
As updates are proposed for the Microsoft 365 Developer Platform, we will be listening
for feedback. Please report concerns, potential consequences, or other questions to the
channels listed in Office Add-ins additional resources.
Excel add-ins documentation
With Excel add-ins, you can use familiar web technologies such as HTML, CSS, and
JavaScript to build a solution that can run in Excel across multiple platforms, including
on Windows, Mac, iPad, and in a web browser. Learn how to build, test, debug, and
publish Excel add-ins.
e OVERVIEW
f QUICKSTART
c HOW-TO GUIDE
Use the Excel JavaScript API to interact with objects and workbook content
e OVERVIEW
p CONCEPT
Resources
i REFERENCE
Ask questions
Request features
Report issues
An Excel add-in allows you to extend Excel application functionality across multiple
platforms including Windows, Mac, iPad, and in a browser. Use Excel add-ins within a
workbook to:
The Office Add-ins platform provides the framework and Office.js JavaScript APIs that
enable you to create and run Excel add-ins. By using the Office Add-ins platform to
create your Excel add-in, you'll get the following benefits.
Cross-platform support: Excel add-ins run in Office on the web, Windows, Mac,
and iPad.
Centralized deployment: Admins can quickly and easily deploy Excel add-ins to
users throughout an organization.
Use of standard web technology: Create your Excel add-in using familiar web
technologies such as HTML, CSS, and JavaScript.
Distribution via AppSource: Share your Excel add-in with a broad audience by
publishing it to AppSource .
7 Note
Excel add-ins are different from COM and VSTO add-ins, which are earlier Office
integration solutions that run only in Office on Windows. Unlike COM add-ins, Excel
add-ins do not require you to install any code on a user's device, or within Excel.
The web application uses the Office JavaScript API to interact with objects in Excel, and
can also facilitate interaction with online resources. For example, an add-in can perform
any of the following tasks.
Create, read, update, and delete data in the workbook (worksheets, ranges, tables,
charts, named items, and more).
Perform user authorization with an online service by using the standard OAuth 2.0
flow.
Issue API requests to Microsoft Graph or any other API.
The web application can be hosted on any web server, and can be built using client-side
frameworks (such as Angular, React, jQuery) or server-side technologies (such as
ASP.NET, Node.js, PHP).
The manifest is a configuration file that defines how the add-in integrates with Office
clients by specifying settings and capabilities such as:
To enable end users to install and use an Excel add-in, you must publish its manifest
either to AppSource or to an add-ins catalog. For details about publishing to
AppSource, see Make your solutions available in AppSource and within Office.
Add-in commands
Add-in commands are UI elements that extend the Excel UI and start actions in your
add-in. You can use add-in commands to add a button on the ribbon or an item to a
context menu in Excel. When users select an add-in command, they initiate actions such
as running JavaScript code, or showing a page of the add-in in a task pane.
For more information about command capabilities, supported platforms, and best
practices for developing add-in commands, see Add-in commands for Excel, Word, and
PowerPoint.
Task panes
Task panes are interface surfaces that typically appear on the right side of the window
within Excel. Task panes give users access to interface controls that run code to modify
the Excel document or display data from a data source.
For more information about task panes, see Task panes in Office Add-ins. For a sample
that implements a task pane in Excel, see Excel Add-in JS WoodGrove Expense Trends .
Custom functions
Custom functions enable developers to add new functions to Excel by defining those
functions in JavaScript as part of an add-in. Users within Excel can access custom
functions just as they would any native function in Excel, such as SUM() .
For more information about custom functions, see Create custom functions in Excel.
Dialog boxes
Dialog boxes are surfaces that float above the active Excel application window. You can
use dialog boxes for tasks such as displaying sign-in pages that can't be opened directly
in a task pane, requesting that the user confirm an action, or hosting videos that might
be too small if confined to a task pane. To open dialog boxes in your Excel add-in, use
the Dialog API.
For more information about dialog boxes and the Dialog API, see Use the Dialog API in
your Office Add-ins.
Content add-ins
Content add-ins are surfaces that you can embed directly into Excel documents. You can
use content add-ins to embed rich, web-based objects such as charts, data
visualizations, or media into a worksheet or to give users access to interface controls
that run code to modify the Excel document or display data from a data source. Use
content add-ins when you want to embed functionality directly into the document.
For more information about content add-ins, see Content Office Add-ins. For a sample
that implements a content add-in in Excel, see Excel Content Add-in Humongous
Insurance in GitHub.
Excel JavaScript API: Introduced with Office 2016, the Excel JavaScript API provides
strongly-typed Excel objects that you can use to access worksheets, ranges, tables,
charts, and more.
Common API: Introduced with Office 2013, the Common API enables you to access
features such as UI, dialogs, and client settings that are common across multiple
types of Office applications. The limited functionality for Excel interaction in the
Common API has been replaced by the Excel JavaScript API.
Next steps
Get started by creating your first Excel add-in. Then, learn about the core concepts of
building Excel add-ins.
See also
Office Add-ins platform overview
Learn about Microsoft 365 Developer Program
Developing Office Add-ins
Excel JavaScript object model in Office Add-ins
Excel JavaScript API reference
Build an Excel task pane add-in
Article • 03/28/2023
In this article, you'll walk through the process of building an Excel task pane add-in.
Yeoman generator
Prerequisites
7 Note
If you aren't familiar with Node.js or npm, you should start by setting up your
development environment.
The latest version of Yeoman and the Yeoman generator for Office Add-ins.
To install these tools globally, run the following command via the command
prompt.
command line
7 Note
command line
yo office
7 Note
When you run the yo office command, you may receive prompts about the
data collection policies of Yeoman and the Office Add-in CLI tools. Use the
information that's provided to respond to the prompts as you see fit.
When prompted, provide the following information to create your add-in project.
After you complete the wizard, the generator creates the project and installs
supporting Node components.
Tip
You can ignore the next steps guidance that the Yeoman generator provides
after the add-in project's been created. The step-by-step instructions within
this article provide all of the guidance you'll need to complete this tutorial.
The ./manifest.xml file in the root directory of the project defines the settings
and capabilities of the add-in. To learn more about the manifest.xml file, see
Office Add-ins XML manifest.
The ./src/taskpane/taskpane.html file contains the HTML markup for the task
pane.
The ./src/taskpane/taskpane.css file contains the CSS that's applied to
content in the task pane.
The ./src/taskpane/taskpane.js file contains the Office JavaScript API code
that facilitates interaction between the task pane and the Office client
application.
Try it out
1. Navigate to the root folder of the project.
command line
2. Complete the following steps to start the local web server and sideload your
add-in.
7 Note
Office Add-ins should use HTTPS, not HTTP, even while you're
developing. If you're prompted to install a certificate after you run one of
the following commands, accept the prompt to install the certificate that
the Yeoman generator provides. You may also have to run your command
prompt or terminal as an administrator for the changes to be made.
Tip
If you're testing your add-in on Mac, run the following command before
proceeding. When you run this command, the local web server starts.
command line
To test your add-in in Excel, run the following command in the root
directory of your project. This starts the local web server and opens Excel
with your add-in loaded.
command line
npm start
7 Note
command line
https://contoso.sharepoint.com/:t:/g/EZGxP7ksiE5DuxvY638G798Bpuhwl
uxCMfF1WZQj3VYhYQ?e=F4QM1R
npm run start:web -- --document
https://1drv.ms/x/s!jkcH7spkM4EGgcZUgqthk4IK3NOypVw?e=Z6G1qp
npm run start:web -- --document https://contoso-my.sharepoint-
df.com/:t:/p/user/EQda453DNTpFnl1bFPhOVR0BwlrzetbXvnaRYii2lDr_oQ?
e=RSccmNP
If your add-in doesn't sideload in the document, manually sideload it by
following the instructions in Manually sideload add-ins to Office on the
web.
3. In Excel, choose the Home tab, and then choose the Show Taskpane button
on the ribbon to open the add-in task pane.
5. At the bottom of the task pane, choose the Run link to set the color of the
selected range to yellow.
Next steps
Congratulations, you've successfully created an Excel task pane add-in! Next, learn
more about the capabilities of an Excel add-in and build a more complex add-in by
following along with the Excel add-in tutorial.
Code samples
Excel "Hello world" add-in : Learn how to build a simple Office Add-in with only a
manifest, HTML web page, and a logo.
See also
Office Add-ins platform overview
Develop Office Add-ins
Excel JavaScript object model in Office Add-ins
Excel add-in code samples
Excel JavaScript API reference
Using Visual Studio Code to publish
Use React to build an Excel task pane
add-in
Article • 03/28/2023
In this article, you'll walk through the process of building an Excel task pane add-in
using React and the Excel JavaScript API.
Prerequisites
7 Note
If you aren't familiar with Node.js or npm, you should start by setting up your
development environment.
The latest version of Yeoman and the Yeoman generator for Office Add-ins. To
install these tools globally, run the following command via the command prompt.
command line
7 Note
command line
yo office
7 Note
When you run the yo office command, you may receive prompts about the data
collection policies of Yeoman and the Office Add-in CLI tools. Use the information
that's provided to respond to the prompts as you see fit.
When prompted, provide the following information to create your add-in project.
Choose a project type: Office Add-in Task Pane project using React framework
Choose a script type: TypeScript
What do you want to name your add-in? My Office Add-in
Which Office client application would you like to support? Excel
After you complete the wizard, the generator creates the project and installs supporting
Node components.
Tip
You can ignore the next steps guidance that the Yeoman generator provides after
the add-in project's been created. The step-by-step instructions within this article
provide all of the guidance you'll need to complete this tutorial.
Try it out
1. Navigate to the root folder of the project.
command line
2. Complete the following steps to start the local web server and sideload your add-
in.
7 Note
Office Add-ins should use HTTPS, not HTTP, even while you're developing. If
you're prompted to install a certificate after you run one of the following
commands, accept the prompt to install the certificate that the Yeoman
generator provides. You may also have to run your command prompt or
terminal as an administrator for the changes to be made.
Tip
If you're testing your add-in on Mac, run the following command before
proceeding. When you run this command, the local web server starts.
command line
command line
npm start
To test your add-in in Excel on a browser, run the following command in the
root directory of your project. When you run this command, the local web
server starts. Replace "{url}" with the URL of an Excel document on your
OneDrive or a SharePoint library to which you have permissions.
7 Note
command line
https://contoso.sharepoint.com/:t:/g/EZGxP7ksiE5DuxvY638G798BpuhwluxCM
fF1WZQj3VYhYQ?e=F4QM1R
https://1drv.ms/x/s!jkcH7spkM4EGgcZUgqthk4IK3NOypVw?e=Z6G1qp
npm run start:web -- --document https://contoso-my.sharepoint-
df.com/:t:/p/user/EQda453DNTpFnl1bFPhOVR0BwlrzetbXvnaRYii2lDr_oQ?
e=RSccmNP
3. In Excel, choose the Home tab, and then choose the Show Taskpane button on the
ribbon to open the add-in task pane.
4. Select any range of cells in the worksheet.
5. At the bottom of the task pane, choose the Run link to set the color of the selected
range to yellow.
Next steps
Congratulations, you've successfully created an Excel task pane add-in using React!
Next, learn more about the capabilities of an Excel add-in and build a more complex
add-in by following along with the Excel add-in tutorial.
In this article, you'll walk through the process of building an Excel task pane add-in
using Vue and the Excel JavaScript API.
Prerequisites
7 Note
If you aren't familiar with Node.js or npm, you should start by setting up your
development environment.
The latest version of Yeoman and the Yeoman generator for Office Add-ins. To
install these tools globally, run the following command via the command prompt.
command line
7 Note
Install the Vue CLI globally. From the terminal, run the following command.
command line
Then, select the Default preset for "Vue 3" (if you prefer, choose "Vue 2").
command line
cd my-add-in
2. Use the Yeoman generator to generate the manifest file for your add-in.
command line
yo office
7 Note
When you run the yo office command, you may receive prompts about the
data collection policies of Yeoman and the Office Add-in CLI tools. Use the
information that's provided to respond to the prompts as appropriate. If you
choose Exit in response to the second prompt, you'll need to run the yo
office command again when you're ready to create your add-in project.
When prompted, provide the following information to create your add-in project.
Choose a project type: Office Add-in project containing the manifest only
What do you want to name your add-in? My Office Add-in
Which Office client application would you like to support? Excel
After completion, the wizard creates a My Office Add-in folder containing a
manifest.xml file. You'll use the manifest to sideload and test your add-in.
Tip
You can ignore the next steps guidance that the Yeoman generator provides after
the add-in project's been created. The step-by-step instructions within this article
provide all of the guidance you'll need to complete this tutorial.
1. Enable HTTPS for your app. In the root folder of the Vue project, create a
vue.config.js file with the following contents.
JavaScript
const fs = require("fs");
const path = require("path");
const homedir = require('os').homedir()
module.exports = {
devServer: {
port: 3000,
https: {
key: fs.readFileSync(path.resolve(`${homedir}/.office-addin-dev-
certs/localhost.key`)),
cert: fs.readFileSync(path.resolve(`${homedir}/.office-addin-dev-
certs/localhost.crt`)),
ca: fs.readFileSync(path.resolve(`${homedir}/.office-addin-dev-
certs/ca.crt`)),
}
}
}
command line
The manifest.xml file in the root directory of the project defines the settings and
capabilities of the add-in. To learn more about the manifest.xml file, see Office
Add-ins XML manifest.
The ./src/App.vue file contains the HTML markup for the task pane, the CSS that's
applied to the content in the task pane, and the Office JavaScript API code that
facilitates interaction between the task pane and Excel.
HTML
<script
src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js">
</script>
2. Open manifest.xml and find the <bt:Urls> tags inside the <Resources> tag.
Locate the <bt:Url> tag with the ID Taskpane.Url and update its DefaultValue
attribute. The new DefaultValue is https://localhost:3000/index.html . The entire
updated tag should match the following line.
HTML
<bt:Url id="Taskpane.Url"
DefaultValue="https://localhost:3000/index.html" />
3. Open ./src/main.js and replace the contents with the following code.
JavaScript
window.Office.onReady(() => {
createApp(App).mount('#app');
});
4. Open ./src/App.vue and replace the file contents with the following code.
HTML
<template>
<div id="app">
<div class="content">
<div class="content-header">
<div class="padding">
<h1>Welcome</h1>
</div>
</div>
<div class="content-main">
<div class="padding">
<p>
Choose the button below to set the color of the selected
range to
green.
</p>
<br />
<h3>Try it out</h3>
<button @click="onSetColor">Set color</button>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'App',
methods: {
onSetColor() {
window.Excel.run(async context => {
const range = context.workbook.getSelectedRange();
range.format.fill.color = 'green';
await context.sync();
});
}
}
};
</script>
<style>
.content-header {
background: #2a8dd4;
color: #fff;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 80px;
overflow: hidden;
}
.content-main {
background: #fff;
position: fixed;
top: 80px;
left: 0;
right: 0;
bottom: 0;
overflow: auto;
}
.padding {
padding: 15px;
}
</style>
command line
Try it out
1. Run your add-in and sideload the add-in within Excel. Follow the instructions for
the platform you'll be using:
2. Open the add-in task pane in Excel. On the Home tab, choose the Show Taskpane
button.
4. Set the color of the selected range to green. In your add-in's task pane, choose the
Set color button.
Next steps
Congratulations, you've successfully created an Excel task pane add-in using Vue! Next,
learn more about the capabilities of an Excel add-in and build a more complex add-in
by following along with the Excel add-in tutorial.
See also
Office Add-ins platform overview
Develop Office Add-ins
Excel JavaScript object model in Office Add-ins
Excel add-in code samples
Excel JavaScript API reference
Using Visual Studio Code to publish
Tutorial: Create an Excel task pane add-
in
Article • 03/28/2023
" Creates a table
" Filters and sorts a table
" Creates a chart
" Freezes a table header
" Protects a worksheet
" Opens a dialog
Tip
If you've already completed the Build an Excel task pane add-in quick start using
the Yeoman generator, and want to use that project as a starting point for this
tutorial, go directly to the Create a table section to start this tutorial.
If you want a completed version of this tutorial, head over to the Office Add-ins
samples repo on GitHub .
Prerequisites
Node.js (the latest LTS version).
The latest version of Yeoman and the Yeoman generator for Office Add-ins. To
install these tools globally, run the following command via the command prompt.
command line
7 Note
If you don't already have Office, you can join the Microsoft 365 developer
program to get a free, 90-day renewable Microsoft 365 subscription to use
during development.
command line
yo office
7 Note
When you run the yo office command, you may receive prompts about the data
collection policies of Yeoman and the Office Add-in CLI tools. Use the information
that's provided to respond to the prompts as you see fit.
When prompted, provide the following information to create your add-in project.
Tip
You can ignore the next steps guidance that the Yeoman generator provides after
the add-in project's been created. The step-by-step instructions within this article
provide all of the guidance you'll need to complete this tutorial.
Create a table
In this step of the tutorial, you'll programmatically test that your add-in supports the
user's current version of Excel, add a table to a worksheet, populate the table with data,
and format it.
2. Open the file ./src/taskpane/taskpane.html. This file contains the HTML markup
for the task pane.
3. Locate the <main> element and delete all lines that appear after the opening
<main> tag and before the closing </main> tag.
4. Add the following markup immediately after the opening <main> tag.
HTML
5. Open the file ./src/taskpane/taskpane.js. This file contains the Office JavaScript API
code that facilitates interaction between the task pane and the Office client
application.
6. Remove all references to the run button and the run() function by doing the
following:
7. Within the Office.onReady function call, locate the line if (info.host ===
Office.HostType.Excel) { and add the following code immediately after that line.
Note:
JavaScript
Your Excel.js business logic will be added to the function that is passed to
Excel.run . This logic does not execute immediately. Instead, it is added to a
queue of pending commands.
The tryCatch function will be used by all the functions interacting with the
workbook from the task pane. Catching Office JavaScript errors in this fashion
is a convenient way to generically handle any uncaught errors.
7 Note
The following code uses ES6 JavaScript, which is not compatible with older
versions of Office that use the Trident (Internet Explorer 11) browser engine.
For information on how to support those platforms in production, see
Support older Microsoft webviews and Office versions. Join the Microsoft
365 developer program to get a free, 90-day renewable Microsoft 365
subscription, with the latest Office applications, to use during development.
JavaScript
await context.sync();
});
}
9. Within the createTable() function, replace TODO1 with the following code. Note:
The code creates a table by using the add method of a worksheet's table
collection, which always exists even if it is empty. This is the standard way
that Excel.js objects are created. There are no class constructor APIs, and you
never use a new operator to create an Excel object. Instead, you add to a
parent collection object.
The first parameter of the add method is the range of only the top row of the
table, not the entire range the table will ultimately use. This is because when
the add-in populates the data rows (in the next step), it will add new rows to
the table instead of writing values to the cells of existing rows. This is a
common pattern, because the number of rows a table will have is often
unknown when the table is created.
Table names must be unique across the entire workbook, not just the
worksheet.
JavaScript
const currentWorksheet =
context.workbook.worksheets.getActiveWorksheet();
const expensesTable = currentWorksheet.tables.add("A1:D1", true
/*hasHeaders*/);
expensesTable.name = "ExpensesTable";
10. Within the createTable() function, replace TODO2 with the following code. Note:
New rows are created in a table by calling the add method of the table's row
collection. You can add multiple rows in a single call of add by including
multiple cell value arrays in the parent array that is passed as the second
parameter.
JavaScript
expensesTable.getHeaderRowRange().values =
[["Date", "Merchant", "Category", "Amount"]];
11. Within the createTable() function, replace TODO3 with the following code. Note:
The code gets a reference to the Amount column by passing its zero-based
index to the getItemAt method of the table's column collection.
7 Note
array.
The code then formats the range of the Amount column as Euros to the
second decimal. Learn more about the Excel number format syntax in the
article Number format codes /
Finally, it ensures that the width of the columns and height of the rows is big
enough to fit the longest (or tallest) data item. Notice that the code must get
Range objects to format. TableColumn and TableRow objects do not have
format properties.
JavaScript
expensesTable.columns.getItemAt(3).getRange().numberFormat =
[['\u20AC#,##0.00']];
expensesTable.getRange().format.autofitColumns();
expensesTable.getRange().format.autofitRows();
12. Verify that you've saved all of the changes you've made to the project.
7 Note
Office Add-ins should use HTTPS, not HTTP, even while you're developing. If
you're prompted to install a certificate after you run one of the following
commands, accept the prompt to install the certificate that the Yeoman
generator provides. You may also have to run your command prompt or
terminal as an administrator for the changes to be made.
Tip
If you're testing your add-in on Mac, run the following command in the root
directory of your project before proceeding. When you run this command, the
local web server starts.
command line
To test your add-in in Excel, run the following command in the root directory
of your project. This starts the local web server (if it's not already running)
and opens Excel with your add-in loaded.
command line
npm start
To test your add-in in Excel on the web, run the following command in the
root directory of your project. When you run this command, the local web
server starts. Replace "{url}" with the URL of an Excel document on your
OneDrive or a SharePoint library to which you have permissions.
7 Note
command line
https://contoso.sharepoint.com/:t:/g/EZGxP7ksiE5DuxvY638G798BpuhwluxCM
fF1WZQj3VYhYQ?e=F4QM1R
npm run start:web -- --document
https://1drv.ms/x/s!jkcH7spkM4EGgcZUgqthk4IK3NOypVw?e=Z6G1qp
npm run start:web -- --document https://contoso-my.sharepoint-
df.com/:t:/p/user/EQda453DNTpFnl1bFPhOVR0BwlrzetbXvnaRYii2lDr_oQ?
e=RSccmNP
2. In Excel, choose the Home tab, and then choose the Show Taskpane button on the
ribbon to open the add-in task pane.
3. In the task pane, choose the Create Table button.
2. Locate the <button> element for the create-table button, and add the following
markup after that line.
HTML
JavaScript
document.getElementById("filter-table").onclick = () =>
tryCatch(filterTable);
JavaScript
await context.sync();
});
}
6. Within the filterTable() function, replace TODO1 with the following code. Note:
The code first gets a reference to the column that needs filtering by passing
the column name to the getItem method, instead of passing its index to the
getItemAt method as the createTable method does. Since users can move
table columns, the column at a given index might change after the table is
created. Hence, it is safer to use the column name to get a reference to the
column. We used getItemAt safely in the preceding tutorial, because we used
it in the very same method that creates the table, so there is no chance that a
user has moved the column.
JavaScript
const currentWorksheet =
context.workbook.worksheets.getActiveWorksheet();
const expensesTable = currentWorksheet.tables.getItem('ExpensesTable');
const categoryFilter =
expensesTable.columns.getItem('Category').filter;
categoryFilter.applyValuesFilter(['Education', 'Groceries']);
Sort the table
1. Open the file ./src/taskpane/taskpane.html.
2. Locate the <button> element for the filter-table button, and add the following
markup after that line.
HTML
4. Within the Office.onReady function call, locate the line that assigns a click handler
to the filter-table button, and add the following code after that line.
JavaScript
document.getElementById("sort-table").onclick = () =>
tryCatch(sortTable);
JavaScript
await context.sync();
});
}
6. Within the sortTable() function, replace TODO1 with the following code. Note:
The code creates an array of SortField objects, which has just one member
since the add-in only sorts on the Merchant column.
const currentWorksheet =
context.workbook.worksheets.getActiveWorksheet();
const expensesTable = currentWorksheet.tables.getItem('ExpensesTable');
const sortFields = [
{
key: 1, // Merchant column
ascending: false,
}
];
expensesTable.sort.apply(sortFields);
7. Verify that you've saved all of the changes you've made to the project.
To test your add-in in Excel, run the following command in the root directory
of your project. This starts the local web server (if it's not already running)
and opens Excel with your add-in loaded.
command line
npm start
To test your add-in in Excel on the web, run the following command in the
root directory of your project. When you run this command, the local web
server starts. Replace "{url}" with the URL of an Excel document on your
OneDrive or a SharePoint library to which you have permissions.
7 Note
command line
fF1WZQj3VYhYQ?e=F4QM1R
npm run start:web -- --document
https://1drv.ms/x/s!jkcH7spkM4EGgcZUgqthk4IK3NOypVw?e=Z6G1qp
e=RSccmNP
2. If the add-in task pane isn't already open in Excel, go to the Home tab and choose
the Show Taskpane button on the ribbon to open it.
3. If the table you added previously in this tutorial is not present in the open
worksheet, choose the Create Table button in the task pane.
4. Choose the Filter Table button and the Sort Table button, in either order.
Create a chart
In this step of the tutorial, you'll create a chart using data from the table that you
created previously, and then format the chart.
2. Locate the <button> element for the sort-table button, and add the following
markup after that line.
HTML
4. Within the Office.onReady function call, locate the line that assigns a click handler
to the sort-table button, and add the following code after that line.
JavaScript
document.getElementById("create-chart").onclick = () =>
tryCatch(createChart);
JavaScript
await context.sync();
});
}
6. Within the createChart() function, replace TODO1 with the following code. Note
that in order to exclude the header row, the code uses the Table.getDataBodyRange
method to get the range of data you want to chart instead of the getRange
method.
JavaScript
const currentWorksheet =
context.workbook.worksheets.getActiveWorksheet();
const expensesTable = currentWorksheet.tables.getItem('ExpensesTable');
const dataRange = expensesTable.getDataBodyRange();
7. Within the createChart() function, replace TODO2 with the following code. Note
the following parameters.
The first parameter to the add method specifies the type of chart. There are
several dozen types.
The second parameter specifies the range of data to include in the chart.
The third parameter determines whether a series of data points from the
table should be charted row-wise or column-wise. The option auto tells Excel
to decide the best method.
JavaScript
8. Within the createChart() function, replace TODO3 with the following code. Most of
this code is self-explanatory. Note:
The parameters to the setPosition method specify the upper left and lower
right cells of the worksheet area that should contain the chart. Excel can
adjust things like line width to make the chart look good in the space it has
been given.
A "series" is a set of data points from a column of the table. Since there is
only one non-string column in the table, Excel infers that the column is the
only column of data points to chart. It interprets the other columns as chart
labels. So there will be just one series in the chart and it will have index 0. This
is the one to label with "Value in €".
JavaScript
chart.setPosition("A15", "F30");
chart.title.text = "Expenses";
chart.legend.position = "Right";
chart.legend.format.fill.setSolidColor("white");
chart.dataLabels.format.font.size = 15;
chart.dataLabels.format.font.color = "black";
chart.series.getItemAt(0).name = 'Value in \u20AC';
9. Verify that you've saved all of the changes you've made to the project.
To test your add-in in Excel, run the following command in the root directory
of your project. This starts the local web server (if it's not already running)
and opens Excel with your add-in loaded.
command line
npm start
To test your add-in in Excel on the web, run the following command in the
root directory of your project. When you run this command, the local web
server starts. Replace "{url}" with the URL of an Excel document on your
OneDrive or a SharePoint library to which you have permissions.
7 Note
command line
https://contoso.sharepoint.com/:t:/g/EZGxP7ksiE5DuxvY638G798BpuhwluxCM
fF1WZQj3VYhYQ?e=F4QM1R
npm run start:web -- --document
https://1drv.ms/x/s!jkcH7spkM4EGgcZUgqthk4IK3NOypVw?e=Z6G1qp
npm run start:web -- --document https://contoso-my.sharepoint-
df.com/:t:/p/user/EQda453DNTpFnl1bFPhOVR0BwlrzetbXvnaRYii2lDr_oQ?
e=RSccmNP
2. If the add-in task pane isn't already open in Excel, go to the Home tab and choose
the Show Taskpane button on the ribbon to open it.
3. If the table you added previously in this tutorial is not present in the open
worksheet, choose the Create Table button, and then the Filter Table button and
the Sort Table button, in either order.
4. Choose the Create Chart button. A chart is created and only the data from the
rows that have been filtered are included. The labels on the data points across the
bottom are in the sort order of the chart; that is, merchant names in reverse
alphabetical order.
2. Locate the <button> element for the create-chart button, and add the following
markup after that line.
HTML
4. Within the Office.onReady function call, locate the line that assigns a click handler
to the create-chart button, and add the following code after that line.
JavaScript
document.getElementById("freeze-header").onclick = () =>
tryCatch(freezeHeader);
JavaScript
await context.sync();
});
}
6. Within the freezeHeader() function, replace TODO1 with the following code. Note:
The freezeRows method takes as a parameter the number of rows, from the
top, that are to be pinned in place. We pass 1 to pin the first row in place.
JavaScript
const currentWorksheet =
context.workbook.worksheets.getActiveWorksheet();
currentWorksheet.freezePanes.freezeRows(1);
7. Verify that you've saved all of the changes you've made to the project.
command line
npm start
To test your add-in in Excel on the web, run the following command in the
root directory of your project. When you run this command, the local web
server starts. Replace "{url}" with the URL of an Excel document on your
OneDrive or a SharePoint library to which you have permissions.
7 Note
command line
https://contoso.sharepoint.com/:t:/g/EZGxP7ksiE5DuxvY638G798BpuhwluxCM
fF1WZQj3VYhYQ?e=F4QM1R
https://1drv.ms/x/s!jkcH7spkM4EGgcZUgqthk4IK3NOypVw?e=Z6G1qp
npm run start:web -- --document https://contoso-my.sharepoint-
df.com/:t:/p/user/EQda453DNTpFnl1bFPhOVR0BwlrzetbXvnaRYii2lDr_oQ?
e=RSccmNP
2. If the add-in task pane isn't already open in Excel, go to the Home tab and choose
the Show Taskpane button on the ribbon to open it.
3. If the table you added previously in this tutorial is present in the worksheet, delete
it.
4. In the task pane, choose the Create Table button.
6. Scroll down the worksheet far enough to see that the table header remains visible
at the top even when the higher rows scroll out of sight.
Protect a worksheet
In this step of the tutorial, you'll add a button to the ribbon that toggles worksheet
protection on and off.
2. Locate the <Control> element. This element defines the Show Taskpane button on
the Home ribbon you have been using to launch the add-in. We're going to add a
second button to the same group on the Home ribbon. In between the closing
</Control> tag and the closing </Group> tag, add the following markup.
XML
3. Within the XML you just added to the manifest file, replace TODO1 with a string that
gives the button an ID that is unique within this manifest file. Since our button is
going to toggle protection of the worksheet on and off, use "ToggleProtection".
When you are done, the opening tag for the Control element should look like this:
XML
4. The next three TODO s set resource IDs, or resid s. A resource is a string (with a
maximum length of 32 characters), and you'll create these three strings in a later
step. For now, you need to give IDs to the resources. The button label should read
"Toggle Protection", but the ID of this string should be "ProtectionButtonLabel", so
the Label element should look like this:
XML
5. The SuperTip element defines the tool tip for the button. The tool tip title should
be the same as the button label, so we use the very same resource ID:
"ProtectionButtonLabel". The tool tip description will be "Click to turn protection of
the worksheet on and off". But the resid should be "ProtectionButtonToolTip". So,
when you are done, the SuperTip element should look like this:
XML
<Supertip>
<Title resid="ProtectionButtonLabel" />
<Description resid="ProtectionButtonToolTip" />
</Supertip>
7 Note
In a production add-in, you would not want to use the same icon for two
different buttons; but to simplify this tutorial, we'll do that. So the Icon
markup in our new Control is just a copy of the Icon element from the
existing Control .
6. The Action element inside the original Control element has its type set to
ShowTaskpane , but our new button isn't going to open a task pane; it's going to run
a custom function that you create in a later step. So, replace TODO5 with
ExecuteFunction , which is the action type for buttons that trigger custom
functions. The opening tag for the Action element should look like this:
XML
<Action xsi:type="ExecuteFunction">
7. The original Action element has child elements that specify a task pane ID and a
URL of the page that should be opened in the task pane. But an Action element of
the ExecuteFunction type has a single child element that names the function that
the control executes. You'll create that function in a later step, and it will be called
toggleProtection . So, replace TODO6 with the following markup.
XML
<FunctionName>toggleProtection</FunctionName>
The entire Control markup should now look like the following:
XML
XML
<bt:String id="ProtectionButtonLabel" DefaultValue="Toggle Worksheet
Protection" />
XML
2. Add the following function immediately after the action function. Note that we
specify an args parameter to the function and the very last line of the function
calls args.completed . This is a requirement for all add-in commands of type
ExecuteFunction. It signals the Office client application that the function has
finished and the UI can become responsive again.
JavaScript
await context.sync();
});
} catch (error) {
// Note: In a production add-in, you'd want to notify the user
through your add-in's UI.
console.error(error);
}
args.completed();
}
3. Add the following line immediately after the function to register it.
JavaScript
Office.actions.associate("toggleProtection", toggleProtection);
4. Within the toggleProtection function, replace TODO1 with the following code. This
code uses the worksheet object's protection property in a standard toggle pattern.
The TODO2 will be explained in the next section.
JavaScript
if (sheet.protection.protected) {
sheet.protection.unprotect();
} else {
sheet.protection.protect();
}
1. Queue a command to load (that is; fetch) the properties that your code needs to
read.
2. Call the context object's sync method to send the queued command to the
document for execution and return the requested information.
3. Because the sync method is asynchronous, ensure that it has completed before
your code calls the properties that were fetched.
These steps must be completed whenever your code needs to read information from the
Office document.
1. Within the toggleProtection function, replace TODO2 with the following code.
Note:
Every Excel object has a load method. You specify the properties of the
object that you want to read in the parameter as a string of comma-delimited
names. In this case, the property you need to read is a subproperty of the
protection property. You reference the subproperty almost exactly as you
would anywhere else in your code, with the exception that you use a forward
slash ('/') character instead of a "." character.
fetched from the document, it must come after the await operator ensures
sync has completed.
JavaScript
sheet.load('protection/protected');
await context.sync();
When you are done, the entire function should look like the following:
JavaScript
sheet.load('protection/protected');
await context.sync();
if (sheet.protection.protected) {
sheet.protection.unprotect();
} else {
sheet.protection.protect();
}
await context.sync();
});
} catch (error) {
// Note: In a production add-in, you'd want to notify the user
through your add-in's UI.
console.error(error);
}
args.completed();
}
2. Verify that you've saved all of the changes you've made to the project.
2. Clear the Office cache. This is necessary to completely clear the old version of the
add-in from the client application. Instructions for this process are in the article
Clear the Office cache.
3. If the local web server is already running, stop it by entering the following
command in the command prompt. This should close the node command window.
command line
npm stop
4. Because your manifest file has been updated, you must sideload your add-in again,
using the updated manifest file. Start the local web server and sideload your add-
in.
To test your add-in in Excel, run the following command in the root directory
of your project. This starts the local web server (if it's not already running)
and opens Excel with your add-in loaded.
command line
npm start
To test your add-in in Excel on the web, run the following command in the
root directory of your project. When you run this command, the local web
server starts. Replace "{url}" with the URL of an Excel document on your
OneDrive or a SharePoint library to which you have permissions.
7 Note
If you are developing on a Mac, enclose the {url} in single quotation
marks. Do not do this on Windows.
command line
https://contoso.sharepoint.com/:t:/g/EZGxP7ksiE5DuxvY638G798BpuhwluxCM
fF1WZQj3VYhYQ?e=F4QM1R
npm run start:web -- --document
https://1drv.ms/x/s!jkcH7spkM4EGgcZUgqthk4IK3NOypVw?e=Z6G1qp
npm run start:web -- --document https://contoso-my.sharepoint-
df.com/:t:/p/user/EQda453DNTpFnl1bFPhOVR0BwlrzetbXvnaRYii2lDr_oQ?
e=RSccmNP
5. On the Home tab in Excel, choose the Toggle Worksheet Protection button. Note
that most of the controls on the ribbon are disabled (and visually grayed-out) as
seen in the following screenshot.
6. Select a cell and try to edit its content. Excel displays an error message indicating
that the worksheet is protected.
7. Choose the Toggle Worksheet Protection button again, and the controls are
reenabled, and you can change cell values again.
Open a dialog
In this final step of the tutorial, you'll open a dialog in your add-in, pass a message from
the dialog process to the task pane process, and close the dialog. Office Add-in dialogs
are nonmodal: a user can continue to interact with both the document in the Office
application and with the host page in the task pane.
Create the dialog page
1. In the ./src folder that's located at the root of the project, create a new folder
named dialogs.
The page has an <input> field where the user will enter their name, and a
button that will send this name to the task pane where it will display.
The markup loads a script named popup.js that you will create in a later step.
HTML
<!DOCTYPE html>
<html>
<head lang="en">
<title>Dialog for My Office Add-in</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-
scale=1">
<script type="text/javascript"
src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js">
</script>
<script type="text/javascript" src="popup.js"></script>
</head>
<body style="display:flex;flex-direction:column;align-
items:center;justify-content:center">
<p class="ms-font-xl">ENTER YOUR NAME</p>
<input id="name-box" type="text"/><br/><br/>
<button id="ok-button" class="ms-Button">OK</button>
</body>
</html>
5. Add the following code to popup.js. Note the following about this code.
Every page that calls APIs in the Office.js library must first ensure that the
library is fully initialized. The best way to do that is to call the
Office.onReady() function. The call of Office.onReady() must run before any
calls to Office.js; hence the assignment is in a script file that is loaded by the
page, as it is in this case.
JavaScript
Office.onReady((info) => {
// TODO1: Assign handler to the OK button.
});
6. Replace TODO1 with the following code. You'll create the sendStringToParentPage
function in the next step.
JavaScript
document.getElementById("ok-button").onclick = () =>
tryCatch(sendStringToParentPage);
7. Replace TODO2 with the following code. The messageParent method passes its
parameter to the parent page, in this case, the page in the task pane. The
parameter must be a string, which includes anything that can be serialized as a
string, such as XML or JSON, or any type that can be cast to a string. This also adds
the same tryCatch method used in taskpane.js for error handling.
JavaScript
function sendStringToParentPage() {
const userName = document.getElementById("name-box").value;
Office.context.ui.messageParent(userName);
}
The popup.html file, and the popup.js file that it loads, run in an entirely separate
browser runtime process from the add-in's task pane. If popup.js was transpiled
into the same bundle.js file as the app.js file, then the add-in would have to load
two copies of the bundle.js file, which defeats the purpose of bundling. Therefore,
this add-in does not transpile the popup.js file at all.
1. Locate the entry object within the config object and add a new entry for popup .
JavaScript
popup: "./src/dialogs/popup.js"
After you've done this, the new entry object will look like this.
JavaScript
entry: {
polyfill: "@babel/polyfill",
taskpane: "./src/taskpane/taskpane.js",
commands: "./src/commands/commands.js",
popup: "./src/dialogs/popup.js"
},
2. Locate the plugins array within the config object and add the following object to
the end of that array.
JavaScript
new HtmlWebpackPlugin({
filename: "popup.html",
template: "./src/dialogs/popup.html",
chunks: ["polyfill", "popup"]
})
After you've done this, the new plugins array will look like this.
JavaScript
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
filename: "taskpane.html",
template: "./src/taskpane/taskpane.html",
chunks: ['polyfill', 'taskpane']
}),
new CopyWebpackPlugin([
{
to: "taskpane.css",
from: "./src/taskpane/taskpane.css"
}
]),
new HtmlWebpackPlugin({
filename: "commands.html",
template: "./src/commands/commands.html",
chunks: ["polyfill", "commands"]
}),
new HtmlWebpackPlugin({
filename: "popup.html",
template: "./src/dialogs/popup.html",
chunks: ["polyfill", "popup"]
})
],
3. If the local web server is running, stop it by entering the following command in the
command prompt. This should close the node command window.
command line
npm stop
command line
2. Locate the <button> element for the freeze-header button, and add the following
markup after that line.
HTML
3. The dialog will prompt the user to enter a name and pass the user's name to the
task pane. The task pane will display it in a label. Immediately after the button that
you just added, add the following markup.
HTML
<label id="user-name"></label><br/><br/>
5. Within the Office.onReady function call, locate the line that assigns a click handler
to the freeze-header button, and add the following code after that line. You'll
create the openDialog method in a later step.
JavaScript
document.getElementById("open-dialog").onclick = openDialog;
6. Add the following declaration to the end of the file. This variable is used to hold an
object in the parent page's execution context that acts as an intermediator to the
dialog page's execution context.
JavaScript
7. Add the following function to the end of the file (after the declaration of dialog ).
The important thing to notice about this code is what is not there: there is no call
of Excel.run . This is because the API to open a dialog is shared among all Office
applications, so it is part of the Office JavaScript Common API, not the Excel-
specific API.
JavaScript
function openDialog() {
// TODO1: Call the Office Common API that opens a dialog.
}
8. Replace TODO1 with the following code. Note:
The second parameter passes options. height and width are percentages of
the size of the Office application's window.
JavaScript
Office.context.ui.displayDialogAsync(
'https://localhost:3000/popup.html',
{height: 45, width: 55},
Process the message from the dialog and close the dialog
1. Within the openDialog function in the file ./src/taskpane/taskpane.js, replace
TODO2 with the following code. Note:
The callback is executed immediately after the dialog successfully opens and
before the user has taken any action in the dialog.
The processMessage function will be created in a later step. This handler will
process any values that are sent from the dialog page with calls of the
messageParent function.
JavaScript
function (result) {
dialog = result.value;
dialog.addEventHandler(Office.EventType.DialogMessageReceived,
processMessage);
}
JavaScript
function processMessage(arg) {
document.getElementById("user-name").innerHTML = arg.message;
dialog.close();
}
3. Verify that you've saved all of the changes you've made to the project.
To test your add-in in Excel, run the following command in the root directory
of your project. This starts the local web server (if it's not already running)
and opens Excel with your add-in loaded.
command line
npm start
To test your add-in in Excel on the web, run the following command in the
root directory of your project. When you run this command, the local web
server starts. Replace "{url}" with the URL of an Excel document on your
OneDrive or a SharePoint library to which you have permissions.
7 Note
command line
fF1WZQj3VYhYQ?e=F4QM1R
e=RSccmNP
2. If the add-in task pane isn't already open in Excel, go to the Home tab and choose
the Show Taskpane button on the ribbon to open it.
4. While the dialog is open, drag it and resize it. Note that you can interact with the
worksheet and press other buttons on the task pane, but you cannot launch a
second dialog from the same task pane page.
5. In the dialog, enter a name and choose the OK button. The name appears on the
task pane and the dialog closes.
section. The dialog stays open and you can change the name. You can close it
manually by pressing the X button in the upper right corner.
Next steps
In this tutorial, you've created an Excel task pane add-in that interacts with tables, charts,
worksheets, and dialogs in an Excel workbook. To learn more about building Excel add-
ins, continue to the following article.
See also
Office Add-ins platform overview
Develop Office Add-ins
Excel JavaScript object model in Office Add-ins
Office Add-ins code samples
Excel JavaScript API overview
Article • 05/02/2023
An Excel add-in interacts with objects in Excel by using the Office JavaScript API, which
includes two JavaScript object models:
Excel JavaScript API: These are the application-specific APIs for Excel. Introduced
with Office 2016, the Excel JavaScript API provides strongly-typed objects that you
can use to access worksheets, ranges, tables, charts, and more.
Common APIs: Introduced with Office 2013, the Common API can be used to
access features such as UI, dialogs, and client settings that are common across
multiple types of Office applications.
This section of the documentation focuses on the Excel JavaScript API, which you'll use
to develop the majority of functionality in add-ins that target Excel on the web or Excel
2016 or later. For information about the Common API, see Common JavaScript API
object model.
For hands-on experience using the Excel JavaScript API to access objects in Excel,
complete the Excel add-in tutorial.
Charts
Comments
Conditional formatting
Custom functions
Data validation
Data types
Events
PivotTables
Ranges and Cells
RangeAreas (Multiple ranges)
Shapes
Tables
Workbooks and Application-level APIs
Worksheets
For detailed information about the Excel JavaScript API object model, see the Excel
JavaScript API reference documentation.
See also
Excel add-ins documentation
Excel add-ins overview
Excel JavaScript API reference
Office client application and platform availability for Office Add-ins
Using the application-specific API model
excel package
Reference
Classes
Excel.AllowEditRange Represents an AllowEditRange object found in a worksheet. This
object works with worksheet protection properties. When
worksheet protection is enabled, an AllowEditRange object can
be used to allow editing of a specific range, while maintaining
protection on the rest of the worksheet.
Excel.BindingCollection Represents the collection of all the binding objects that are part
of the workbook.
Excel.ChartAreaFormat Encapsulates the format properties for the overall chart area.
Excel.ChartBinOptions Encapsulates the bin options for histogram charts and pareto
charts.
Excel.ChartBorder Represents the border formatting of a chart element.
Excel.ChartDataLabelFormat Encapsulates the format properties for the chart data labels.
Excel.ChartErrorBars This object represents the attributes for a chart's error bars.
Excel.ChartFont This object represents the font attributes (such as font name,
font size, and color) for a chart object.
Excel.ChartPlotArea This object represents the attributes for a chart plot area.
Excel.ChartPointsCollection A collection of all the chart points within a series inside a chart.
Excel.ChartTrendline This object represents the attributes for a chart trendline object.
Excel.ChartTrendlineLabel This object represents the attributes for a chart trendline label
object.
Excel.ChartTrendlineLabel Encapsulates the format properties for the chart trendline label.
Format
Excel.ConditionalDataBar Represents a conditional format for the negative side of the data
NegativeFormat bar.
Excel.ConditionalDataBar Represents a conditional format for the positive side of the data
PositiveFormat bar.
Excel.ConditionalRangeFont This object represents the font attributes (font style, color, etc.)
for an object.
Excel.DataConnection Represents a collection of all the data connections that are part
Collection of the workbook.
Excel.HeaderFooter
Excel.HeaderFooterGroup
Excel.LinkedDataType Represents a linked data type. A linked data type is a data type
connected to an online data source.
Excel.LinkedDataType Represents a collection of linked data types.
Collection
Excel.NamedItemCollection A collection of all the NamedItem objects that are part of the
workbook or worksheet, depending on how it was reached.
Excel.PageBreak
Excel.PageBreakCollection
Excel.PageLayout Represents layout and print settings that are not dependent on
any printer-specific implementation. These settings include
margins, orientation, page numbering, title rows, and print area.
Excel.PivotTableCollection Represents a collection of all the PivotTables that are part of the
workbook or worksheet.
Excel.RangeBorderCollection Represents the border objects that make up the range border.
Excel.RangeCollection
Excel.RangeFont This object represents the font attributes (font name, font size,
color, etc.) for an object.
Excel.RangeFormat A format object encapsulating the range's font, fill, borders,
alignment, and other properties.
Excel.ShapeFont Represents the font attributes, such as font name, font size, and
color, for a shape's TextRange object.
Excel.ShapeLineFormat Represents the line formatting for the shape object. For images
and geometric shapes, line formatting represents the border of
the shape.
Excel.SlicerItemCollection Represents a collection of all the slicer item objects in the slicer.
Excel.Table Represents an Excel table. To learn more about the table object
model, read Work with tables using the Excel JavaScript API.
Excel.TableCollection Represents a collection of all the tables that are part of the
workbook or worksheet, depending on how it was reached.
Excel.TableColumnCollection Represents a collection of all the columns that are part of the
table.
Note that unlike ranges or columns, which will adjust if new rows
or columns are added before them, a TableRow object represents
the physical location of the table row, but not the data. That is, if
the data is sorted or if new rows are added, a table row will
continue to point at the index for which it was created.
Excel.TableRowCollection Represents a collection of all the rows that are part of the table.
Note that unlike ranges or columns, which will adjust if new rows
or columns are added before them, a TableRow object represents
the physical location of the table row, but not the data. That is, if
the data is sorted or if new rows are added, a table row will
continue to point at the index for which it was created.
Excel.TableScopedCollection Represents a scoped collection of tables. For each table its top-
left corner is considered its anchor location, and the tables are
sorted top-to-bottom and then left-to-right.
Excel.WorksheetFreezePanes
Excel.BindingDataChanged Provides information about the binding that raised the data
EventArgs changed event.
Excel.CellValueAttribution The attribution attributes object represents the set of details that
Attributes can be used to describe where information came from, if the
information comes from a public source.
Excel.CellValueExtraProperties These extra properties may appear on a CellValue and provide
information about that CellValue , but the extra properties are
not part of the value in the cell.
Excel.CellValueProvider The provider attributes object represents the set of details used
Attributes in card view to provide specified branding information for a
CellValue type that supports provider attributes.
Excel.ChartActivatedEventArgs Provides information about the chart that raised the activated
event.
Excel.ChartAddedEventArgs Provides information about the chart that raised the added
event.
Excel.ChartDeactivatedEvent Provides information about the chart that raised the deactivated
Args event.
Excel.ChartDeletedEventArgs Provides information about the chart that raised the deleted
event.
Excel.CommentDetail A structure for the comment ID and IDs of its related replies.
Excel.CommentMention Represents the entity that is mentioned in comments.
Excel.DataValidationErrorAlert Represents the error alert properties for the data validation.
Excel.DataValidationPrompt Represents the user prompt properties for the data validation.
Excel.EmptyCellValue Represents the value of a cell that's empty and has no formulas
or data.
Excel.InsertWorksheetOptions The options that define which worksheets to insert and where in
the workbook the new worksheets will be inserted.
Excel.Interfaces.Application An interface for updating data on the Application object, for use
UpdateData in application.set({ ... }) .
Excel.Interfaces.Binding Represents the collection of all the binding objects that are part
CollectionLoadOptions of the workbook.
Excel.Interfaces.ChartArea Encapsulates the format properties for the overall chart area.
FormatLoadOptions
Excel.Interfaces.ChartAxes An interface for updating data on the ChartAxes object, for use
UpdateData in chartAxes.set({ ... }) .
Excel.Interfaces.ChartAxis An interface for updating data on the ChartAxis object, for use in
UpdateData chartAxis.set({ ... }) .
Excel.Interfaces.ChartBin Encapsulates the bin options for histogram charts and pareto
OptionsLoadOptions charts.
Excel.Interfaces.ChartBorder An interface for updating data on the ChartBorder object, for use
UpdateData in chartBorder.set({ ... }) .
Excel.Interfaces.ChartData Encapsulates the format properties for the chart data labels.
LabelFormatLoadOptions
Excel.Interfaces.ChartErrorBars This object represents the attributes for a chart's error bars.
LoadOptions
Excel.Interfaces.ChartFontLoad This object represents the font attributes (such as font name,
Options font size, and color) for a chart object.
Excel.Interfaces.ChartFont An interface for updating data on the ChartFont object, for use
UpdateData in chartFont.set({ ... }) .
Excel.Interfaces.ChartPlotArea This object represents the attributes for a chart plot area.
LoadOptions
Excel.Interfaces.ChartPoints A collection of all the chart points within a series inside a chart.
CollectionLoadOptions
Excel.Interfaces.ChartPoint An interface for updating data on the ChartPoint object, for use
UpdateData in chartPoint.set({ ... }) .
Excel.Interfaces.ChartTitle An interface for updating data on the ChartTitle object, for use in
UpdateData chartTitle.set({ ... }) .
Excel.Interfaces.ChartTrendline Encapsulates the format properties for the chart trendline label.
LabelFormatLoadOptions
Excel.Interfaces.ChartTrendline An interface for updating data on the ChartTrendlineLabelFormat
LabelFormatUpdateData object, for use in chartTrendlineLabelFormat.set({ ... }) .
Excel.Interfaces.ChartTrendline This object represents the attributes for a chart trendline label
LabelLoadOptions object.
Excel.Interfaces.ChartTrendline This object represents the attributes for a chart trendline object.
LoadOptions
Excel.Interfaces.ChartUpdate An interface for updating data on the Chart object, for use in
Data chart.set({ ... }) .
Excel.Interfaces.Comment An interface for updating data on the Comment object, for use
UpdateData in comment.set({ ... }) .
Excel.Interfaces.Conditional Represents a conditional format for the negative side of the data
DataBarNegativeFormatLoad bar.
Options
Excel.Interfaces.Conditional Represents a conditional format for the positive side of the data
DataBarPositiveFormatLoad bar.
Options
Excel.Interfaces.Conditional This object represents the font attributes (font style, color, etc.)
RangeFontLoadOptions for an object.
Excel.Interfaces.Conditional An interface for updating data on the ConditionalRangeFont
RangeFontUpdateData object, for use in conditionalRangeFont.set({ ... }) .
Excel.Interfaces.HeaderFooterGroupLoadOptions
Excel.Interfaces.HeaderFooterLoadOptions
Excel.Interfaces.LineUpdate An interface for updating data on the Line object, for use in
Data line.set({ ... }) .
Excel.Interfaces.LinkedData Represents a linked data type. A linked data type is a data type
TypeLoadOptions connected to an online data source.
Excel.Interfaces.NamedItem A collection of all the NamedItem objects that are part of the
CollectionLoadOptions workbook or worksheet, depending on how it was reached.
Excel.Interfaces.NamedItem An interface for updating data on the NamedItem object, for use
UpdateData in namedItem.set({ ... }) .
Excel.Interfaces.PageBreakCollectionLoadOptions
Excel.Interfaces.PageBreakLoadOptions
Excel.Interfaces.PageLayout Represents layout and print settings that are not dependent on
LoadOptions any printer-specific implementation. These settings include
margins, orientation, page numbering, title rows, and print area.
Excel.Interfaces.PageLayout An interface for updating data on the PageLayout object, for use
UpdateData in pageLayout.set({ ... }) .
Excel.Interfaces.PivotField An interface for updating data on the PivotField object, for use in
UpdateData pivotField.set({ ... }) .
Excel.Interfaces.PivotItem An interface for updating data on the PivotItem object, for use in
UpdateData pivotItem.set({ ... }) .
Excel.Interfaces.PivotLayout An interface for updating data on the PivotLayout object, for use
UpdateData in pivotLayout.set({ ... }) .
Excel.Interfaces.PivotTable Represents a collection of all the PivotTables that are part of the
CollectionLoadOptions workbook or worksheet.
Excel.Interfaces.PivotTable An interface for updating data on the PivotTable object, for use
UpdateData in pivotTable.set({ ... }) .
Excel.Interfaces.RangeAreas An interface for updating data on the RangeAreas object, for use
UpdateData in rangeAreas.set({ ... }) .
Excel.Interfaces.RangeBorder Represents the border objects that make up the range border.
CollectionLoadOptions
Excel.Interfaces.RangeCollectionLoadOptions
Excel.Interfaces.Range An interface for updating data on the RangeCollection object,
CollectionUpdateData for use in rangeCollection.set({ ... }) .
Excel.Interfaces.RangeFill An interface for updating data on the RangeFill object, for use in
UpdateData rangeFill.set({ ... }) .
Excel.Interfaces.RangeFont This object represents the font attributes (font name, font size,
LoadOptions color, etc.) for an object.
Excel.Interfaces.RangeFont An interface for updating data on the RangeFont object, for use
UpdateData in rangeFont.set({ ... }) .
Excel.Interfaces.RangeUpdate An interface for updating data on the Range object, for use in
Data range.set({ ... }) .
Excel.Interfaces.RangeView An interface for updating data on the RangeView object, for use
UpdateData in rangeView.set({ ... }) .
Excel.Interfaces.Runtime An interface for updating data on the Runtime object, for use in
UpdateData runtime.set({ ... }) .
Excel.Interfaces.SettingUpdate An interface for updating data on the Setting object, for use in
Data setting.set({ ... }) .
Excel.Interfaces.ShapeFill An interface for updating data on the ShapeFill object, for use in
UpdateData shapeFill.set({ ... }) .
Excel.Interfaces.ShapeFont Represents the font attributes, such as font name, font size, and
LoadOptions color, for a shape's TextRange object.
Excel.Interfaces.ShapeFont An interface for updating data on the ShapeFont object, for use
UpdateData in shapeFont.set({ ... }) .
Excel.Interfaces.ShapeLine Represents the line formatting for the shape object. For images
FormatLoadOptions and geometric shapes, line formatting represents the border of
the shape.
Excel.Interfaces.ShapeUpdate An interface for updating data on the Shape object, for use in
Data shape.set({ ... }) .
Excel.Interfaces.SlicerItem Represents a collection of all the slicer item objects in the slicer.
CollectionLoadOptions
Excel.Interfaces.SlicerItem An interface for updating data on the SlicerItem object, for use
UpdateData in slicerItem.set({ ... }) .
Excel.Interfaces.SlicerStyle An interface for updating data on the SlicerStyle object, for use
UpdateData in slicerStyle.set({ ... }) .
Excel.Interfaces.SlicerUpdate An interface for updating data on the Slicer object, for use in
Data slicer.set({ ... }) .
Excel.Interfaces.StyleUpdate An interface for updating data on the Style object, for use in
Data style.set({ ... }) .
Excel.Interfaces.Table Represents a collection of all the tables that are part of the
CollectionLoadOptions workbook or worksheet, depending on how it was reached.
Excel.Interfaces.TableLoad Represents an Excel table. To learn more about the table object
Options model, read Work with tables using the Excel JavaScript API.
Excel.Interfaces.TableRow Represents a collection of all the rows that are part of the table.
CollectionLoadOptions
Note that unlike ranges or columns, which will adjust if new rows
or columns are added before them, a TableRow object represents
the physical location of the table row, but not the data. That is, if
the data is sorted or if new rows are added, a table row will
continue to point at the index for which it was created.
Excel.Interfaces.TableRow An interface for updating data on the TableRow object, for use in
UpdateData tableRow.set({ ... }) .
Excel.Interfaces.TableStyle An interface for updating data on the TableStyle object, for use
UpdateData in tableStyle.set({ ... }) .
Excel.Interfaces.TableUpdate An interface for updating data on the Table object, for use in
Data table.set({ ... }) .
Excel.Interfaces.TextRange An interface for updating data on the TextRange object, for use
UpdateData in textRange.set({ ... }) .
Excel.Interfaces.Workbook An interface for updating data on the Workbook object, for use
UpdateData in workbook.set({ ... }) .
Excel.Interfaces.Worksheet An interface for updating data on the Worksheet object, for use
UpdateData in worksheet.set({ ... }) .
Excel.LinkedDataTypeAdded The argument that is passed to the event handler after a new
EventArgs linked data type is added to the workbook.
Excel.RunOptions
Excel.Session
Excel.SettingsChangedEvent Provides information about the setting that raised the settings
Args changed event
Excel.ShapeActivatedEvent Provides information about the shape that raised the activated
Args event.
Excel.ShowAsRule
Excel.TableAddedEventArgs Provides information about the table that raised the added
event.
Excel.TableChangedEventArgs Provides information about the table that raised the changed
event.
Excel.TableDeletedEventArgs Provides information about the table that raised the deleted
event.
Excel.TableFilteredEventArgs Provides information about the table that raised the filter
applied event.
Excel.TableSelectionChanged Provides information about the table that raised the selection
EventArgs changed event.
Excel.WorksheetAddedEvent Provides information about the worksheet that raised the added
Args event.
Excel.WorksheetFilteredEvent Provides information about the worksheet that raised the filter
Args applied event.
Excel.WorksheetRowSorted Provides information about the row-sorted event and its related
EventArgs worksheet.
Type Aliases
Excel.CardLayout Represents the layout of a card in card view.
Enums
Excel.AggregationFunction Aggregation function for the DataPivotHierarchy .
Excel.ArrowheadLength
Excel.ArrowheadStyle
Excel.ArrowheadWidth
Excel.BindingType
Excel.BorderIndex
Excel.BorderLineStyle
Excel.BorderWeight
Excel.BuiltInStyle
Excel.BuiltInTableStyle Represents a built-in table style.
Excel.CalculationMode
Excel.CalculationType
Excel.ChartAxisDisplayUnit
Excel.ChartAxisGroup
Excel.ChartAxisPosition
Excel.ChartAxisScaleType
Excel.ChartAxisTickLabelPosition
Excel.ChartAxisTickMark
Excel.ChartAxisTimeUnit Specifies the unit of time for chart axes and data series.
Excel.ChartAxisType
Excel.ChartBinType Specifies the bin type of a histogram chart or pareto chart series.
Excel.ChartColorScheme
Excel.ChartDataLabelPosition
Excel.ChartDisplayBlanksAs
Excel.ChartGradientStyleType Represents the gradient style type of a chart series. This is only
applicable for region map charts.
Excel.ChartLegendPosition
Excel.ChartLineStyle
Excel.ChartMapAreaLevel Represents the mapping level of a chart series. This only applies
to region map charts.
Excel.ChartMapLabelStrategy Represents the region level of a chart series layout. This only
applies to region map charts.
Excel.ChartMarkerStyle
Excel.ChartParentLabel Represents the parent label strategy of the chart series layout.
Strategy This only applies to treemap charts
Excel.ChartPlotAreaPosition
Excel.ChartPlotBy
Excel.ChartSplitType
Excel.ChartTickLabelAlignment
Excel.ChartTrendlineType
Excel.ChartType
Excel.ChartUnderlineStyle
Excel.ClearApplyTo
Excel.ConditionalFormatType
Excel.ConditionalRangeBorderIndex
Excel.ConditionalRangeBorderLineStyle
Excel.ConditionalRangeFontUnderlineStyle
Excel.ConnectorType
Excel.ContentType
Excel.DataChangeType
Excel.DataValidationAlertStyle Represents the data validation error alert style. The default is
Stop .
Excel.DeleteShiftDirection
Excel.DocumentPropertyItem
Excel.DocumentPropertyType
Excel.DynamicFilterCriteria
Excel.ErrorCodes
Excel.EventSource
Excel.EventTriggerSource
Excel.EventType
Excel.FillPattern
Excel.FilterDatetimeSpecificity
Excel.FilterOn
Excel.FilterOperator
Excel.GroupOption
Excel.HeaderFooterState
Excel.HorizontalAlignment
Excel.IconSet
Excel.ImageFittingMode
Excel.InsertShiftDirection
Excel.KeyboardDirection
Excel.LinkedDataTypeState
Excel.NamedItemScope
Excel.NamedItemType
Excel.PageOrientation
Excel.PaperType
Excel.PivotLayoutType
Excel.PrintComments
Excel.PrintErrorType
Excel.PrintMarginUnit
Excel.PrintOrder
Excel.ProtectionSelectionMode
Excel.RangeCopyType
Excel.RangeUnderlineStyle
Excel.RangeValueType
Excel.ReadingOrder
Excel.RibbonTab
Excel.RowHiddenChangeType
Excel.ShapeScaleFrom Specifies which part of the shape retains its position when the
shape is scaled.
Excel.ShapeTextHorizontal Specifies the horizontal alignment for the text frame in a shape.
Alignment
Excel.ShapeTextHorizontal Specifies the horizontal overflow for the text frame in a shape.
Overflow
Excel.ShapeTextReadingOrder Specifies the reading order for the text frame in a shape.
Excel.ShapeTextVertical Specifies the vertical alignment for the text frame in a shape.
Alignment
Excel.ShapeTextVertical Specifies the vertical overflow for the text frame in a shape.
Overflow
Excel.SheetVisibility
Excel.SortDataOption
Excel.SortMethod
Excel.SortOn
Excel.SortOrientation
Excel.SpecialCellType
Excel.SpecialCellValueType
Excel.SubtotalLocationType
Excel.VerticalAlignment
Excel.WorksheetPositionType
Functions
Excel.createWorkbook(base64) Creates and opens a new workbook. Optionally, the workbook
can be pre-populated with a base64-encoded .xlsx file. Note:
Macros can be a security risk. If this API is used to create a
workbook that includes a macro, the add-in user will be
prompted with a "Trust this add-in?" dialog in the Excel UI. The
user must select the "Trust add-in" button to proceed.
Excel.getDataCommon
Postprocess(response, call
Args)
Excel.postprocessBinding
Descriptor(response)
Excel.run(batch) Executes a batch script that performs actions on the Excel object
model, using a new RequestContext. When the promise is
resolved, any tracked objects that were automatically allocated
during execution will be released.
Excel.run(object, batch) Executes a batch script that performs actions on the Excel object
model, using the RequestContext of a previously-created API
object. When the promise is resolved, any tracked objects that
were automatically allocated during execution will be released.
Excel.run(objects, batch) Executes a batch script that performs actions on the Excel object
model, using the RequestContext of previously-created API
objects.
Excel.run(options, batch) Executes a batch script that performs actions on the Excel object
model, using the RequestContext of a previously-created API
object. When the promise is resolved, any tracked objects that
were automatically allocated during execution will be released.
Excel.run(context, batch) Executes a batch script that performs actions on the Excel object
model, using the RequestContext of a previously-created object.
When the promise is resolved, any tracked objects that were
automatically allocated during execution will be released.
Function Details
Excel.createWorkbook(base64)
Creates and opens a new workbook. Optionally, the workbook can be pre-populated
with a base64-encoded .xlsx file. Note: Macros can be a security risk. If this API is
used to create a workbook that includes a macro, the add-in user will be prompted
with a "Trust this add-in?" dialog in the Excel UI. The user must select the "Trust add-
in" button to proceed.
TypeScript
Parameters
base64 string
Returns
Promise<void>
Examples
TypeScript
Excel.getDataCommonPostprocess(response, callArgs)
TypeScript
Parameters
response any
callArgs any
Returns
any
Excel.postprocessBindingDescriptor(response)
TypeScript
Parameters
response any
Returns
any
Excel.run(batch)
Executes a batch script that performs actions on the Excel object model, using a new
RequestContext. When the promise is resolved, any tracked objects that were
automatically allocated during execution will be released.
TypeScript
Parameters
batch (context: Excel.RequestContext) => Promise<T>
A function that takes in a RequestContext and returns a promise (typically, just the
result of "context.sync()"). The context parameter facilitates requests to the Excel
application. Since the Office add-in and the Excel application run in two different
processes, the RequestContext is required to get access to the Excel object model
from the add-in.
Returns
Promise<T>
Excel.run(object, batch)
Executes a batch script that performs actions on the Excel object model, using the
RequestContext of a previously-created API object. When the promise is resolved,
any tracked objects that were automatically allocated during execution will be
released.
TypeScript
Parameters
object OfficeExtension.ClientObject
A previously-created API object. The batch will use the same RequestContext as the
passed-in object, which means that any changes applied to the object will be picked
up by "context.sync()".
Returns
Promise<T>
Excel.run(objects, batch)
Executes a batch script that performs actions on the Excel object model, using the
RequestContext of previously-created API objects.
TypeScript
Parameters
objects OfficeExtension.ClientObject[]
An array of previously-created API objects. The array will be validated to make sure
that all of the objects share the same context. The batch will use this shared
RequestContext, which means that any changes applied to these objects will be
picked up by "context.sync()".
Returns
Promise<T>
Excel.run(options, batch)
Executes a batch script that performs actions on the Excel object model, using the
RequestContext of a previously-created API object. When the promise is resolved,
any tracked objects that were automatically allocated during execution will be
released.
TypeScript
Parameters
options Excel.RunOptions
The additional options for this Excel.run which specify previous objects, whether to
delay the request for cell edit, session info, etc.
Returns
Promise<T>
Excel.run(context, batch)
Executes a batch script that performs actions on the Excel object model, using the
RequestContext of a previously-created object. When the promise is resolved, any
tracked objects that were automatically allocated during execution will be released.
TypeScript
Parameters
context OfficeExtension.ClientRequestContext
A previously-created object. The batch will use the same RequestContext as the
passed-in object, which means that any changes applied to the object will be picked
up by "context.sync()".
Returns
Promise<T>
Excel JavaScript object model in Office
Add-ins
Article • 03/21/2023
This article describes how to use the Excel JavaScript API to build add-ins for Excel 2016
or later. It introduces core concepts that are fundamental to using the API and provides
guidance for performing specific tasks such as reading or writing to a large range,
updating all cells in range, and more.
) Important
See Using the application-specific API model to learn about the asynchronous
nature of the Excel APIs and how they work with the workbook.
Excel JavaScript API: Introduced with Office 2016, the Excel JavaScript API provides
strongly-typed Excel objects that you can use to access worksheets, ranges, tables,
charts, and more.
Common API: Introduced with Office 2013, the Common API enables you to access
features such as UI, dialogs, and client settings that are common across multiple
types of Office applications. The limited functionality for Excel interaction in the
Common API has been replaced by the Excel JavaScript API.
While you'll likely use the Excel JavaScript API to develop the majority of functionality,
you'll also use objects in the Common API. For example:
Context: The Context object represents the runtime environment of the add-in and
provides access to key objects of the API. It consists of workbook configuration
details such as contentLanguage and officeTheme and also provides information
about the add-in's runtime environment such as host and platform . Additionally,
it provides the requirements.isSetSupported() method, which you can use to
check whether the specified requirement set is supported by the Excel application
where the add-in is running.
Document: The Document object provides the getFileAsync() method, which you
can use to download the Excel file where the add-in is running.
The following image illustrates when you might use the Excel JavaScript API or the
Common APIs.
7 Note
The Excel JavaScript API doesn't have a "Cell" object or class. Instead, the Excel
JavaScript API defines all Excel cells as Range objects. An individual cell in the Excel
UI translates to a Range object with one cell in the Excel JavaScript API. A single
Range object can also contain multiple contiguous cells. See Work with cells using
the Excel JavaScript API to learn more.
Ranges
A range is a group of contiguous cells in the workbook. Add-ins typically use A1-style
notation (e.g. B3 for the single cell in column B and row 3 or C2:F4 for the cells from
columns C through F and rows 2 through 4) to define ranges.
Ranges have three core properties: values , formulas , and format . These properties get
or set the cell values, formulas to be evaluated, and the visual formatting of the cells.
Range sample
The following sample shows how to create sales records. This function uses Range
objects to set the values, formulas, and formats.
JavaScript
For more information, see Set and get range values, text, or formulas using the Excel
JavaScript API.
Creating a table
Create tables by using data-filled ranges. Formatting and table controls (such as filters)
are automatically applied to the range.
The following sample creates a table using the ranges from the previous sample.
JavaScript
Using this sample code on the worksheet with the previous data creates the following
table.
For more information, see Work with tables using the Excel JavaScript API.
Creating a chart
Create charts to visualize the data in a range. The APIs support dozens of chart varieties,
each of which can be customized to suit your needs.
The following sample creates a simple column chart for three items and places it 100
pixels below the top of the worksheet.
JavaScript
Running this sample on the worksheet with the previous table creates the following
chart.
For more information, see Work with charts using the Excel JavaScript API.
See also
Build your first Excel add-in
Excel add-ins code samples
Excel JavaScript API performance optimization
Excel JavaScript API reference
Blank and null values in Excel add-ins
Article • 03/22/2022
null and empty strings have special implications in the Excel JavaScript APIs. They're
used to represent empty cells, no formatting, or default values. This section details the
use of null and empty string when getting and setting properties.
For example, to update the number format for only one cell within a range, and retain
the existing number format for all other cells in the range, specify the new number
format for the cell to update, and specify null for all other cells. The following code
snippet sets a new number format for the fourth cell in the range, and leaves the
number format unchanged for the first three cells in the range.
JavaScript
JavaScript
Likewise, the following code snippet is not valid, as null is not a valid value for the
color property.
JavaScript
If all cells in the range have the same font color, range.format.font.color specifies
that color.
If multiple font colors are present within the range, range.format.font.color is
null .
If you specify a blank value for the values property of a range, the content of the
range is cleared.
If you specify a blank value for the numberFormat property, the number format is
reset to General .
If you specify a blank value for the formula property and formulaLocale property,
the formula values are cleared.
JavaScript
JavaScript
This article explains how to call built-in Excel worksheet functions such as VLOOKUP and
SUM using the Excel JavaScript API. It also provides the full list of built-in Excel worksheet
7 Note
For information about how to create custom functions in Excel using the Excel
JavaScript API, see Create custom functions in Excel.
function to call and the input parameters that the function requires. The value property
of the FunctionResult object that's returned by a worksheet function contains the result
of the specified function. As this example shows, you must load the value property of
the FunctionResult object before you can read it. In this example, the result of the
function is simply being written to the console.
JavaScript
await context.sync();
console.log('Result of the function: ' + functionResult.value);
});
Tip
See the Supported worksheet functions section of this article for a list of functions
that can be called using the Excel JavaScript API.
Sample data
The following image shows a table in an Excel worksheet that contains sales data for
various types of tools over a three month period. Each number in the table represents
the number of units sold for a specific tool in a specific month. The examples that follow
will show how to apply built-in worksheet functions to this data.
JavaScript
await context.sync();
console.log(' Number of wrenches sold in November = ' +
unitSoldInNov.value);
});
As this example shows, when one or more function calls are nested within another
function call, you only need to load the final result that you subsequently want to read
(in this example, sumOfTwoLookups ). Any intermediate results (in this example, the result
of each VLOOKUP function) will be calculated and used to calculate the final result.
JavaScript
await context.sync();
console.log(' Number of wrenches sold in November and December = ' +
sumOfTwoLookups.value);
});
Function Description
ACCRINT function Returns the accrued interest for a security that pays periodic interest
ACCRINTM Returns the accrued interest for a security that pays interest at maturity
function
AVEDEV function Returns the average of the absolute deviations of data points from their
mean
AVERAGEA Returns the average of its arguments, including numbers, text, and logical
function values
AVERAGEIF Returns the average (arithmetic mean) of all the cells in a range that meet
function a given criteria
AVERAGEIFS Returns the average (arithmetic mean) of all cells that meet multiple
function criteria
BASE function Converts a number into a text representation with the given radix (base)
BETA.INV function Returns the inverse of the cumulative distribution function for a specified
beta distribution
BINOM.INV Returns the smallest value for which the cumulative binomial distribution
function is less than or equal to a criterion value
CEILING.MATH, Rounds a number up, to the nearest integer or to the nearest multiple of
ECMA_CEILING significance
functions
CODE function Returns a numeric code for the first character in a text string
Function Description
COMBIN function Returns the number of combinations for a given number of objects
COMBINA Returns the number of combinations with repetitions for a given number
function of items
CONFIDENCE.T Returns the confidence interval for a population mean, using a Student's t
function distribution
COUNT function Counts how many numbers are in the list of arguments
COUNTA function Counts how many values are in the list of arguments
COUNTIF function Counts the number of cells within a range that meet the given criteria
COUNTIFS Counts the number of cells within a range that meet multiple criteria
function
COUPDAYBS Returns the number of days from the beginning of the coupon period to
function the settlement date
COUPDAYS Returns the number of days in the coupon period that contains the
function settlement date
COUPDAYSNC Returns the number of days from the settlement date to the next coupon
function date
Function Description
COUPNCD Returns the next coupon date after the settlement date
function
COUPNUM Returns the number of coupons payable between the settlement date and
function maturity date
COUPPCD Returns the previous coupon date before the settlement date
function
CUMPRINC Returns the cumulative principal paid on a loan between two periods
function
DAYS360 function Calculates the number of days between two dates based on a 360-day
year
DB function Returns the depreciation of an asset for a specified period by using the
fixed-declining balance method
DDB function Returns the depreciation of an asset for a specified period by using the
double-declining balance method or some other method that you specify
DECIMAL function Converts a text representation of a number in a given base into a decimal
number
DGET function Extracts from a database a single record that matches the specified criteria
DMAX function Returns the maximum value from selected database entries
DMIN function Returns the minimum value from selected database entries
DOLLAR, USDOLLAR Converts a number to text, using the $ (dollar) currency format
functions
DOLLARFR Converts a dollar price, expressed as a decimal number, into a dollar price,
function expressed as a fraction
DPRODUCT Multiplies the values in a particular field of records that match the criteria
function in a database
DSTDEV function Estimates the standard deviation based on a sample of selected database
entries
DSTDEVP function Calculates the standard deviation based on the entire population of
selected database entries
DSUM function Adds the numbers in the field column of records in the database that
match the criteria
DURATION Returns the annual duration of a security with periodic interest payments
function
Dlet function Estimates variance based on a sample from selected database entries
DVARP function Calculates variance based on the entire population of selected database
entries
Function Description
EDATE function Returns the serial number of the date that is the indicated number of
months before or after the start date
EOMONTH Returns the serial number of the last day of the month before or after a
function specified number of months
ERFC.PRECISE Returns the complementary ERF function integrated between x and infinity
function
FLOOR.MATH Rounds a number down, to the nearest integer or to the nearest multiple
function of significance
FLOOR.PRECISE Rounds a number down to the nearest integer or to the nearest multiple
function of significance. Regardless of the sign of the number, the number is
rounded down.
FVSCHEDULE Returns the future value of an initial principal after applying a series of
function compound interest rates
GAUSS function Returns 0.5 less than the standard normal cumulative distribution
HLOOKUP Looks in the top row of an array and returns the value of the indicated cell
function
INTRATE function Returns the interest rate for a fully invested security
IPMT function Returns the interest payment for an investment for a given period
IRR function Returns the internal rate of return for a series of cash flows
ISERR function Returns TRUE if the value is any error value except #N/A
ISNA function Returns TRUE if the value is the #N/A error value
ISOWEEKNUM Returns the number of the ISO week number of the year for a given date
function
Function Description
ISPMT function Calculates the interest paid during a specific period of an investment
MAXA function Returns the maximum value in a list of arguments, including numbers,
text, and logical values
MDURATION Returns the Macauley modified duration for a security with an assumed
function par value of $100
MID, MIDB Returns a specific number of characters from a text string starting at the
functions position you specify
MINA function Returns the smallest value in a list of arguments, including numbers, text,
and logical values
MIRR function Returns the internal rate of return where positive and negative cash flows
are financed at different rates
NETWORKDAYS.INTL Returns the number of whole workdays between two dates using
function parameters to indicate which and how many days are weekend days
NOW function Returns the serial number of the current date and time
Function Description
NPV function Returns the net present value of an investment based on a series of
periodic cash flows and a discount rate
ODDFPRICE Returns the price per $100 face value of a security with an odd first period
function
ODDLPRICE Returns the price per $100 face value of a security with an odd last period
function
PERCENTILE.EXC Returns the k-th percentile of values in a range, where k is in the range
function 0..1, exclusive
PERCENTRANK.EXC Returns the rank of a value in a data set as a percentage (0..1, exclusive) of
function the data set
PERMUT function Returns the number of permutations for a given number of objects
PERMUTATIONA Returns the number of permutations for a given number of objects (with
function repetitions) that can be selected from the total objects
Function Description
PHI function Returns the value of the density function for a standard normal
distribution
PPMT function Returns the payment on the principal for an investment for a given period
PRICE function Returns the price per $100 face value of a security that pays periodic
interest
PRICEDISC Returns the price per $100 face value of a discounted security
function
PRICEMAT Returns the price per $100 face value of a security that pays interest at
function maturity
PROPER function Capitalizes the first letter in each word of a text value
QUARTILE.EXC Returns the quartile of the data set, based on percentile values from 0..1,
function exclusive
RECEIVED function Returns the amount received at maturity for a fully invested security
RRI function Returns an equivalent interest rate for the growth of an investment
SLN function Returns the straight-line depreciation of an asset for one period
STDEVA function Estimates standard deviation based on a sample, including numbers, text,
and logical values
STDEVPA function Calculates standard deviation based on the entire population, including
numbers, text, and logical values
SUMIFS function Adds the cells in a range that meet multiple criteria
SYD function Returns the sum-of-years' digits depreciation of an asset for a specified
period
T.DIST function Returns the Percentage Points (probability) for the Student t-distribution
T.DIST.2T function Returns the Percentage Points (probability) for the Student t-distribution
T.INV function Returns the t-value of the Student's t-distribution as a function of the
probability and the degrees of freedom
TBILLPRICE Returns the price per $100 face value for a Treasury bill
function
UNICHAR function Returns the Unicode character that is references by the given numeric
value
UNICODE function Returns the number (code point) that corresponds to the first character of
the text
VARA function Estimates variance based on a sample, including numbers, text, and logical
values
VARPA function Calculates variance based on the entire population, including numbers,
text, and logical values
Function Description
VDB function Returns the depreciation of an asset for a specified or partial period by
using a declining balance method
VLOOKUP Looks in the first column of an array and moves across the row to return
function the value of a cell
WEEKNUM Converts a serial number to a number representing where the week falls
function numerically with a year
WORKDAY Returns the serial number of the date before or after a specified number
function of workdays
WORKDAY.INTL Returns the serial number of the date before or after a specified number
function of workdays using parameters to indicate which and how many days are
weekend days
XIRR function Returns the internal rate of return for a schedule of cash flows that is not
necessarily periodic
XNPV function Returns the net present value for a schedule of cash flows that is not
necessarily periodic
YEARFRAC Returns the year fraction representing the number of whole days between
function start_date and end_date
YIELD function Returns the yield on a security that pays periodic interest
YIELDDISC Returns the annual yield for a discounted security; for example, a Treasury
function bill
YIELDMAT Returns the annual yield of a security that pays interest at maturity
function
See also
Excel JavaScript object model in Office Add-ins
Functions Class (JavaScript API for Excel)
Workbook Functions Object (JavaScript API for Excel)
Work with cells using the Excel
JavaScript API
Article • 05/02/2023
The Excel JavaScript API doesn't have a "Cell" object or class. Instead, all Excel cells are
Range objects. An individual cell in the Excel UI translates to a Range object with one cell
A Range object can also contain multiple, contiguous cells. Contiguous cells form an
unbroken rectangle (including single rows or columns). To learn about working with cells
that are not contiguous, see Work with discontiguous cells using the RangeAreas object.
For the complete list of properties and methods that the Range object supports, see
Range Object (JavaScript API for Excel).
See also
Excel JavaScript object model in Office Add-ins
Get a range using the Excel JavaScript API
Work with multiple ranges simultaneously in Excel add-ins
Work with charts using the Excel
JavaScript API
Article • 03/22/2022
This article provides code samples that show how to perform common tasks with charts
using the Excel JavaScript API. For the complete list of properties and methods that the
Chart and ChartCollection objects support, see Chart Object (JavaScript API for Excel)
Create a chart
The following code sample creates a chart in the worksheet named Sample. The chart is
a Line chart that is based upon data in the range A1:B13.
JavaScript
await context.sync();
});
JavaScript
await context.sync();
});
JavaScript
await context.sync();
});
JavaScript
await context.sync();
});
JavaScript
await context.sync();
});
JavaScript
await context.sync();
});
Add a trendline
The following code sample adds a moving average trendline to the first series in the first
chart in the worksheet named Sample. The trendline shows a moving average over 5
periods.
JavaScript
seriesCollection.getItemAt(0).trendlines.add("MovingAverage").movingAverageP
eriod = 5;
await context.sync();
});
JavaScript
await context.sync();
});
The following code sample shows how to add a data table to a chart and then format
that data table using the ChartDataTable and ChartDataTableFormat objects.
JavaScript
// This code sample adds a data table to a chart that already exists on the
worksheet,
// and then adjusts the display and format of that data table.
await Excel.run(async (context) => {
// Retrieve the chart on the "Sample" worksheet.
let chart =
context.workbook.worksheets.getItem("Sample").charts.getItemAt(0);
// Get the chart data table object and load its properties.
let chartDataTable = chart.getDataTableOrNullObject();
chartDataTable.load();
// Set the display properties of the chart data table.
chartDataTable.visible = true;
chartDataTable.showLegendKey = true;
chartDataTable.showHorizontalBorder = false;
chartDataTable.showVerticalBorder = true;
chartDataTable.showOutlineBorder = true;
// Retrieve the chart data table format object and set font and border
properties.
let chartDataTableFormat = chartDataTable.format;
chartDataTableFormat.font.color = "#B76E79";
chartDataTableFormat.font.name = "Comic Sans";
chartDataTableFormat.border.color = "blue";
await context.sync();
});
The following screenshot shows the data table that the preceding code sample creates.
JavaScript
console.log(imageAsString.value);
// Instead of logging, your add-in may use the base64-encoded string to
save the image as a file or insert it in HTML.
});
Chart.getImage takes three optional parameters: width, height, and the fitting mode.
TypeScript
These parameters determine the size of the image. Images are always proportionally
scaled. The width and height parameters put upper or lower bounds on the scaled
image. ImageFittingMode has three values with the following behaviors.
Fill : The image's minimum height or width is the specified height or width
(whichever is reached first when scaling the image). This is the default behavior
when no fitting mode is specified.
Fit : The image's maximum height or width is the specified height or width
(whichever is reached first when scaling the image).
FitAndCenter : The image's maximum height or width is the specified height or
width (whichever is reached first when scaling the image). The resulting image is
centered relative to the other dimension.
See also
Excel JavaScript object model in Office Add-ins
Coauthoring in Excel add-ins
Article • 03/22/2022
With coauthoring , multiple people can work together and edit the same Excel
workbook simultaneously. All coauthors of a workbook can see another coauthor's
changes as soon as that coauthor saves the workbook. To coauthor an Excel workbook,
the workbook must be stored in OneDrive, OneDrive for Business, or SharePoint Online.
) Important
In Excel for Microsoft 365, you will notice AutoSave in the upper-left corner. When
AutoSave is turned on, coauthors see your changes in real time. Consider the
impact of this behavior on the design of your Excel add-in. Users can turn off
AutoSave via the switch in the upper left of the Excel window.
Coauthoring overview
When you change a workbook's content, Excel automatically synchronizes those
changes across all coauthors. Coauthors can change the content of a workbook, but so
can code running within an Excel add-in. For example, when the following JavaScript
code runs in an Office Add-in, the value of a range is set to Contoso.
JavaScript
range.values = [['Contoso']];
After 'Contoso' synchronizes across all coauthors, any user or add-in running in the
same workbook will see the new value of the range.
Coauthoring only synchronizes the content within the shared workbook. Values copied
from the workbook to JavaScript variables in an Excel add-in are not synchronized. For
example, if your add-in stores the value of a cell (such as 'Contoso') in a JavaScript
variable, and then a coauthor changes the value of the cell to 'Example', after
synchronization all coauthors see 'Example' in the cell. However, the value of the
JavaScript variable is still set to 'Contoso'. Furthermore, when multiple coauthors use the
same add-in, each coauthor has their own copy of the variable, which is not
synchronized. When you use variables that use workbook content, be sure you check for
updated values in the workbook before you use the variable.
Use events to manage the in-memory state of
your add-in
Excel add-ins can read workbook content (from hidden worksheets and a setting object),
and then store it in data structures such as variables. After the original values are copied
into any of these data structures, coauthors can update the original workbook content.
This means that the copied values in the data structures are now out of sync with the
workbook content. When you build your add-ins, be sure to account for this separation
of workbook content and values stored in data structures.
For example, you might build a content add-in that displays custom visualizations. The
state of your custom visualizations might be saved in a hidden worksheet. When
coauthors use the same workbook, the following scenario can occur.
User A opens the document and the custom visualizations are shown in the
workbook. The custom visualizations read data from a hidden worksheet (for
example, the color of the visualizations is set to blue).
User B opens the same document, and starts modifying the custom visualizations.
User B sets the color of the custom visualizations to orange. Orange is saved to the
hidden worksheet.
User A's hidden worksheet is updated with the new value of orange.
User A's custom visualizations are still blue.
If you want User A's custom visualizations to respond to changes made by coauthors on
the hidden worksheet, use the BindingDataChanged event. This ensures that changes to
workbook content made by coauthors is reflected in the state of your add-in.
See also
About coauthoring in Excel (VBA)
How AutoSave impacts add-ins and macros (VBA)
Work with comments using the Excel
JavaScript API
Article • 08/30/2022
This article describes how to add, read, modify, and remove comments in a workbook
with the Excel JavaScript API. You can learn more about the comment feature from the
Insert comments and notes in Excel article.
In the Excel JavaScript API, a comment includes both the single initial comment and the
connected threaded discussion. It is tied to an individual cell. Anyone viewing the
workbook with sufficient permissions can reply to a comment. A Comment object stores
those replies as CommentReply objects. You should consider a comment to be a thread
and that a thread must have a special entry as the starting point.
Comment objects. Comments are also accessible at the Worksheet level. The samples in
this article work with comments at the workbook level, but they can be easily modified
to use the Worksheet.comments property.
Add comments
Use the CommentCollection.add method to add comments to a workbook. This method
takes up to three parameters:
cellAddress : The cell where the comment is added. This can either be a string or
JavaScript
7 Note
Comments added by an add-in are attributed to the current user of that add-in.
displayed in the order they are added. They are also attributed to the current user of the
add-in.
The following code sample adds a reply to the first comment in the workbook.
JavaScript
Edit comments
To edit a comment or comment reply, set its Comment.content property or
CommentReply.content property.
JavaScript
JavaScript
Delete comments
To delete a comment use the Comment.delete method. Deleting a comment also deletes
the replies associated with that comment.
JavaScript
JavaScript
JavaScript
Comment replies have a read-only resolved property. Its value is always equal to that of
the rest of the thread.
Comment metadata
Each comment contains metadata about its creation, such as the author and creation
date. Comments created by your add-in are considered to be authored by the current
user.
The following sample shows how to display the author's email, author's name, and
creation date of a comment at A2.
JavaScript
await Excel.run(async (context) => {
// Get the comment at cell A2 in the "MyWorksheet" worksheet.
let comment = context.workbook.comments.getItemByCell("MyWorksheet!A2");
console.log(`${comment.creationDate.toDateString()}:
${comment.authorName} (${comment.authorEmail})`);
});
The following sample shows how to display the author's email, author's name, and
creation date of the latest comment reply at A2.
JavaScript
Mentions
Mentions are used to tag colleagues in a comment. This sends them notifications with
your comment's content. Your add-in can create these mentions on your behalf.
7 Note
Currently, only the mention's exact name can be used as the text of the mention
link. Support for shortened versions of a name will be added later.
JavaScript
// This will tag the mention's name using the '@' syntax.
// They will be notified via email.
let commentBody = {
mentions: [mention],
richContent: '<at id="0">' + mention.name + "</at> - Can you take a
look?"
};
Comment events
Your add-in can listen for comment additions, changes, and deletions. Comment events
occur on the CommentCollection object. To listen for comment events, register the
onAdded , onChanged , or onDeleted comment event handler. When a comment event is
detected, use this event handler to retrieve data about the added, changed, or deleted
comment. The onChanged event also handles comment reply additions, changes, and
deletions.
Each comment event only triggers once when multiple additions, changes, or deletions
are performed at the same time. All the CommentAddedEventArgs,
CommentChangedEventArgs, and CommentDeletedEventArgs objects contain arrays of
comment IDs to map the event actions back to the comment collections.
See the Work with Events using the Excel JavaScript API article for additional information
about registering event handlers, handling events, and removing event handlers.
The following sample shows how to register the onAdded event handler and then use the
CommentAddedEventArgs object to retrieve the commentDetails array of the added
comment.
7 Note
JavaScript
await context.sync();
});
await context.sync();
// Print out the added comment's data.
console.log(`A comment was added. ID:
${event.commentDetails[0].commentId}. Comment
content:${addedComment.content}. Comment
author:${addedComment.authorName}`);
await context.sync();
});
}
The following sample shows how to register the onChanged event handler and then use
the CommentChangedEventArgs object to retrieve the commentDetails array of the changed
comment.
7 Note
JavaScript
await context.sync();
});
await context.sync();
The following sample shows how to register the onDeleted event handler and then use
the CommentDeletedEventArgs object to retrieve the commentDetails array of the deleted
comment.
7 Note
JavaScript
await context.sync();
});
See also
Excel JavaScript object model in Office Add-ins
Work with workbooks using the Excel JavaScript API
Work with Events using the Excel JavaScript API
Insert comments and notes in Excel
Overview of data types in Excel add-ins
Article • 03/09/2023
Data types organize complex data structures as objects. This includes formatted number
values, web images, and entities as entity cards.
The following screenshot highlights one of the primary features of data types: an entity
card. In this case, the entity card shows expanded information about the Tofu product
from a list of grocery store products.
7 Note
To start experimenting with data types right away, install Script Lab in Excel and
check out the Data types section in our Samples library. You can also explore the
Script Lab samples in our OfficeDev/office-js-snippets repository.
Prior to the data types addition, the Excel JavaScript API supported string, number,
boolean, and error data types. The Excel UI formatting layer is capable of adding
currency, date, and other types of formatting to cells that contain the four original data
types, but this formatting layer only controls the display of the original data types in the
Excel UI. The underlying number value is not changed, even when a cell in the Excel UI is
formatted as currency or a date. This gap between an underlying value and the
formatted display in the Excel UI can result in confusion and errors during add-in
calculations. The data types APIs are a solution to this gap.
Data types expand Excel JavaScript API support beyond the four original data types
(string, number, boolean, and error) to include web images, formatted number values,
entities, arrays within entities, and improved error data types as flexible data structures.
These types, which power many linked data types experiences, allow for precision and
simplicity during add-in calculations and extend the potential of Excel add-ins beyond a
2-dimensional grid.
Tip
Check out examples of linked data types, which are available to all Excel users, in
the following sample workbook: linked-data-types-sample-workbook.xlsx.
Resources
Explore data types with the following resources.
1. Learn data types basics in the Excel data types core concepts article.
2. Install Script Lab in Excel and explore the Data types section in our Samples library.
3. Learn how to extend Excel beyond a 2-dimensional grid with entity data types in
the Use cards with entity value data types article.
4. Try the Create and explore data types in Excel sample in our OfficeDev/Office-
Add-in-samples repository.
This article describes how to use the Excel JavaScript API to work with data types. It
introduces core concepts that are fundamental to data type development.
7 Note
Some cell values change based on a user's locale. The valuesAsJsonLocal property
offers localization support and is available on all the same objects as valuesAsJson .
Cell values
The valuesAsJson property returns a CellValue type alias, which is a union of the
following data types.
ArrayCellValue
BooleanCellValue
DoubleCellValue
EmptyCellValue
EntityCellValue
ErrorCellValue
FormattedNumberCellValue
LinkedEntityCellValue
ReferenceCellValue
StringCellValue
ValueTypeNotAvailableCellValue
WebImageCellValue
The CellValue type alias also returns the CellValueExtraProperties object, which is an
intersection with the rest of the *CellValue types. It's not a data type itself. The
properties of the CellValueExtraProperties object are used with all data types to
specify details related to overwriting cell values.
JSON schema
Each cell value type returned by valuesAsJson uses a JSON metadata schema designed
for that type. Along with additional properties unique to each data type, these JSON
metadata schemas all have the type , basicType , and basicValue properties in common.
The type defines the CellValueType of the data. The basicType is always read-only and
is used as a fallback when the data type isn't supported or is formatted incorrectly. The
basicValue matches the value that would be returned by the values property. The
In addition to the three fields that all data types share, the JSON metadata schema for
each *CellValue has properties available according to that type. For example, the
WebImageCellValue type includes the altText and attribution properties, while the
EntityCellValue type offers the properties and text fields.
The following sections show JSON code samples for the formatted number value, entity
value, and web image data types.
The following JSON code sample shows the complete schema of a formatted number
value. The myDate formatted number value in the code sample displays as 1/16/1990 in
the Excel UI. If the minimum compatibility requirements for the data types feature aren't
met, calculations use the basicValue in place of the formatted number.
TypeScript
Begin experimenting with formatted number values by opening Script Lab and checking
out the Data types: Formatted numbers snippet in our Samples library.
Entity values
An entity value is a container for data types, similar to an object in object-oriented
programming. Entities also support arrays as properties of an entity value. The
EntityCellValue object allows add-ins to define properties such as type , text , and
properties . The properties property enables the entity value to define and contain
The basicType and basicValue properties define how calculations read this entity data
type if the minimum compatibility requirements to use data types aren't met. In that
scenario, this entity data type displays as a #VALUE! error in the Excel UI.
The following JSON code sample shows the complete schema of an entity value that
contains text, an image, a date, and an additional text value.
TypeScript
Entity values also offer a layouts property that creates a card for the entity. The card
displays as a modal window in the Excel UI and can display additional information
contained within the entity value, beyond what's visible in the cell. To learn more, see
Use cards with entity value data types.
To explore entity data types, start by going to Script Lab in Excel and opening the Data
types: Create entity cards from data in a table snippet in our Samples library. The Data
types: Entity values with references and Data types: Entity value attribution
properties snippets offer a deeper look at entity features.
Linked entities
Linked entity values, or LinkedEntityCellValue objects, are a type of entity value. These
objects integrate data provided by an external service and can display this data as an
entity card, like regular entity values. The Stocks and Geography data types available
via the Excel UI are linked entity values.
The basicType and basicValue properties define how calculations read the web image
data type if the minimum compatibility requirements to use the data types feature
aren't met. In that scenario, this web image data type displays as a #VALUE! error in the
Excel UI.
The following JSON code sample shows the complete schema of a web image.
TypeScript
// This is an example of the complete JSON for a web image.
const myImage: Excel.WebImageCellValue = {
type: Excel.CellValueType.webImage,
address: "https://bit.ly/2YGOwtw",
basicType: Excel.RangeValueType.error, // A read-only property. Used as
a fallback in incompatible scenarios.
basicValue: "#VALUE!" // A read-only property. Used as a fallback in
incompatible scenarios.
};
Try out web image data types by opening Script Lab and selecting the Data types: Web
images snippet in our Samples library.
The following is a list of all the error objects with expanded support through data types.
BlockedErrorCellValue
BusyErrorCellValue
CalcErrorCellValue
ConnectErrorCellValue
Div0ErrorCellValue
FieldErrorCellValue
GettingDataErrorCellValue
NotAvailableErrorCellValue
NameErrorCellValue
NullErrorCellValue
NumErrorCellValue
RefErrorCellValue
SpillErrorCellValue
ValueErrorCellValue
Each of the error objects can access an enum through the errorSubType property, and
this enum contains additional data about the error. For example, the
BlockedErrorCellValue error object can access the BlockedErrorCellValueSubType enum.
The BlockedErrorCellValueSubType enum offers additional data about what caused the
error.
Learn more about the data types error objects by checking out the Data types: Set error
values snippet in our Script Lab Samples library.
Next steps
Learn how entity data types extend the potential of Excel add-ins beyond a 2-
dimensional grid with the Use cards with entity value data types article.
Use the Create and explore data types in Excel sample in our OfficeDev/Office-Add-
in-samples repository to experiment more deeply with data types by building and
sideloading an add-in that creates and edits data types in a workbook.
See also
Overview of data types in Excel add-ins
Use cards with entity value data types
Create and explore data types in Excel
Custom functions and data types
Excel JavaScript API reference
Use cards with entity value data types
Article • 03/09/2023
This article describes how to use the Excel JavaScript API to create card modal windows
in the Excel UI with entity value data types. These cards can display additional
information contained within an entity value, beyond what's already visible in a cell, such
as related images, product category information, and data attributions.
7 Note
This article expands on information described in the Excel data types core
concepts article. We recommend reading that article before learning about entity
cards.
An entity value, or EntityCellValue, is a container for data types and similar to an object
in object-oriented programming. This article shows how to use entity value card
properties, layout options, and data attribution functionality to create entity values that
display as cards.
The following screenshot shows an example of an open entity value card, in this case for
the Chef Anton's Gumbo Mix product from a list of grocery store products.
Card properties
The entity value properties property allows you to set customized information about
your data types. The properties key accepts nested data types. Each nested property, or
data type, must have a type and basicValue setting.
) Important
The nested properties data types are used in combination with the Card layout
values described in the subsequent article section. After defining a nested data type
in properties , it must be assigned in the layouts property to display on the card.
The following code snippet shows the JSON for an entity value with multiple data types
nested within properties .
7 Note
To experiment with this code snippet in a complete sample, open Script Lab in
Excel and select Data types: Create entity cards from data in a table in our
Samples library.
TypeScript
The following screenshot shows an entity value card that uses the preceding code
snippet. The screenshot shows the Product ID, Product Name, Image, Quantity Per
Unit, and Unit Price information from the preceding code snippet.
Property metadata
Entity properties have an optional propertyMetadata field that uses the
CellValuePropertyMetadata object and offers the properties attribution , excludeFrom ,
and sublabel . The following code snippet shows how to add a sublabel to the "Unit
Price" property from the preceding code snippet. In this case, the sublabel identifies
the currency type.
7 Note
The propertyMetadata field is only available on data types that are nested within
entity properties.
TypeScript
// This code snippet is an excerpt from the `properties` field of the
// preceding `EntityCellValue` snippet. "Unit Price" is a property of
// an entity value.
"Unit Price": {
type: Excel.CellValueType.formattedNumber,
basicValue: product.unitPrice,
numberFormat: "$* #,##0.00",
propertyMetadata: {
sublabel: "USD"
}
},
The following screenshot shows an entity value card that uses the preceding code
snippet, displaying the property metadata sublabel of USD next to the Unit Price
property.
Card layout
The entity value layouts property defines the appearance of the entity. Use layouts to
specify attributes such as an entity icon, card title, image for a card, and the number of
sections to display.
) Important
The nested layouts values are used in combination with the Card properties data
types described in the preceding article section. A nested data type must be
defined in properties before it can be assigned in layouts to display on the card.
The layouts property contains two direct subproperties, compact and card . The card
property specifies the appearance of a card when the entity card is open. The compact
property only defines the icon for an entity, and this icon only displays when the card is
in its compact, or unopened state. See the EntityCompactLayoutIcons enum for a full list
of available icons. The next code snippet shows how to display the shoppingBag icon.
Within the card property, use the CardLayoutStandardProperties object to define the
components of the card like title , subTitle , and sections .
The entity value JSON in the next code snippet shows a card layout with nested title
and mainImage objects, as well as three sections within the card. Note that the title
property "Product Name" has a corresponding data type in the preceding Card
properties article section. The mainImage property also has a corresponding "Image"
data type in the preceding section. The sections property takes a nested array and uses
the CardLayoutSectionStandardProperties object to define the appearance of each
section.
Within each card section you can specify elements like layout , title , and properties .
The layout key uses the CardLayoutListSection object and accepts the value "List" .
The properties key accepts an array of strings. Note that the properties values, such as
"Product ID" , have corresponding data types in the preceding Card properties article
section. Sections can also be collapsible and can be defined with boolean values as
collapsed or not collapsed when the entity card is opened in the Excel UI.
7 Note
To experiment with this code snippet in a complete sample, open Script Lab in
Excel and select Data types: Create entity cards from data in a table in our
Samples library.
TypeScript
The following screenshot shows an entity value card that uses the preceding code
snippets. In the screenshot, the shoppingBag icon displays alongside the product names
in the spreadsheet. In the entity card, the mainImage object displays at the top, followed
by the title object which uses the Product Name and is set to Chef Anton's Gumbo
Mix. The screenshot also shows sections . The Quantity and price section is collapsible
and contains Quantity Per Unit and Unit Price. The Additional information field is
collapsible and is collapsed when the card is opened.
7 Note
In the preceding screenshot, the branch icon displays alongside Condiments in the
Category section. See the Data types: Create entity cards from data in a table
sample to learn how to set nested icons like the Category section icon.
There is a known issue with nested icons in Excel on Mac. In that environment,
nested icons will always display as the generic icon, regardless of which icon is
selected with the EntityCompactLayoutIcons enum.
The data provider property displays an image in the lower left corner of the entity card.
It uses the logoSourceAddress to specify a source URL for the image. The
logoTargetAddress value defines the URL destination if the logo image is selected. The
description value displays as a tooltip when hovering over the logo. The description
value also displays as a plain text fallback if the logoSourceAddress is not defined or if
the source address for the image is broken.
The JSON in the following code snippet shows an entity value that uses the provider
property to specify a data provider attribution for the entity.
7 Note
To experiment with this code snippet in a complete sample, open Script Lab in
Excel and select Data types: Entity value attribution properties in our Samples
library.
TypeScript
The following screenshot shows an entity value card that uses the preceding code
snippet. The screenshot shows the data provider attribution in the lower left corner. In
this instance, the data provider is Microsoft and the Microsoft logo is displayed.
Next steps
Try out the Create and explore data types in Excel sample in our OfficeDev/Office-
Add-in-samples repository. This sample guides you through building and then
sideloading an add-in that creates and edits data types in a workbook.
See also
Overview of data types in Excel add-ins
Excel data types core concepts
Create and explore data types in Excel
Excel JavaScript API reference
Add data validation to Excel ranges
Article • 03/22/2022
The Excel JavaScript Library provides APIs to enable your add-in to add automatic data
validation to tables, columns, rows, and other ranges in a workbook. To understand the
concepts and the terminology of data validation, please see the following articles about
how users add data validation through the Excel UI.
rule — Defines what constitutes valid data for the range. See DataValidationRule.
errorAlert — Specifies whether an error pops up if the user enters invalid data,
and defines the alert text, title, and style; for example, information , warning , and
stop . See DataValidationErrorAlert.
prompt — Specifies whether a prompt appears when the user hovers over the
range and defines the prompt message. See DataValidationPrompt.
ignoreBlanks — Specifies whether the data validation rule applies to blank cells in
the range. Defaults to true .
type — A read-only identification of the validation type, such as WholeNumber,
Date, TextLength, etc. It is set indirectly when you set the rule property.
7 Note
Data validation added programmatically behaves just like manually added data
validation. In particular, note that data validation is triggered only if the user
directly enters a value into a cell or copies and pastes a cell from elsewhere in the
workbook and chooses the Values paste option. If the user copies a cell and does a
plain paste into a range with data validation, validation is not triggered.
Here is an example of creating a validation rule. Note the following about this code.
The operator is the binary operator greaterThan . Whenever you use a binary
operator, the value that the user tries to enter in the cell is the left-hand operand
and the value specified in formula1 is the right-hand operand. So this rule says
that only whole numbers that are greater than 0 are valid.
The formula1 is a hard-coded number. If you don't know at coding time what the
value should be, you can also use an Excel formula (as a string) for the value. For
example, "=A3" and "=SUM(A4,B5)" could also be values of formula1 .
JavaScript
range.dataValidation.rule = {
wholeNumber: {
formula1: 0,
operator: Excel.DataValidationOperator.greaterThan
}
};
await context.sync();
});
See BasicDataValidation for a list of the other binary operators.
There are also two ternary operators: between and notBetween . To use these, you must
specify the optional formula2 property. The formula1 and formula2 values are the
bounding operands. The value that the user tries to enter in the cell is the third
(evaluated) operand. The following is an example of using the "Between" operator.
JavaScript
range.dataValidation.rule = {
decimal: {
formula1: 0,
formula2: 100,
operator: Excel.DataValidationOperator.between
}
};
await context.sync();
});
The next two rule properties take a DateTimeDataValidation object as their value.
date
time
JavaScript
range.dataValidation.rule = {
date: {
formula1: "2022-04-01",
formula2: "2022-04-08",
operator: Excel.DataValidationOperator.between
}
};
await context.sync();
});
It assumes that there is a worksheet named "Names" and that the values in the
range "A1:A3" are names.
The source property specifies the list of valid values. The string argument refers to
a range containing the names. You can also assign a comma-delimited list; for
example: "Sue, Ricky, Liz".
The inCellDropDown property specifies whether a drop-down control will appear in
the cell when the user selects it. If set to true , then the drop-down appears with
the list of values from the source .
JavaScript
range.dataValidation.rule = {
list: {
inCellDropDown: true,
source: "=Names!$A$1:$A$3"
}
};
await context.sync();
})
is not contained in B2, it does not return a number. ISNUMBER() returns a boolean.
So the formula property says that valid data for the Comment column is data that
does not include the string in the Athlete Name column.
JavaScript
commentsRange.dataValidation.rule = {
custom: {
formula: "=NOT(ISNUMBER(SEARCH(A2,B2)))"
}
};
await context.sync();
});
The style property determines whether the user gets an informational alert, a
warning, or a "stop" alert. Only stop actually prevents the user from adding invalid
data. The pop-ups for warning and information have options that allow the user
enter the invalid data anyway.
The showAlert property defaults to true . This means that Excel will pop-up a
generic alert (of type stop ) unless you create a custom alert which either sets
showAlert to false or sets a custom message, title, and style. This code sets a
custom message and title.
JavaScript
range.dataValidation.errorAlert = {
message: "Sorry, only positive whole numbers are allowed",
showAlert: true, // The default is 'true'.
style: Excel.DataValidationAlertStyle.stop,
title: "Negative or Decimal Number Entered"
};
await context.sync();
});
JavaScript
range.dataValidation.prompt = {
message: "Please enter a positive whole number.",
showPrompt: true, // The default is 'false'.
title: "Positive Whole Numbers Only."
};
await context.sync();
});
JavaScript
myrange.dataValidation.clear()
It isn't necessary that the range you clear is exactly the same range as a range on which
you added data validation. If it isn't, only the overlapping cells, if any, of the two ranges
are cleared.
7 Note
Clearing data validation from a range will also clear any data validation that a user
has added manually to the range.
See also
Excel JavaScript object model in Office Add-ins
DataValidation Object (JavaScript API for Excel)
Range Object (JavaScript API for Excel)
Work with Events using the Excel
JavaScript API
Article • 05/19/2023
This article describes important concepts related to working with events in Excel and
provides code samples that show how to register event handlers, handle events, and
remove event handlers using the Excel JavaScript API.
Events in Excel
Each time certain types of changes occur in an Excel workbook, an event notification
fires. By using the Excel JavaScript API, you can register event handlers that allow your
add-in to automatically run a designated function when a specific event occurs. The
following events are currently supported.
onSelectionChanged Occurs when the active cell or selected Binding, Table, Workbook,
range is changed. Worksheet,
WorksheetCollection
Events in preview
7 Note
The following events are currently available only in public preview. To use this
feature, you must use the preview version of the Office JavaScript API library from
the Office.js content delivery network (CDN) . The type definition file for
TypeScript compilation and IntelliSense is found at the CDN and DefinitelyTyped .
You can install these types with npm install --save-dev @types/office-js-preview .
For more information on our upcoming APIs, please visit Excel JavaScript API
requirement sets.
Event triggers
Events within an Excel workbook can be triggered by:
User interaction via the Excel user interface (UI) that changes the workbook
Office Add-in (JavaScript) code that changes the workbook
VBA add-in (macro) code that changes the workbook
Any change that complies with default behavior of Excel will trigger the corresponding
event(s) in a workbook.
U Caution
When an object to which events are registered is deleted (e.g., a table with an
onChanged event registered), the event handler no longer triggers but remains in
memory until the add-in or Excel session refreshes or closes.
JavaScript
await context.sync();
console.log("Event handler successfully registered for onChanged event
in the worksheet.");
}).catch(errorHandlerFunction);
Handle an event
As shown in the previous example, when you register an event handler, you indicate the
function that should run when the specified event occurs. You can design that function
to perform whatever actions your scenario requires. The following code sample shows
an event handler function that simply writes information about the event to the console.
JavaScript
JavaScript
let eventResult;
await context.sync();
console.log("Event handler successfully registered for
onSelectionChanged event in the worksheet.");
});
}
eventResult = null;
console.log("Event handler successfully removed.");
});
}
Events are enabled and disabled at the runtime level. The enableEvents property
determines if events are fired and their handlers are activated.
The following code sample shows how to toggle events on and off.
JavaScript
await context.sync();
});
See also
Excel JavaScript object model in Office Add-ins
Performance optimization using the
Excel JavaScript API
Article • 03/09/2023
There are multiple ways that you can perform common tasks with the Excel JavaScript
API. You'll find significant performance differences between various approaches. This
article provides guidance and code samples to show you how to perform common tasks
efficiently using Excel JavaScript API.
) Important
See the Application Object reference documentation for information about how to use
the suspendApiCalculationUntilNextSync() API to suspend and reactivate calculations in
a very convenient way. The following code demonstrates how to suspend calculation
temporarily.
JavaScript
rangeToSet = sheet.getRange("A1:C1");
rangeToSet.values = [[1, 2, "=SUM(A1:B1)"]];
rangeToGet = sheet.getRange("A1:C1");
rangeToGet.load("values");
await context.sync();
// Range value should be [1, 2, 3] now
console.log(rangeToGet.values);
// Suspending recalculation
app.suspendApiCalculationUntilNextSync();
rangeToSet = sheet.getRange("A1:B1");
rangeToSet.values = [[10, 20]];
rangeToGet = sheet.getRange("A1:C1");
rangeToGet.load("values");
app.load("calculationMode");
await context.sync();
// Range value should be [10, 20, 3] when we load the property, because
calculation is suspended at that point
console.log(rangeToGet.values);
// Calculation mode should still be "Automatic" even with suspend
recalculation
console.log(app.calculationMode);
rangeToGet.load("values");
await context.sync();
// Range value should be [10, 20, 30] when we load the property, because
calculation is resumed after last sync
console.log(rangeToGet.values);
});
Please note that only formula calculations are suspended. Any altered references are still
rebuilt. For example, renaming a worksheet still updates any references in formulas to
that worksheet.
7 Note
you are trying to write data into an existing table, write the data into a range object via
table.getDataBodyRange() , and the table will expand automatically.
JavaScript
You can conveniently convert a Table object to a Range object by using the
Table.convertToRange() method.
JavaScript
// DO NOT USE THIS CODE SAMPLE. This sample shows a poor performance
strategy.
async function run() {
await Excel.run(async (context) => {
let ranges = [];
// This sample retrieves the worksheet every time the loop runs, which
is bad for performance.
for (let i = 0; i < 7500; i++) {
let rangeByIndex =
context.workbook.worksheets.getActiveWorksheet().getRangeByIndexes(i, 1, 1,
1);
}
await context.sync();
});
}
The following code sample shows logic similar to the preceding code sample, but with
an improved performance strategy. The value
context.workbook.worksheets.getActiveWorksheet() is retrieved before the for loop,
because this value doesn't need to be retrieved each time the for loop runs. Only
values that change within the context of a loop should be retrieved within that loop.
JavaScript
One way to create fewer range objects is to split each range array into multiple arrays,
and then process each new array with a loop and a new context.sync() call.
) Important
Only use this strategy if you've first determined that you're exceeding the payload
request size limit. Using multiple loops can reduce the size of each payload request
to avoid exceeding the 5MB limit, but using multiple loops and multiple
context.sync() calls also negatively impacts performance.
The following code sample attempts to process a large array of ranges in a single loop
and then a single context.sync() call. Processing too many range values in one
context.sync() call causes the payload request size to exceed the 5MB limit.
JavaScript
The following code sample shows logic similar to the preceding code sample, but with a
strategy that avoids exceeding the 5MB payload request size limit. In the following code
sample, the ranges are processed in two separate loops, and each loop is followed by a
context.sync() call.
JavaScript
// This code sample shows a strategy for reducing payload request size.
// However, using multiple loops and `context.sync()` calls negatively
impacts performance.
// Only use this strategy if you've determined that you're exceeding the
payload request limit.
async function run() {
await Excel.run(async (context) => {
let worksheet = context.workbook.worksheets.getActiveWorksheet();
// Split the ranges into two loops, rows 1-5000 and then 5001-10000.
for (let row = 1; row < 5000; row++) {
let range = worksheet.getRangeByIndexes(row, 1, 1, 1);
range.values = [["1"]];
}
// Sync after each loop.
await context.sync();
The following code sample shows how to create an array, set the values of that array in a
for loop, and then pass the array values to a range outside the loop.
JavaScript
See also
Excel JavaScript object model in Office Add-ins
Error handling with the application-specific JavaScript APIs
Resource limits and performance optimization for Office Add-ins
Worksheet Functions Object (JavaScript API for Excel)
Work with PivotTables using the Excel
JavaScript API
Article • 03/22/2022
PivotTables streamline larger data sets. They allow the quick manipulation of grouped
data. The Excel JavaScript API lets your add-in create PivotTables and interact with their
components. This article describes how PivotTables are represented by the Office
JavaScript API and provides code samples for key scenarios.
If you are unfamiliar with the functionality of PivotTables, consider exploring them as an
end user. See Create a PivotTable to analyze worksheet data for a good primer on
these tools.
) Important
PivotTables created with OLAP are not currently supported. There is also no support
for Power Pivot.
Object model
The PivotTable is the central object for PivotTables in the Office JavaScript API.
Let's look at how these relationships apply to some example data. The following data
describes fruit sales from various farms. It will be the example throughout this article.
This fruit farm sales data will be used to make a PivotTable. Each column, such as Types,
is a PivotHierarchy . The Types hierarchy contains the Types field. The Types field
contains the items Apple, Kiwi, Lemon, Lime, and Orange.
Hierarchies
PivotTables are organized based on four hierarchy categories: row, column, data, and
filter.
The farm data shown earlier has five hierarchies: Farms, Type, Classification, Crates Sold
at Farm, and Crates Sold Wholesale. Each hierarchy can only exist in one of the four
categories. If Type is added to column hierarchies, it cannot also be in the row, data, or
filter hierarchies. If Type is subsequently added to row hierarchies, it is removed from
the column hierarchies. This behavior is the same whether hierarchy assignment is done
through the Excel UI or the Excel JavaScript APIs.
Row and column hierarchies define how data will be grouped. For example, a row
hierarchy of Farms will group together all the data sets from the same farm. The choice
between row and column hierarchy defines the orientation of the PivotTable.
Data hierarchies are the values to be aggregated based on the row and column
hierarchies. A PivotTable with a row hierarchy of Farms and a data hierarchy of Crates
Sold Wholesale shows the sum total (by default) of all the different fruits for each farm.
Filter hierarchies include or exclude data from the pivot based on values within that
filtered type. A filter hierarchy of Classification with the type Organic selected only
shows data for organic fruit.
Here is the farm data again, alongside a PivotTable. The PivotTable is using Farm and
Type as the row hierarchies, Crates Sold at Farm and Crates Sold Wholesale as the data
hierarchies (with the default aggregation function of sum), and Classification as a filter
hierarchy (with Organic selected).
This PivotTable could be generated through the JavaScript API or through the Excel UI.
Both options allow for further manipulation through add-ins.
Create a PivotTable
PivotTables need a name, source, and destination. The source can be a range address or
table name (passed as a Range , string , or Table type). The destination is a range
address (given as either a Range or string ). The following samples show various
PivotTable creation techniques.
await context.sync();
});
await context.sync();
});
await context.sync();
});
JavaScript
Adding the Farm column pivots all the sales around each farm. Adding the Type and
Classification rows further breaks down the data based on what fruit was sold and
whether it was organic or not.
JavaScript
pivotTable.rowHierarchies.add(pivotTable.hierarchies.getItem("Type"));
pivotTable.rowHierarchies.add(pivotTable.hierarchies.getItem("Classification
"));
pivotTable.columnHierarchies.add(pivotTable.hierarchies.getItem("Farm"));
await context.sync();
});
JavaScript
pivotTable.rowHierarchies.add(pivotTable.hierarchies.getItem("Classification
"));
await context.sync();
});
In the example, both Farm and Type are rows, with the crate sales as the data.
JavaScript
// "Crates Sold at Farm" and "Crates Sold Wholesale" are the hierarchies
// that will have their data aggregated (summed in this case).
pivotTable.dataHierarchies.add(pivotTable.hierarchies.getItem("Crates
Sold at Farm"));
pivotTable.dataHierarchies.add(pivotTable.hierarchies.getItem("Crates
Sold Wholesale"));
await context.sync();
});
The following diagram shows which layout function calls correspond to which ranges of
the PivotTable.
provided by the layout to get data collected and aggregated by the PivotTable. In
particular, use PivotLayout.getDataBodyRange to access the data produced by the
PivotTable.
The following code demonstrates how to get the last row of the PivotTable data by
going through the layout (the Grand Total of both the Sum of Crates Sold at Farm and
Sum of Crates Sold Wholesale columns in the earlier example). Those values are then
summed together for a final total, which is displayed in cell E30 (outside of the
PivotTable).
JavaScript
// Get the totals for each data hierarchy from the layout.
let range = pivotTable.layout.getDataBodyRange();
let grandTotalRange = range.getLastRow();
grandTotalRange.load("address");
await context.sync();
// Sum the totals from the PivotTable data hierarchies and place them in
a new range, outside of the PivotTable.
let masterTotalRange =
context.workbook.worksheets.getActiveWorksheet().getRange("E30");
masterTotalRange.formulas = [["=SUM(" + grandTotalRange.address + ")"]];
await context.sync();
});
Layout types
PivotTables have three layout styles: Compact, Outline, and Tabular. We've seen the
compact style in the previous examples.
The following examples use the outline and tabular styles, respectively. The code sample
shows how to cycle between the different layouts.
Outline layout
Tabular layout
PivotLayout type switch code sample
JavaScript
await context.sync();
});
Other PivotLayout functions
By default, PivotTables adjust row and column sizes as needed. This is done when the
PivotTable is refreshed. PivotLayout.autoFormat specifies that behavior. Any row or
column size changes made by your add-in persist when autoFormat is false .
Additionally, the default settings of a PivotTable keep any custom formatting in the
PivotTable (such as fills and font changes). Set PivotLayout.preserveFormatting to false
to apply the default format when refreshed.
A PivotLayout also controls header and total row settings, how empty data cells are
displayed, and alt text options. The PivotLayout reference provides a complete list of
these features.
The following code sample makes empty data cells display the string "--" , formats the
body range to a consistent horizontal alignment, and ensures that the formatting
changes remain even after the PivotTable is refreshed.
JavaScript
// Set a default value for an empty cell in the PivotTable. This doesn't
include cells left blank by the layout.
pivotLayout.emptyCellText = "--";
// Ensure that the format settings persist, even after the PivotTable is
refreshed and recalculated.
pivotLayout.preserveFormatting = true;
await context.sync();
});
Delete a PivotTable
PivotTables are deleted by using their name.
JavaScript
await Excel.run(async (context) => {
context.workbook.worksheets.getItem("Pivot").pivotTables.getItem("Farm
Sales").delete();
await context.sync();
});
Filter a PivotTable
The primary method for filtering PivotTable data is with PivotFilters. Slicers offer an
alternate, less flexible filtering method.
PivotFilters filter data based on a PivotTable's four hierarchy categories (filters, columns,
rows, and values). There are four types of PivotFilters, allowing calendar date-based
filtering, string parsing, number comparison, and filtering based on a custom input.
Slicers can be applied to both PivotTables and regular Excel tables. When applied to a
PivotTable, slicers function like a PivotManualFilter and allow filtering based on a custom
input. Unlike PivotFilters, slicers have an Excel UI component . With the Slicer class,
you create this UI component, manage filtering, and control its visual appearance.
Types of PivotFilters
Create a PivotFilter
To filter PivotTable data with a Pivot*Filter (such as a PivotDateFilter ), apply the filter
to a PivotField. The following four code samples show how to use each of the four types
of PivotFilters.
PivotDateFilter
The first code sample applies a PivotDateFilter to the Date Updated PivotField, hiding
any data prior to 2020-08-01.
) Important
JavaScript
7 Note
The following three code snippets only display filter-specific excerpts, instead of full
Excel.run calls.
PivotLabelFilter
The second code snippet demonstrates how to apply a PivotLabelFilter to the Type
PivotField, using the LabelFilterCondition.beginsWith property to exclude labels that
start with the letter L.
JavaScript
// Filter out any types that start with "L" ("Lemons" and "Limes" in
this case).
let filter: Excel.PivotLabelFilter = {
condition: Excel.LabelFilterCondition.beginsWith,
substring: "L",
exclusive: true
};
PivotManualFilter
The third code snippet applies a manual filter with PivotManualFilter to the the
Classification field, filtering out data that doesn't include the classification Organic.
JavaScript
To compare numbers, use a value filter with PivotValueFilter, as shown in the final code
snippet. The PivotValueFilter compares the data in the Farm PivotField to the data in
the Crates Sold Wholesale PivotField, including only farms whose sum of crates sold
exceeds the value 500.
JavaScript
// Filter to only include rows with more than 500 wholesale crates sold.
let filter: Excel.PivotValueFilter = {
condition: Excel.ValueFilterCondition.greaterThan,
comparator: 500,
value: "Sum of Crates Sold Wholesale"
};
Remove PivotFilters
JavaScript
7 Note
The techniques described in this section focus on how to use slicers connected to
PivotTables. The same techniques also apply to using slicers connected to tables.
Create a slicer
You can create a slicer in a workbook or worksheet by using the Workbook.slicers.add
method or Worksheet.slicers.add method. Doing so adds a slicer to the SlicerCollection
of the specified Workbook or Worksheet object. The SlicerCollection.add method has
three parameters:
slicerSource : The data source on which the new slicer is based. It can be a
Table .
sourceField : The field in the data source by which to filter. It can be a PivotField ,
slicerDestination : The worksheet where the new slicer will be created. It can be a
The following code sample adds a new slicer to the Pivot worksheet. The slicer's source
is the Farm Sales PivotTable and filters using the Type data. The slicer is also named
Fruit Slicer for future reference.
JavaScript
The slicer filters the PivotTable with items from the sourceField . The
Slicer.selectItems method sets the items that remain in the slicer. These items are
passed to the method as a string[] , representing the keys of the items. Any rows
containing those items remain in the PivotTable's aggregation. Subsequent calls to
selectItems set the list to the keys specified in those calls.
7 Note
The following code sample shows three items being selected for the slicer: Lemon, Lime,
and Orange.
JavaScript
JavaScript
You add-in can adjust a slicer's display settings through Slicer properties. The
following code sample sets the style to SlicerStyleLight6, sets the text at the top of the
slicer to Fruit Types, places the slicer at the position (395, 15) on the drawing layer, and
sets the slicer's size to 135x150 pixels.
JavaScript
Delete a slicer
To delete a slicer, call the Slicer.delete method. The following code sample deletes the
first slicer from the current worksheet.
JavaScript
The currently supported aggregation function types are Sum , Count , Average , Max , Min ,
Product , CountNumbers , StandardDeviation , StandardDeviationP , Variance , VarianceP ,
and Automatic (the default).
The following code samples changes the aggregation to be averages of the data.
JavaScript
// Change the aggregation from the default sum to an average of all the
values in the hierarchy.
pivotTable.dataHierarchies.items[0].summarizeBy =
Excel.AggregationFunction.average;
pivotTable.dataHierarchies.items[1].summarizeBy =
Excel.AggregationFunction.average;
await context.sync();
});
calculation : The type of relative calculation to apply to the data hierarchy (the
default is none ).
baseField : The PivotField in the hierarchy containing the base data before the
based on the calculation type. Not all calculations require this field.
The following example sets the calculation on the Sum of Crates Sold at Farm data
hierarchy to be a percentage of the column total. We still want the granularity to extend
to the fruit type level, so we'll use the Type row hierarchy and its underlying field. The
example also has Farm as the first row hierarchy, so the farm total entries display the
percentage each farm is responsible for producing as well.
JavaScript
farmDataHierarchy.load("showAs");
await context.sync();
// Show the crates of each fruit type sold at the farm as a percentage
of the column's total.
let farmShowAs = farmDataHierarchy.showAs;
farmShowAs.calculation = Excel.ShowAsCalculation.percentOfColumnTotal;
farmShowAs.baseField =
pivotTable.rowHierarchies.getItem("Type").fields.getItem("Type");
farmDataHierarchy.showAs = farmShowAs;
farmDataHierarchy.name = "Percentage of Total Farm Sales";
});
The previous example set the calculation to the column, relative to the field of an
individual row hierarchy. When the calculation relates to an individual item, use the
baseItem property.
The following example shows the differenceFrom calculation. It displays the difference
of the farm crate sales data hierarchy entries relative to those of A Farms. The baseField
is Farm, so we see the differences between the other farms, as well as breakdowns for
each type of like fruit (Type is also a row hierarchy in this example).
JavaScript
farmDataHierarchy.load("showAs");
await context.sync();
// Show the difference between crate sales of the "A Farms" and the
other farms.
// This difference is both aggregated and shown for individual fruit
types (where applicable).
let farmShowAs = farmDataHierarchy.showAs;
farmShowAs.calculation = Excel.ShowAsCalculation.differenceFrom;
farmShowAs.baseField =
pivotTable.rowHierarchies.getItem("Farm").fields.getItem("Farm");
farmShowAs.baseItem =
pivotTable.rowHierarchies.getItem("Farm").fields.getItem("Farm").items.getIt
em("A Farms");
farmDataHierarchy.showAs = farmShowAs;
farmDataHierarchy.name = "Difference from A Farms";
});
JavaScript
See also
Excel JavaScript object model in Office Add-ins
Excel JavaScript API Reference
Get a range using the Excel JavaScript
API
Article • 05/02/2023
This article provides examples that show different ways to get a range within a
worksheet using the Excel JavaScript API. For the complete list of properties and
methods that the Range object supports, see Excel.Range class.
7 Note
The Excel JavaScript API doesn't have a "Cell" object or class. Instead, the Excel
JavaScript API defines all Excel cells as Range objects. An individual cell in the Excel
UI translates to a Range object with one cell in the Excel JavaScript API. A single
Range object can also contain multiple contiguous cells. See Work with cells using
JavaScript
JavaScript
await Excel.run(async (context) => {
let sheet = context.workbook.worksheets.getItem("Sample");
JavaScript
JavaScript
See also
Excel JavaScript object model in Office Add-ins
Work with cells using the Excel JavaScript API
Insert a range using the Excel JavaScript API
Insert a range of cells using the Excel
JavaScript API
Article • 05/02/2023
This article provides a code sample that inserts a range of cells with the Excel JavaScript
API. For the complete list of properties and methods that the Range object supports, see
the Excel.Range class.
7 Note
The Excel JavaScript API doesn't have a "Cell" object or class. Instead, the Excel
JavaScript API defines all Excel cells as Range objects. An individual cell in the Excel
UI translates to a Range object with one cell in the Excel JavaScript API. A single
Range object can also contain multiple contiguous cells. See Work with cells using
JavaScript
range.insert(Excel.InsertShiftDirection.down);
await context.sync();
});
See also
Excel JavaScript object model in Office Add-ins
Work with cells using the Excel JavaScript API
Clear or delete a ranges using the Excel JavaScript API
Clear or delete ranges using the Excel
JavaScript API
Article • 05/02/2023
This article provides code samples that clear and delete ranges with the Excel JavaScript
API. For the complete list of properties and methods supported by the Range object, see
Excel.Range class.
7 Note
The Excel JavaScript API doesn't have a "Cell" object or class. Instead, the Excel
JavaScript API defines all Excel cells as Range objects. An individual cell in the Excel
UI translates to a Range object with one cell in the Excel JavaScript API. A single
Range object can also contain multiple contiguous cells. See Work with cells using
JavaScript
range.clear();
await context.sync();
});
JavaScript
range.delete(Excel.DeleteShiftDirection.up);
await context.sync();
});
This article provides code samples that set and get the selected range with the Excel
JavaScript API. For the complete list of properties and methods that the Range object
supports, see Excel.Range class.
7 Note
The Excel JavaScript API doesn't have a "Cell" object or class. Instead, the Excel
JavaScript API defines all Excel cells as Range objects. An individual cell in the Excel
UI translates to a Range object with one cell in the Excel JavaScript API. A single
Range object can also contain multiple contiguous cells. See Work with cells using
JavaScript
range.select();
await context.sync();
});
JavaScript
await context.sync();
In the following screenshot, the used range is the table with values in each cell, C5:F12.
The empty cells outside this table are outside the used range.
Select the cell at the edge of the current used range
The following code sample shows how use the Range.getRangeEdge method to select the
cell at the furthest edge of the current used range, in the direction up. This action
matches the result of using the Ctrl+Up arrow key keyboard shortcut while a range is
selected.
JavaScript
await context.sync();
});
The following screenshot shows the same table as the preceding screenshot, with data
in the range C5:F12. Inside this table, the range D5 is selected. This selection is after
state, after running the Range.getRangeEdge method to select the cell at the edge of the
used range in the up direction.
JavaScript
// Get all the cells from the currently selected range to the bottom-
most edge of the used range.
// This method acts like the Ctrl+Shift+Down arrow key keyboard shortcut
while a range is selected.
let extendedRange = range.getExtendedRange(
direction,
activeCell
);
extendedRange.select();
await context.sync();
});
Before selecting all the cells from the current range to the edge of
the used range
The following screenshot shows a used range and a selected range within the used
range. The used range is a table with data at C5:F12. Inside this table, the range D8:E9 is
selected. This selection is the before state, prior to running the Range.getExtendedRange
method.
After selecting all the cells from the current range to the edge of
the used range
The following screenshot shows the same table as the preceding screenshot, with data
in the range C5:F12. Inside this table, the range D8:E12 is selected. This selection is after
state, after running the Range.getExtendedRange method to select all the cells from the
current range to the edge of the used range in the down direction.
See also
Excel JavaScript object model in Office Add-ins
Work with cells using the Excel JavaScript API
Set and get range values, text, or formulas using the Excel JavaScript API
Set range format using the Excel JavaScript API
Set and get range values, text, or
formulas using the Excel JavaScript API
Article • 05/02/2023
This article provides code samples that set and get range values, text, or formulas with
the Excel JavaScript API. For the complete list of properties and methods that the Range
object supports, see Excel.Range class.
7 Note
The Excel JavaScript API doesn't have a "Cell" object or class. Instead, the Excel
JavaScript API defines all Excel cells as Range objects. An individual cell in the Excel
UI translates to a Range object with one cell in the Excel JavaScript API. A single
Range object can also contain multiple contiguous cells. See Work with cells using
JavaScript
await context.sync();
});
JavaScript
let data = [
["Potato Chips", 10, 1.80],
];
await context.sync();
});
JavaScript
await context.sync();
});
JavaScript
let data = [
["=C3 * D3"],
["=C4 * D4"],
["=C5 * D5"],
["=SUM(E3:E5)"]
];
await context.sync();
});
JavaScript
[
[
"Product",
"Qty",
"Unit Price",
"Total Price"
],
[
"Almonds",
2,
7.5,
15
],
[
"Coffee",
1,
34.5,
34.5
],
[
"Chocolate",
5,
9.56,
47.8
],
[
"",
"",
"",
97.3
]
]
JavaScript
JSON
[
[
"Product",
"Qty",
"Unit Price",
"Total Price"
],
[
"Almonds",
"2",
"7.5",
"15"
],
[
"Coffee",
"1",
"34.5",
"34.5"
],
[
"Chocolate",
"5",
"9.56",
"47.8"
],
[
"",
"",
"",
"97.3"
]
]
JavaScript
JSON
[
[
"Product",
"Qty",
"Unit Price",
"Total Price"
],
[
"Almonds",
2,
7.5,
"=C3 * D3"
],
[
"Coffee",
1,
34.5,
"=C4 * D4"
],
[
"Chocolate",
5,
9.56,
"=C5 * D5"
],
[
"",
"",
"",
"=SUM(E3:E5)"
]
]
See also
Excel JavaScript object model in Office Add-ins
Work with cells using the Excel JavaScript API
Set and get ranges using the Excel JavaScript API
Set range format using the Excel JavaScript API
Set range format using the Excel
JavaScript API
Article • 05/02/2023
This article provides code samples that set font color, fill color, and number format for
cells in a range with the Excel JavaScript API. For the complete list of properties and
methods that the Range object supports, see Excel.Range class.
7 Note
The Excel JavaScript API doesn't have a "Cell" object or class. Instead, the Excel
JavaScript API defines all Excel cells as Range objects. An individual cell in the Excel
UI translates to a Range object with one cell in the Excel JavaScript API. A single
Range object can also contain multiple contiguous cells. See Work with cells using
JavaScript
await context.sync();
});
Data in range before font color and fill color are set
Data in range after font color and fill color are set
JavaScript
let formats = [
["0.00", "0.00"],
["0.00", "0.00"],
["0.00", "0.00"]
];
await context.sync();
});
The Excel JavaScript Library provides APIs to apply conditional formatting to data ranges
in your worksheets. This functionality makes large sets of data easy to visually parse. The
formatting also dynamically updates based on changes within the range.
7 Note
This article covers conditional formatting in the context of Excel JavaScript add-ins.
The following articles provide detailed information about the full conditional
formatting capabilities within Excel.
cellValue
colorScale
custom
dataBar
iconSet
preset
textComparison
topBottom
7 Note
Cell value
Cell value conditional formatting applies a user-defined format based on the results of
one or two formulas in the ConditionalCellValueRule. The operator property is a
ConditionalCellValueOperator defining how the resulting expressions relate to the
formatting.
The following example shows red font coloring applied to any value in the range less
than zero.
JavaScript
await context.sync();
});
Color scale
Color scale conditional formatting applies a color gradient across the data range. The
criteria property on the ColorScaleConditionalFormat defines three
ConditionalColorScaleCriterion: minimum , maximum , and, optionally, midpoint . Each of the
criterion scale points have three properties:
The following example shows a range being colored blue to yellow to red. Note that
minimum and maximum are the lowest and highest values respectively and use null
formulas. midpoint is using the percentage type with a formula of "=50" so the
yellowest cell is the mean value.
JavaScript
// Color the backgrounds of the cells from blue to yellow to red based
on value.
const criteria = {
minimum: {
formula: null,
type: Excel.ConditionalFormatColorCriterionType.lowestValue,
color: "blue"
},
midpoint: {
formula: "50",
type: Excel.ConditionalFormatColorCriterionType.percent,
color: "yellow"
},
maximum: {
formula: null,
type: Excel.ConditionalFormatColorCriterionType.highestValue,
color: "red"
}
};
conditionalFormat.colorScale.criteria = criteria;
await context.sync();
});
Custom
Custom conditional formatting applies a user-defined format to the cells based on a
formula of arbitrary complexity. The ConditionalFormatRule object lets you define the
formula in different notations:
The following example colors the fonts green of cells with higher values than the cell to
their left.
JavaScript
// If a cell has a higher value than the one to its left, set that
cell's font to green.
conditionalFormat.custom.rule.formula =
'=IF(B8>INDIRECT("RC[-1]",0),TRUE)';
conditionalFormat.custom.format.font.color = "green";
await context.sync();
});
Data bar
Data bar conditional formatting adds data bars to the cells. By default, the minimum and
maximum values in the Range form the bounds and proportional sizes of the data bars.
The DataBarConditionalFormat object has several properties to control the bar's
appearance.
The following example formats the range with data bars filling left-to-right.
JavaScript
Icon set
Icon set conditional formatting uses Excel Icons to highlight cells. The criteria property
is an array of ConditionalIconCriterion, which define the symbol to be inserted and the
condition under which it is inserted. This array is automatically prepopulated with
criterion elements with default properties. Individual properties cannot be overwritten.
Instead, the whole criteria object must be replaced.
The following example shows a three-triangle icon set applied across the range.
JavaScript
/*
With a "three*" icon set style, such as "threeTriangles", the third
element in the criteria array (criteria[2]) defines the "top" icon;
e.g., a green triangle. The second (criteria[1]) defines the
"middle"
icon, The first (criteria[0]) defines the "low" icon, but it can
often
be left empty as this method does below, because every cell that
does not match the other two criteria always gets the low icon.
*/
iconSetCF.criteria = [
{},
{
type: Excel.ConditionalFormatIconRuleType.number,
operator:
Excel.ConditionalIconCriterionOperator.greaterThanOrEqual,
formula: "=700"
},
{
type: Excel.ConditionalFormatIconRuleType.number,
operator:
Excel.ConditionalIconCriterionOperator.greaterThanOrEqual,
formula: "=1000"
}
];
await context.sync();
});
Preset criteria
Preset conditional formatting applies a user-defined format to the range based on a
selected standard rule. These rules are defined by the ConditionalFormatPresetCriterion
in the ConditionalPresetCriteriaRule.
The following example colors the font white wherever a cell's value is at least one
standard deviation above the range's average.
JavaScript
// Color every cell's font white that is one standard deviation above
average relative to the range.
conditionalFormat.preset.format.font.color = "white";
conditionalFormat.preset.rule = {
criterion:
Excel.ConditionalFormatPresetCriterion.oneStdDevAboveAverage
};
await context.sync();
});
Text comparison
Text comparison conditional formatting uses string comparisons as the condition. The
rule property is a ConditionalTextComparisonRule defining a string to compare with
the cell and an operator to specify the type of comparison.
The following example formats the font color red when a cell's text contains "Delayed".
JavaScript
await context.sync();
});
Top/bottom
Top/bottom conditional formatting applies a format to the highest or lowest values in a
range. The rule property, which is of type ConditionalTopBottomRule, sets whether the
condition is based on the highest or lowest, as well as whether the evaluation is ranked
or percentage-based.
The following example applies a green highlight to the highest value cell in the range.
JavaScript
// For the highest valued cell in the range, make the background green.
conditionalFormat.topBottom.format.fill.color = "green"
conditionalFormat.topBottom.rule = { rank: 1, type: "TopItems"}
await context.sync();
});
changeRuleToCellValue
changeRuleToColorScale
changeRuleToContainsText
changeRuleToCustom
changeRuleToDataBar
changeRuleToIconSet
changeRuleToPresetCriteria
changeRuleToTopBottom
The following example shows how to use the changeRuleToPresetCriteria method from
the preceding list to change an existing conditional format rule to the preset criteria rule
type.
7 Note
The specified range must have an existing conditional format rule to use the
change methods. If the specified range has no conditional format rule, the change
methods don't apply a new rule.
JavaScript
await context.sync();
});
The following example shows a conflicting font color choice between the two formats.
Negative numbers will get a bold font, but NOT a red font, because priority goes to the
format that gives them a blue font.
JavaScript
// Set low numbers to bold, dark red font and assign priority 1.
const presetFormat = temperatureDataRange.conditionalFormats
.add(Excel.ConditionalFormatType.presetCriteria);
presetFormat.preset.format.font.color = "red";
presetFormat.preset.format.font.bold = true;
presetFormat.preset.rule = { criterion:
Excel.ConditionalFormatPresetCriterion.oneStdDevBelowAverage };
presetFormat.priority = 1;
// Set negative numbers to blue font with green background and set
priority 0.
const cellValueFormat = temperatureDataRange.conditionalFormats
.add(Excel.ConditionalFormatType.cellValue);
cellValueFormat.cellValue.format.font.color = "blue";
cellValueFormat.cellValue.format.fill.color = "lightgreen";
cellValueFormat.cellValue.rule = { formula1: "=0", operator: "LessThan"
};
cellValueFormat.priority = 0;
await context.sync();
});
The following example shows two conditional formats being added to a range. Negative
numbers will have a blue font with a light green background, regardless of whether the
other format condition is true.
JavaScript
// Set low numbers to bold, dark red font and assign priority 1.
const presetFormat = temperatureDataRange.conditionalFormats
.add(Excel.ConditionalFormatType.presetCriteria);
presetFormat.preset.format.font.color = "red";
presetFormat.preset.format.font.bold = true;
presetFormat.preset.rule = { criterion:
Excel.ConditionalFormatPresetCriterion.oneStdDevBelowAverage };
presetFormat.priority = 1;
await context.sync();
});
To remove all the conditional formatting rules from a specific range, or an entire
worksheet, use the clearAll method of the ConditionalFormatCollection object.
The following sample shows how to remove all conditional formatting from a worksheet
with the clearAll method.
JavaScript
await context.sync();
});
See also
Excel JavaScript object model in Office Add-ins
ConditionalFormat Object (JavaScript API for Excel)
Add, change, or clear conditional formats
Use formulas with conditional formatting
Read or write to an unbounded range
using the Excel JavaScript API
Article • 05/02/2023
This article describes how to read and write to an unbounded range with the Excel
JavaScript API. For the complete list of properties and methods that the Range object
supports, see Excel.Range class.
An unbounded range address is a range address that specifies either entire columns or
entire rows. For example:
A:F
1:4
values , text , numberFormat , and formula . Other properties of the range, such as
address and cellCount , will contain valid values for the unbounded range.
JavaScript
This article describes how to handle reading and writing to large ranges with the Excel
JavaScript API.
For details on the system limitations, see the "Excel add-ins" section of Resource limits
and performance optimization for Office Add-ins.
See also
Excel JavaScript object model in Office Add-ins
Work with cells using the Excel JavaScript API
Read or write to an unbounded range using the Excel JavaScript API
Work with multiple ranges simultaneously in Excel add-ins
Find a string within a range using the
Excel JavaScript API
Article • 05/02/2023
This article provides a code sample that finds a string within a range using the Excel
JavaScript API. For the complete list of properties and methods that the Range object
supports, see Excel.Range class.
7 Note
The Excel JavaScript API doesn't have a "Cell" object or class. Instead, the Excel
JavaScript API defines all Excel cells as Range objects. An individual cell in the Excel
UI translates to a Range object with one cell in the Excel JavaScript API. A single
Range object can also contain multiple contiguous cells. See Work with cells using
The following code sample finds the first cell with a value equal to the string Food and
logs its address to the console. Note that find throws an ItemNotFound error if the
specified string doesn't exist in the range. If you expect that the specified string may not
exist in the range, use the findOrNullObject method instead, so your code gracefully
handles that scenario.
JavaScript
foundRange.load("address");
await context.sync();
console.log(foundRange.address);
});
When the find method is called on a range representing a single cell, the entire
worksheet is searched. The search begins at that cell and goes in the direction specified
by SearchCriteria.searchDirection , wrapping around the ends of the worksheet if
needed.
See also
Excel JavaScript object model in Office Add-ins
Work with cells using the Excel JavaScript API
Find special cells within a range using the Excel JavaScript API
Work with dates using the Excel
JavaScript API and the Moment-MSDate
plug-in
Article • 05/02/2023
This article provides code samples that show how to work with dates using the Excel
JavaScript API and the Moment-MSDate plug-in . For the complete list of properties
and methods that the Range object supports, see the Excel.Range class.
7 Note
The Excel JavaScript API doesn't have a "Cell" object or class. Instead, the Excel
JavaScript API defines all Excel cells as Range objects. An individual cell in the Excel
UI translates to a Range object with one cell in the Excel JavaScript API. A single
Range object can also contain multiple contiguous cells. See Work with cells using
The following code shows how to set the range at B4 to a moment's timestamp.
JavaScript
The following code sample demonstrates a similar technique to get the date back out of
the cell and convert it to a Moment or other format.
JavaScript
await context.sync();
Your add-in has to format the ranges to display the dates in a more human-readable
form. For example, "[$-409]m/d/yy h:mm AM/PM;@" displays "12/3/18 3:57 PM". For more
information about date and time number formats, see "Guidelines for date and time
formats" in the Review guidelines for customizing a number format article.
See also
Work with cells using the Excel JavaScript API
Excel JavaScript object model in Office Add-ins
Work with multiple ranges simultaneously in Excel add-ins
Find special cells within a range using
the Excel JavaScript API
Article • 05/02/2023
This article provides code samples that find special cells within a range using the Excel
JavaScript API. For the complete list of properties and methods that the Range object
supports, see Excel.Range class.
TypeScript
TypeScript
The following code sample uses the getSpecialCells method to find all the cells with
formulas. About this code, note:
It limits the part of the sheet that needs to be searched by first calling
Worksheet.getUsedRange and calling getSpecialCells for only that range.
The getSpecialCells method returns a RangeAreas object, so all of the cells with
formulas will be colored pink even if they are not all contiguous.
JavaScript
If no cells with the targeted characteristic exist in the range, getSpecialCells throws an
ItemNotFound error. This diverts the flow of control to a catch block, if there is one. If
there isn't a catch block, the error halts the method.
If you expect that cells with the targeted characteristic should always exist, you'll likely
want your code to throw an error if those cells aren't there. If it's a valid scenario that
there aren't any matching cells, your code should check for this possibility and handle it
gracefully without throwing an error. You can achieve this behavior with the
getSpecialCellsOrNullObject method and its returned isNullObject property. The
following code sample uses this pattern. About this code, note:
JavaScript
if (formulaRanges.isNullObject) {
console.log("No cells have formulas");
}
else {
formulaRanges.format.fill.color = "pink";
}
await context.sync();
});
For simplicity, all other code samples in this article use the getSpecialCells method
instead of getSpecialCellsOrNullObject .
7 Note
Excel.SpecialCellType.constants .
Excel.SpecialCellValueType.errors
Excel.SpecialCellValueType.numbers
Excel.SpecialCellValueType.text
The following code sample finds special cells that are numerical constants and colors
those cells pink. About this code, note:
It only highlights cells that have a literal number value. It won't highlight cells that
have a formula (even if the result is a number) or a boolean, text, or error state
cells.
To test the code, be sure the worksheet has some cells with literal number values,
some with other kinds of literal values, and some with formulas.
JavaScript
await context.sync();
});
types returned. The following code sample colors all cells with formulas that produce
number or boolean value.
JavaScript
await context.sync();
});
See also
Excel JavaScript object model in Office Add-ins
Work with cells using the Excel JavaScript API
Find a string using the Excel JavaScript API
Work with multiple ranges simultaneously in Excel add-ins
Cut, copy, and paste ranges using the
Excel JavaScript API
Article • 05/02/2023
This article provides code samples that cut, copy, and paste ranges using the Excel
JavaScript API. For the complete list of properties and methods that the Range object
supports, see Excel.Range class.
7 Note
The Excel JavaScript API doesn't have a "Cell" object or class. Instead, the Excel
JavaScript API defines all Excel cells as Range objects. An individual cell in the Excel
UI translates to a Range object with one cell in the Excel JavaScript API. A single
Range object can also contain multiple contiguous cells. See Work with cells using
The following code sample copies the data from A1:E1 into the range starting at G1
(which ends up pasting into G1:K1).
JavaScript
TypeScript
skipBlanks sets whether blank cells are copied into the destination. When true,
copyFrom skips blank cells in the source range. Skipped cells will not overwrite the
existing data of their corresponding cells in the destination range. The default is false.
transpose determines whether or not the data is transposed, meaning its rows and
columns are switched, into the source location. A transposed range is flipped along the
main diagonal, so rows 1, 2, and 3 will become columns A, B, and C.
The following code sample and images demonstrate this behavior in a simple scenario.
JavaScript
The following code sample moves a range with the Range.moveTo method. Note that if
the destination range is smaller than the source, it will be expanded to encompass the
source content.
JavaScript
// Move the cells "A1:E1" to "G1" (which fills the range "G1:K1").
sheet.getRange("A1:E1").moveTo("G1");
await context.sync();
});
See also
Excel JavaScript object model in Office Add-ins
Work with cells using the Excel JavaScript API
Remove duplicates using the Excel JavaScript API
Work with multiple ranges simultaneously in Excel add-ins
Remove duplicates using the Excel
JavaScript API
Article • 05/02/2023
This article provides a code sample that removes duplicate entries in a range using the
Excel JavaScript API. For the complete list of properties and methods that the Range
object supports, see Excel.Range class.
The following code sample shows the removal of entries with duplicate values in the first
column.
JavaScript
await context.sync();
See also
Excel JavaScript object model in Office Add-ins
Work with cells using the Excel JavaScript API
Cut, copy, and paste ranges using the Excel JavaScript API
Work with multiple ranges simultaneously in Excel add-ins
Group ranges for an outline using the
Excel JavaScript API
Article • 05/02/2023
This article provides a code sample that shows how to group ranges for an outline using
the Excel JavaScript API. For the complete list of properties and methods that the Range
object supports, see Excel.Range class.
An outline can have a hierarchy, where smaller groups are nested under larger groups.
This allows the outline to be viewed at different levels. Changing the visible outline level
can be done programmatically through the Worksheet.showOutlineLevels method. Note
that Excel only supports eight levels of outline groups.
The following code sample creates an outline with two levels of groups for both the
rows and columns. The subsequent image shows the groupings of that outline. In the
code sample, the ranges being grouped do not include the row or column of the outline
control (the "Totals" for this example). A group defines what will be collapsed, not the
row or column with the control.
JavaScript
// Group the larger, main level. Note that the outline controls
// will be on row 10, meaning 4-9 will collapse and expand.
sheet.getRange("4:9").group(Excel.GroupOption.byRows);
// Group the larger, main level. Note that the outline controls
// will be on column R, meaning C-Q will collapse and expand.
sheet.getRange("C:Q").group(Excel.GroupOption.byColumns);
See also
Excel JavaScript object model in Office Add-ins
Work with cells using the Excel JavaScript API
Work with multiple ranges simultaneously in Excel add-ins
Handle dynamic arrays and spilling
using the Excel JavaScript API
Article • 05/02/2023
This article provides a code sample that handles dynamic arrays and range spilling using
the Excel JavaScript API. For the complete list of properties and methods that the Range
object supports, see Excel.Range class.
Dynamic arrays
Some Excel formulas return Dynamic arrays . These fill the values of multiple cells
outside of the formula's original cell. This value overflow is referred to as a "spill". Your
add-in can find the range used for a spill with the Range.getSpillingToRange method.
There is also a *OrNullObject version, Range.getSpillingToRangeOrNullObject .
The following sample shows a basic formula that copies the contents of a range into a
cell, which spills into neighboring cells. The add-in then logs the range that contains the
spill.
JavaScript
// Get the address of the cells that the dynamic array spilled into.
let spillRange = targetCell.getSpillingToRange();
spillRange.load("address");
Range spilling
Find the cell responsible for spilling into a given cell by using the Range.getSpillParent
method. Note that getSpillParent only works when the range object is a single cell.
Calling getSpillParent on a range with multiple cells will result in an error being thrown
(or a null range being returned for Range.getSpillParentOrNullObject ).
See also
Excel JavaScript object model in Office Add-ins
Work with cells using the Excel JavaScript API
Work with multiple ranges simultaneously in Excel add-ins
Get formula precedents and dependents
using the Excel JavaScript API
Article • 05/02/2023
Excel formulas often refer to other cells. These cross-cell references are known as
"precedents" and "dependents". A precedent is a cell that provides data to a formula. A
dependent is a cell that contains a formula that refers to other cells. To learn more about
Excel features related to relationships between cells, see Display the relationships
between formulas and cells .
A precedent cell may have its own precedent cells. Every precedent cell in this chain of
precedents is still a precedent of the original cell. The same relationship exists for
dependents. Any cell affected by another cell is a dependent of that cell. A "direct
precedent" is the first preceding group of cells in this sequence, similar to the concept
of parents in a parent-child relationship. A "direct dependent" is the first dependent
group of cells in a sequence, similar to children in a parent-child relationship.
This article provides code samples that retrieve precedents and dependents of formulas
using the Excel JavaScript API. For the complete list of properties and methods that the
Range object supports, see Range Object (JavaScript API for Excel).
The following screenshot shows the result of selecting the Trace Precedents button in
the Excel UI. This button draws an arrow from precedent cells to the selected cell. The
selected cell, E3, contains the formula "=C3 * D3", so both C3 and D3 are precedent
cells. Unlike the Excel UI button, the getPrecedents and getDirectPrecedents methods
don't draw arrows.
) Important
The following code sample shows how to work with the Range.getPrecedents and
Range.getDirectPrecedents methods. The sample gets the precedents for the active
range and then changes the background color of those precedent cells. The background
color of the direct precedent cells is set to yellow and the background color of the other
precedent cells is set to orange.
JavaScript
// This code sample shows how to find and highlight the precedents
// and direct precedents of the currently selected cell.
await Excel.run(async (context) => {
let range = context.workbook.getActiveCell();
// Precedents are all cells that provide data to the selected formula.
let precedents = range.getPrecedents();
// Direct precedents are the parent cells, or the first preceding group of
cells that provide data to the selected formula.
let directPrecedents = range.getDirectPrecedents();
range.load("address");
precedents.areas.load("address");
directPrecedents.areas.load("address");
await context.sync();
// Use the precedents API to loop through all precedents of the active
cell.
for (let i = 0; i < precedents.areas.items.length; i++) {
// Highlight and print out the address of all precedent cells.
precedents.areas.items[i].format.fill.color = "Orange";
console.log(` ${precedents.areas.items[i].address}`);
}
// Use the direct precedents API to loop through direct precedents of the
active cell.
for (let i = 0; i < directPrecedents.areas.items.length; i++) {
// Highlight and print out the address of each direct precedent cell.
directPrecedents.areas.items[i].format.fill.color = "Yellow";
console.log(` ${directPrecedents.areas.items[i].address}`);
}
});
The following screenshot shows the result of selecting the Trace Dependents button in
the Excel UI. This button draws an arrow from the selected cell to dependent cells. The
selected cell, D3, has cell E3 as a dependent. E3 contains the formula "=C3 * D3". Unlike
the Excel UI button, the getDependents and getDirectDependents methods don't draw
arrows.
) Important
The following code sample gets the direct dependents for the active range and then
changes the background color of those dependent cells to yellow.
The following code sample shows how to work with the Range.getDependents and
Range.getDirectDependents methods. The sample gets the dependents for the active
range and then changes the background color of those dependent cells. The
background color of the direct dependent cells is set to yellow and the background
color of the other dependent cells is set to orange.
JavaScript
// This code sample shows how to find and highlight the dependents
// and direct dependents of the currently selected cell.
await Excel.run(async (context) => {
let range = context.workbook.getActiveCell();
// Dependents are all cells that contain formulas that refer to other
cells.
let dependents = range.getDependents();
// Direct dependents are the child cells, or the first succeeding group
of cells in a sequence of cells that refer to other cells.
let directDependents = range.getDirectDependents();
range.load("address");
dependents.areas.load("address");
directDependents.areas.load("address");
await context.sync();
// Use the dependents API to loop through all dependents of the active
cell.
for (let i = 0; i < dependents.areas.items.length; i++) {
// Highlight and print out the addresses of all dependent cells.
dependents.areas.items[i].format.fill.color = "Orange";
console.log(` ${dependents.areas.items[i].address}`);
}
See also
Excel JavaScript object model in Office Add-ins
Work with cells using the Excel JavaScript API
Work with multiple ranges simultaneously in Excel add-ins
Delay execution while cell is being
edited
Article • 07/21/2022
Excel.run has an overload that takes in a Excel.RunOptions object. This contains a set of
properties that affect platform behavior when the function runs. The following property
is currently supported.
delayForCellEdit : Determines whether Excel delays the batch request until the
user exits cell edit mode. When true , the batch request is delayed and runs when
the user exits cell edit mode. When false , the batch request automatically fails if
the user is in cell edit mode (causing an error to reach the user). The default
behavior with no delayForCellEdit property specified is equivalent to when it is
false .
JavaScript
The Excel JavaScript library enables your add-in to perform operations, and set
properties, on multiple ranges simultaneously. The ranges do not have to be
contiguous. In addition to making your code simpler, this way of setting a property runs
much faster than setting the same property individually for each of the ranges.
RangeAreas
A set of (possibly discontiguous) ranges is represented by a RangeAreas object. It has
properties and methods similar to the Range type (many with the same, or similar,
names), but adjustments have been made to:
The data types for properties and the behavior of the setters and getters.
The data types of method parameters and the method behaviors.
The data types of method return values.
Some examples:
that represents the data validation of all the ranges in the RangeAreas , if it is
consistent. The property is null if identical DataValidation objects are not applied
to all the all the ranges in the RangeAreas . This is a general, but not universal,
principle with the RangeAreas object: If a property does not have consistent values
on all the all the ranges in the RangeAreas , then it is null . See Read properties of
RangeAreas for more information and some exceptions.
RangeAreas.cellCount gets the total number of cells in all the ranges in the
RangeAreas .
RangeAreas.calculate recalculates the cells of all the ranges in the RangeAreas .
RangeAreas object that represents all of the columns (or rows) in all the ranges in
the RangeAreas . For example, if the RangeAreas represents "A1:C4" and "F14:L15",
then RangeAreas.getEntireColumn returns a RangeAreas object that represents
"A:C" and "F:L".
RangeAreas.copyFrom can take either a Range or a RangeAreas parameter
Properties
Be familiar with Read properties of RangeAreas before you write code that reads any
properties listed. There are subtleties to what gets returned.
address
addressLocal
cellCount
conditionalFormats
context
dataValidation
format
isEntireColumn
isEntireRow
style
worksheet
Methods
calculate()
clear()
convertDataTypeToText()
convertToLinkedDataType()
copyFrom()
getEntireColumn()
getEntireRow()
getIntersection()
getIntersectionOrNullObject()
getSpecialCells()
getSpecialCellsOrNullObject()
getTables()
getUsedRange() (named getUsedRangeAreas on the RangeAreas object)
load()
set()
setDirty()
toJSON()
track()
untrack()
areas : A RangeCollection object that contains all of the ranges represented by the
RangeAreas object. The RangeCollection object is also new and is similar to other
Excel collection objects. It has an items property which is an array of Range objects
representing the ranges.
areaCount : The total number of ranges in the RangeAreas .
getOffsetRangeAreas : Works just like Range.getOffsetRange, except that a
RangeAreas is returned and it contains ranges that are each offset from one of the
Create RangeAreas
You can create RangeAreas object in two basic ways:
Once you have a RangeAreas object, you can create others using the methods on the
object that return RangeAreas such as getOffsetRangeAreas and getIntersection .
7 Note
You cannot directly add additional ranges to a RangeAreas object. For example, the
collection in RangeAreas.areas does not have an add method.
2 Warning
For example, it is possible to push an additional Range object onto the array, but
doing so will cause errors because RangeAreas properties and methods behave as if
the new item isn't there. For example, the areaCount property does not include
ranges pushed in this way, and the RangeAreas.getItemAt(index) throws an error if
index is larger than areasCount-1 . Similarly, deleting a Range object in the
Range.delete method causes bugs: although the Range object is deleted, the
properties and methods of the parent RangeAreas object behave, or try to, as if it is
still in existence. For example, if your code calls RangeAreas.calculate , Office will
try to calculate the range, but will error because the range object is gone.
JavaScript
await context.sync();
});
This example applies to scenarios in which you can hard code the range addresses that
you pass to getRanges or easily calculate them at runtime. Some of the scenarios in
which this would be true include:
The code runs in the context of a known template.
The code runs in the context of imported data where the schema of the data is
known.
within a range.
JavaScript
rangeAreas.load("format/fill/color, isEntireColumn");
await context.sync();
console.log(rangeAreas.format.fill.color); // #FFC0CB
console.log(rangeAreas.isEntireColumn); // true
});
Things get more complicated when consistency isn't possible. The behavior of
RangeAreas properties follows these three principles:
For example, the following code creates a RangeAreas in which only one range is an
entire column and only one is filled with pink. The console will show null for the fill
color, false for the isEntireRow property, and "Sheet1!F3:F5, Sheet1!H:H" (assuming
the sheet name is "Sheet1") for the address property.
JavaScript
console.log(rangeAreas.format.fill.color); // null
console.log(rangeAreas.isEntireColumn); // false
console.log(rangeAreas.address); // "Sheet1!F3:F5, Sheet1!H:H"
});
See also
Fundamental programming concepts with the Excel JavaScript API
Read or write to a large range using the Excel JavaScript API
Work with shapes using the Excel
JavaScript API
Article • 07/19/2022
Excel defines shapes as any object that sits on the drawing layer of Excel. That means
anything outside of a cell is a shape. This article describes how to use geometric shapes,
lines, and images in conjunction with the Shape and ShapeCollection APIs. Charts are
covered in their own article, Work with charts using the Excel JavaScript API.
Create shapes
Shapes are created through and stored in a worksheet's shape collection
( Worksheet.shapes ). ShapeCollection has several .add* methods for this purpose. All
shapes have names and IDs generated for them when they are added to the collection.
These are the name and id properties, respectively. name can be set by your add-in for
easy retrieval with the ShapeCollection.getItem(name) method.
The following types of shapes are added using the associated method.
Geometric shapes
A geometric shape is created with ShapeCollection.addGeometricShape . That method
takes a GeometricShapeType enum as an argument.
The following code sample creates a 150x150-pixel rectangle named "Square" that is
positioned 100 pixels from the top and left sides of the worksheet.
JavaScript
// This sample creates a rectangle positioned 100 pixels from the top and
left sides
// of the worksheet and is 150x150 pixels.
await Excel.run(async (context) => {
let shapes = context.workbook.worksheets.getItem("MyWorksheet").shapes;
let rectangle =
shapes.addGeometricShape(Excel.GeometricShapeType.rectangle);
rectangle.left = 100;
rectangle.top = 100;
rectangle.height = 150;
rectangle.width = 150;
rectangle.name = "Square";
await context.sync();
});
Images
JPEG, PNG, and SVG images can be inserted into a worksheet as shapes. The
ShapeCollection.addImage method takes a base64-encoded string as an argument. This
is either a JPEG or PNG image in string form. ShapeCollection.addSvg also takes in a
string, though this argument is XML that defines the graphic.
The following code sample shows an image file being loaded by a FileReader as a
string. The string has the metadata "base64," removed before the shape is created.
JavaScript
// This sample creates an image as a Shape object in the worksheet.
let myFile = document.getElementById("selectedFile");
let reader = new FileReader();
Lines
A line is created with ShapeCollection.addLine . That method needs the left and top
margins of the line's start and end points. It also takes a ConnectorType enum to specify
how the line contorts between endpoints. The following code sample creates a straight
line on the worksheet.
JavaScript
specified connection points. The locations of these points vary by shape, but the
Shape.connectionSiteCount can be used to ensure your add-in does not connect to a
point that's out-of-bounds. A line is disconnected from any attached shapes using the
disconnectBeginShape and disconnectEndShape methods.
The following code sample connects the "MyLine" line to two shapes named
"LeftShape" and "RightShape".
JavaScript
// This sample connects a line between two shapes at connection points '0'
and '3'.
await Excel.run(async (context) => {
let shapes = context.workbook.worksheets.getItem("MyWorksheet").shapes;
let line = shapes.getItem("MyLine").line;
line.connectBeginShape(shapes.getItem("LeftShape"), 0);
line.connectEndShape(shapes.getItem("RightShape"), 3);
await context.sync();
});
A shape's depth relative to other shapes is defined by the zorderPosition property. This
is set using the setZOrder method, which takes a ShapeZOrder. setZOrder adjusts the
ordering of the current shape relative to the other shapes.
Your add-in has a couple options for changing the height and width of shapes. Setting
either the height or width property changes the specified dimension without changing
the other dimension. The scaleHeight and scaleWidth adjust the shape's respective
dimensions relative to either the current or original size (based on the value of the
provided ShapeScaleType). An optional ShapeScaleFrom parameter specifies from where
the shape scales (top-left corner, middle, or bottom-right corner). If the
lockAspectRatio property is true , the scale methods maintain the shape's current
7 Note
Direct changes to the height and width properties only affect that property,
regardless of the lockAspectRatio property's value.
The following code sample shows a shape being scaled to 1.25 times its original size and
rotated 30 degrees.
JavaScript
await context.sync();
});
Text in shapes
Geometric Shapes can contain text. Shapes have a textFrame property of type
TextFrame. The TextFrame object manages the text display options (such as margins and
text overflow). TextFrame.textRange is a TextRange object with the text content and font
settings.
The following code sample creates a geometric shape named "Wave" with the text
"Shape Text". It also adjusts the shape and text colors, as well as sets the text's
horizontal alignment to the center.
JavaScript
// This sample creates a light-blue wave shape and adds the purple text
"Shape text" to the center.
await Excel.run(async (context) => {
let shapes = context.workbook.worksheets.getItem("MyWorksheet").shapes;
let wave = shapes.addGeometricShape(Excel.GeometricShapeType.wave);
wave.left = 100;
wave.top = 400;
wave.height = 50;
wave.width = 150;
wave.name = "Wave";
wave.fill.setSolidColor("lightblue");
The following code sample shows the creation of a text box with the text "Hello!".
JavaScript
// This sample creates a text box with the text "Hello!" and sizes it
appropriately.
await Excel.run(async (context) => {
let shapes = context.workbook.worksheets.getItem("MyWorksheet").shapes;
let textbox = shapes.addTextBox("Hello!");
textbox.left = 100;
textbox.top = 100;
textbox.height = 20;
textbox.width = 45;
textbox.name = "Textbox";
await context.sync();
});
Shape groups
Shapes can be grouped together. This allows a user to treat them as a single entity for
positioning, sizing, and other related tasks. A ShapeGroup is a type of Shape , so your
add-in treats the group as a single shape.
The following code sample shows three shapes being grouped together. The
subsequent code sample shows that shape group being moved to the right 50 pixels.
JavaScript
await context.sync();
});
// This sample moves the previously created shape group to the right by 50
pixels.
await Excel.run(async (context) => {
let shapes = context.workbook.worksheets.getItem("MyWorksheet").shapes;
let shapeGroup = shapes.getItem("Group");
shapeGroup.incrementLeft(50);
await context.sync();
});
) Important
Individual shapes within the group are referenced through the ShapeGroup.shapes
property, which is of type GroupShapeCollection. They are no longer accessible
through the worksheet's shape collection after being grouped. As an example, if
your worksheet had three shapes and they were all grouped together, the
worksheet's shapes.getCount method would return a count of 1.
JavaScript
await context.sync();
console.log(stringResult.value);
// Instead of logging, your add-in may use the base64-encoded string to
save the image as a file or insert it in HTML.
});
Delete shapes
Shapes are removed from the worksheet with the Shape object's delete method. No
other metadata is needed.
The following code sample deletes all the shapes from MyWorksheet.
JavaScript
// We'll load all the shapes in the collection without loading their
properties.
shapes.load("items/$none");
await context.sync();
shapes.items.forEach(function (shape) {
shape.delete();
});
await context.sync();
});
See also
Fundamental programming concepts with the Excel JavaScript API
Work with charts using the Excel JavaScript API
Work with tables using the Excel
JavaScript API
Article • 05/20/2022
This article provides code samples that show how to perform common tasks with tables
using the Excel JavaScript API. For the complete list of properties and methods that the
Table and TableCollection objects support, see Table Object (JavaScript API for Excel)
Create a table
The following code sample creates a table in the worksheet named Sample. The table
has headers and contains four columns and seven rows of data. If the Excel application
where the code is running supports requirement set ExcelApi 1.2, the width of the
columns and height of the rows are set to best fit the current data in the table.
7 Note
To specify a name for a table, you must first create the table and then set its name
property, as shown in the following example.
JavaScript
if (Office.context.requirements.isSetSupported("ExcelApi", "1.2")) {
sheet.getUsedRange().format.autofitColumns();
sheet.getUsedRange().format.autofitRows();
}
sheet.activate();
await context.sync();
});
New table
alwaysInsert parameter is set to true , which indicates that the new rows be inserted
into the table, not below the table. The width of the columns and height of the rows are
then set to best fit the current data in the table.
7 Note
The index property of a TableRow object indicates the index number of the row
within the rows collection of the table. A TableRow object does not contain an id
property that can be used as a unique key to identify the row.
JavaScript
// This code sample shows how to add rows to a table that already exists
// on a worksheet named Sample.
await Excel.run(async (context) => {
let sheet = context.workbook.worksheets.getItem("Sample");
let expensesTable = sheet.tables.getItem("ExpensesTable");
expensesTable.rows.add(
null, // index, Adds rows to the end of the table.
[
["1/16/2017", "THE PHONE COMPANY", "Communications", "$120"],
["1/20/2017", "NORTHWIND ELECTRIC CARS", "Transportation",
"$142"],
["1/20/2017", "BEST FOR YOU ORGANICS COMPANY", "Groceries",
"$27"],
["1/21/2017", "COHO VINEYARD", "Restaurant", "$33"],
["1/25/2017", "BELLOWS COLLEGE", "Education", "$350"],
["1/28/2017", "TREY RESEARCH", "Other", "$135"],
["1/31/2017", "BEST FOR YOU ORGANICS COMPANY", "Groceries",
"$97"]
],
true, // alwaysInsert, Specifies that the new rows be inserted into
the table.
);
sheet.getUsedRange().format.autofitColumns();
sheet.getUsedRange().format.autofitRows();
await context.sync();
});
The index property of a TableColumn object indicates the index number of the
column within the columns collection of the table. The id property of a
TableColumn object contains a unique key that identifies the column.
JavaScript
sheet.getUsedRange().format.autofitColumns();
sheet.getUsedRange().format.autofitRows();
await context.sync();
});
JavaScript
sheet.getUsedRange().format.autofitColumns();
sheet.getUsedRange().format.autofitRows();
await context.sync();
});
Table with new calculated column
Resize a table
Your add-in can resize a table without adding data to the table or changing cell values.
To resize a table, use the Table.resize method. The following code sample shows how to
resize a table. This code sample uses the ExpensesTable from the Create a table section
earlier in this article and sets the new range of the table to A1:D20.
JavaScript
await context.sync();
});
) Important
The new range of the table must overlap with the original range, and the headers
(or the top of the table) must be in the same row.
JavaScript
await context.sync();
sheet.getUsedRange().format.autofitColumns();
sheet.getUsedRange().format.autofitRows();
await context.sync();
});
JavaScript
The TableChangedEventArgs object provides information about the changes and the
source. Since onChanged fires when either the format or value of the data changes, it can
be useful to have your add-in check if the values have actually changed. The details
property encapsulates this information as a ChangedEventDetail. The following code
sample shows how to display the before and after values and types of a cell that has
been changed.
JavaScript
// Print the before and after types and values to the console.
console.log(`Change at ${address}: was ${details.valueBefore}
(${details.valueTypeBefore}),`
+ ` now is ${details.valueAfter}(${details.valueTypeAfter})`);
await context.sync();
});
}
JavaScript
When data is sorted in a worksheet, an event notification fires. To learn more about sort-
related events and how your add-in can register event handlers to respond to such
events, see Handle sorting events.
JavaScript
JavaScript
expensesTable.clearFilters();
await context.sync();
});
JavaScript
await context.sync();
console.log(visibleRange.values);
});
AutoFilter
An add-in can use the table's AutoFilter object to filter data. An AutoFilter object is the
entire filter structure of a table or range. All of the filter operations discussed earlier in
this article are compatible with the auto-filter. The single access point does make it
easier to access and manage multiple filters.
The following code sample shows the same data filtering as the earlier code sample, but
done entirely through the auto-filter.
JavaScript
expensesTable.autoFilter.apply(expensesTable.getRange(), 2, {
filterOn: Excel.FilterOn.values,
values: ["Restaurant", "Groceries"]
});
expensesTable.autoFilter.apply(expensesTable.getRange(), 3, {
filterOn: Excel.FilterOn.dynamic,
dynamicCriteria: Excel.DynamicFilterCriteria.belowAverage
});
await context.sync();
});
An AutoFilter can also be applied to a range at the worksheet level. See Work with
worksheets using the Excel JavaScript API for more information.
Format a table
The following code sample applies formatting to a table. It specifies different fill colors
for the header row of the table, the body of the table, the second row of the table, and
the first column of the table. For information about the properties you can use to specify
format, see RangeFormat Object (JavaScript API for Excel).
JavaScript
expensesTable.getHeaderRowRange().format.fill.color = "#C70039";
expensesTable.getDataBodyRange().format.fill.color = "#DAF7A6";
expensesTable.rows.getItemAt(1).getRange().format.fill.color =
"#FFC300";
expensesTable.columns.getItemAt(0).getDataBodyRange().format.fill.color
= "#FFA07A";
await context.sync();
});
JavaScript
sheet.getUsedRange().format.autofitColumns();
sheet.getUsedRange().format.autofitRows();
sheet.activate();
await context.sync();
});
JavaScript
let transactions = [
{
"DATE": "1/1/2017",
"MERCHANT": "The Phone Company",
"CATEGORY": "Communications",
"AMOUNT": "$120"
},
{
"DATE": "1/1/2017",
"MERCHANT": "Southridge Video",
"CATEGORY": "Entertainment",
"AMOUNT": "$40"
}
];
expensesTable.rows.add(null, newData);
sheet.getUsedRange().format.autofitColumns();
sheet.getUsedRange().format.autofitRows();
sheet.activate();
await context.sync();
});
New table
See also
Excel JavaScript object model in Office Add-ins
Work with workbooks using the Excel
JavaScript API
Article • 05/02/2023
This article provides code samples that show how to perform common tasks with
workbooks using the Excel JavaScript API. For the complete list of properties and
methods that the Workbook object supports, see Workbook Object (JavaScript API for
Excel). This article also covers workbook-level actions performed through the
Application object.
The Workbook object is the entry point for your add-in to interact with Excel. It
maintains collections of worksheets, tables, PivotTables, and more, through which Excel
data is accessed and changed. The WorksheetCollection object gives your add-in access
to all the workbook's data through individual worksheets. Specifically, it lets your add-in
add worksheets, navigate among them, and assign handlers to worksheet events. The
article Work with worksheets using the Excel JavaScript API describes how to access and
edit worksheets.
JavaScript
The getSelectedRange() method returns the currently selected single range. If multiple
ranges are selected, an InvalidSelection error is thrown. The following example shows a
call to getSelectedRange() that then sets the range's fill color to yellow.
JavaScript
await Excel.run(async (context) => {
let range = context.workbook.getSelectedRange();
range.format.fill.color = "yellow";
await context.sync();
});
Create a workbook
Your add-in can create a new workbook, separate from the Excel instance in which the
add-in is currently running. The Excel object has the createWorkbook method for this
purpose. When this method is called, the new workbook is immediately opened and
displayed in a new instance of Excel. Your add-in remains open and running with the
previous workbook.
JavaScript
Excel.createWorkbook();
The createWorkbook method can also create a copy of an existing workbook. The
method accepts a base64-encoded string representation of an .xlsx file as an optional
parameter. The resulting workbook will be a copy of that file, assuming the string
argument is a valid .xlsx file.
You can get your add-in's current workbook as a base64-encoded string by using file
slicing. The FileReader class can be used to convert a file into the required base64-
encoded string, as demonstrated in the following example.
JavaScript
Excel.createWorkbook(externalWorkbook);
return context.sync();
});
});
// Read the file as a data URL so we can parse the base64-encoded string.
reader.readAsDataURL(myFile.files[0]);
TypeScript
) Important
The following code sample shows how to insert worksheets from another workbook into
the current workbook. This code sample first processes a workbook file with a
FileReader object and extracts a base64-encoded string, and then it inserts this
base64-encoded string into the current workbook. The new worksheets are inserted
after the worksheet named Sheet1. Note that [] is passed as the parameter for the
InsertWorksheetOptions.sheetNamesToInsert property. This means that all the
worksheets from the target workbook are inserted into the current workbook.
JavaScript
// Read the file as a data URL so we can parse the base64-encoded string.
reader.readAsDataURL(myFile.files[0]);
JavaScript
if (!workbook.protection.protected) {
workbook.protection.protect();
}
});
The protect method accepts an optional string parameter. This string represents the
password needed for a user to bypass protection and change the workbook's structure.
Protection can also be set at the worksheet level to prevent unwanted data editing. For
more information, see the Data protection section of the Work with worksheets using
the Excel JavaScript API article.
7 Note
For more information about workbook protection in Excel, see the Protect a
workbook article.
JavaScript
Custom properties
You can also define custom properties. The DocumentProperties object contains a
custom property that represents a collection of key-value pairs for user-defined
properties. The following example shows how to create a custom property named
Introduction with the value "Hello", then retrieve it.
JavaScript
[...]
JavaScript
await context.sync();
});
[...]
await context.sync();
JavaScript
await context.sync();
console.log("Workbook needs review : " + needsReview.value);
});
This contains settings like the numerical decimal separator or the date format.
Some culture settings can be changed through the Excel UI . The system settings are
preserved in the CultureInfo object. Any local changes are kept as Application-level
properties, such as Application.decimalSeparator .
The following sample changes the decimal separator character of a numerical string
from a ',' to the character used by the system settings.
JavaScript
context.application.cultureInfo.numberFormat.load("numberDecimalSeparator");
await context.sync();
let systemDecimalSeparator =
context.application.cultureInfo.numberFormat.numberDecimalSeparator;
let oldDecimalString = decimalSource.values[0][0];
The following samples show how to use custom XML parts. The first code block
demonstrates how to embed XML data in the document. It stores a list of reviewers,
then uses the workbook's settings to save the XML's id for future retrieval. The second
block shows how to access that XML later. The "ContosoReviewXmlPartId" setting is
loaded and passed to the workbook's customXmlParts . The XML data is then printed to
the console.
JavaScript
JavaScript
await context.sync();
if (xmlPartIDSetting.value) {
let customXmlPart =
context.workbook.customXmlParts.getItem(xmlPartIDSetting.value);
let xmlBlob = customXmlPart.getXml();
await context.sync();
7 Note
automatic : The default recalculation behavior where Excel calculates new formula
full : Recalculate all formulas in all open workbooks, regardless of whether they
marked for recalculation) since the last calculation, and formulas dependent on
them, in all active workbooks.
7 Note
For more information about recalculation, see the Change formula recalculation,
iteration, or precision article.
JavaScript
context.application.suspendApiCalculationUntilNextSync();
To detect when a workbook is activated, register an event handler for the onActivated
event of a workbook. Event handlers for the onActivated event receive a
WorkbookActivatedEventArgs object when the event fires.
) Important
The onActivated event doesn't detect when a workbook is opened. This event only
detects when a user switches focus back to an already open workbook.
The following code sample shows how to register the onActivated event handler and
set up a callback function.
JavaScript
single, optional saveBehavior parameter that can be one of the following values.
Excel.SaveBehavior.save (default): The file is saved without prompting the user to
specify file name and save location. If the file has not been saved previously, it's
saved to the default location. If the file has been saved previously, it's saved to the
same location.
Excel.SaveBehavior.prompt : If file has not been saved previously, the user will be
prompted to specify file name and save location. If the file has been saved
previously, it will be saved to the same location and the user will not be prompted.
U Caution
If the user is prompted to save and cancels the operation, save throws an
exception.
JavaScript
context.workbook.save(Excel.SaveBehavior.prompt);
workbook (the Excel application remains open). The close method takes a single,
optional closeBehavior parameter that can be one of the following values.
Excel.CloseBehavior.save (default): The file is saved before closing. If the file has
not been saved previously, the user will be prompted to specify file name and save
location.
Excel.CloseBehavior.skipSave : The file is immediately closed, without saving. Any
JavaScript
context.workbook.close(Excel.CloseBehavior.save);
See also
Excel JavaScript object model in Office Add-ins
Work with worksheets using the Excel JavaScript API
Work with worksheets using the Excel
JavaScript API
Article • 07/21/2022
This article provides code samples that show how to perform common tasks with
worksheets using the Excel JavaScript API. For the complete list of properties and
methods that the Worksheet and WorksheetCollection objects support, see Worksheet
Object (JavaScript API for Excel) and WorksheetCollection Object (JavaScript API for
Excel).
7 Note
The information in this article applies only to regular worksheets; it does not apply
to "chart" sheets or "macro" sheets.
Get worksheets
The following code sample gets the collection of worksheets, loads the name property of
each worksheet, and writes a message to the console.
JavaScript
await context.sync();
if (sheets.items.length > 1) {
console.log(`There are ${sheets.items.length} worksheets in the
workbook:`);
} else {
console.log(`There is one worksheet in the workbook:`);
}
sheets.items.forEach(function (sheet) {
console.log(sheet.name);
});
});
7 Note
The id property of a worksheet uniquely identifies the worksheet in a given
workbook and its value will remain the same even when the worksheet is renamed
or moved. When a worksheet is deleted from a workbook in Excel on Mac, the id
of the deleted worksheet may be reassigned to a new worksheet that is
subsequently created.
JavaScript
await context.sync();
console.log(`The active worksheet is "${sheet.name}"`);
});
JavaScript
await context.sync();
console.log(`The active worksheet is "${sheet.name}"`);
});
JavaScript
await context.sync();
console.log(`The name of the first worksheet is "${firstSheet.name}"`);
});
JavaScript
await context.sync();
console.log(`The name of the last worksheet is "${lastSheet.name}"`);
});
JavaScript
await context.sync();
console.log(`The name of the sheet that follows the active worksheet is
"${nextSheet.name}"`);
});
JavaScript
await context.sync();
console.log(`The name of the sheet that precedes the active worksheet is
"${previousSheet.name}"`);
});
Add a worksheet
The following code sample adds a new worksheet named Sample to the workbook,
loads its name and position properties, and writes a message to the console. The new
worksheet is added after all existing worksheets.
JavaScript
await context.sync();
console.log(`Added worksheet named "${sheet.name}" in position
${sheet.position}`);
});
worksheet's name will have a number appended to the end, in a manner consistent with
copying a worksheet through the Excel UI (for example, MySheet (2)). Worksheet.copy
can take two parameters, both of which are optional:
The following code sample copies the current worksheet and inserts the new sheet
directly after the current worksheet.
JavaScript
Delete a worksheet
The following code sample deletes the final worksheet in the workbook (as long as it's
not the only sheet in the workbook) and writes a message to the console.
JavaScript
await context.sync();
if (sheets.items.length === 1) {
console.log("Unable to delete the only worksheet in the workbook");
} else {
let lastSheet = sheets.items[sheets.items.length - 1];
await context.sync();
}
});
7 Note
A worksheet with a visibility of "Very Hidden" cannot be deleted with the delete
method. If you wish to delete the worksheet anyway, you must first change the
visibility.
Rename a worksheet
The following code sample changes the name of the active worksheet to New Name.
JavaScript
await context.sync();
});
Move a worksheet
The following code sample moves a worksheet from the last position in the workbook to
the first position in the workbook.
JavaScript
JavaScript
await context.sync();
console.log(`Worksheet with name "${sheet.name}" is hidden`);
});
Unhide a worksheet
The following code sample sets the visibility of worksheet named Sample to visible,
loads its name property, and writes a message to the console.
JavaScript
await context.sync();
console.log(`Worksheet with name "${sheet.name}" is visible`);
});
JavaScript
await context.sync();
console.log(`The value of the cell in row 2, column 5 is
"${cell.values[0][0]}" and the address of that cell is "${cell.address}"`);
});
The WorksheetChangedEventArgs object provides information about the changes and the
source. Since onChanged fires when either the format or value of the data changes, it can
be useful to have your add-in check if the values have actually changed. The details
property encapsulates this information as a ChangedEventDetail. The following code
sample shows how to display the before and after values and types of a cell that has
been changed.
JavaScript
// Print the before and after types and values to the console.
console.log(`Change at ${address}: was ${details.valueBefore}
(${details.valueTypeBefore}),`
+ ` now is ${details.valueAfter}(${details.valueTypeAfter})`);
return context.sync();
});
}
) Important
The onFormulaChanged event detects when a formula itself changes, not the data
value resulting from the formula's calculation.
The following code sample shows how to register the onFormulaChanged event handler,
use the WorksheetFormulaChangedEventArgs object to retrieve the formulaDetails array of
the changed formula, and then print out details about the changed formula with the
FormulaChangedEventDetail properties.
7 Note
JavaScript
await context.sync();
});
}
7 Note
onColumnSorted fires when columns are sorted as the result of a left-to-right sort
operation. onRowSorted fires when rows are sorted as the result of a top-to-bottom
sort operation. Sorting a table using the drop-down menu on a column header
results in an onRowSorted event. The event corresponds with what is moving, not
what is being considered as the sorting criteria.
The following images show the ranges returned by the address property for sort events.
First, here is the sample data before sorting:
The following code sample shows how to register an event handler for the
Worksheet.onRowSorted event. The handler's callback clears the fill color for the range,
then fills the cells of the moved rows.
JavaScript
// This will fire whenever a row has been moved as the result of a sort
action.
sheet.onRowSorted.add(async (event) => {
await Excel.run(async (context) => {
console.log("Row sorted: " + event.address);
let sheet = context.workbook.worksheets.getActiveWorksheet();
await context.sync();
});
});
await context.sync();
});
Find all cells with matching text
The Worksheet object has a findAll method to search for a specified string within the
worksheet. It returns a RangeAreas object, which is a collection of Range objects that can
be edited all at once.
The following code sample finds all cells with values equal to the string Complete and
colors them green. Note that findAll throws an ItemNotFound error if the specified
string doesn't exist in the worksheet. If you're uncertain whether the specified string
exists in the worksheet, use the findAllOrNullObject method to gracefully handle that
scenario.
JavaScript
await context.sync();
foundRanges.format.fill.color = "green";
});
7 Note
This section describes how to find cells and ranges using the Worksheet object's
methods. More range retrieval information can be found in object-specific articles.
For examples that show how to get a range within a worksheet using the
Range object, see Get a range using the Excel JavaScript API.
For examples that show how to get ranges from a Table object, see Work
with tables using the Excel JavaScript API.
For examples that show how to search a large range for multiple sub-ranges
based on cell characteristics, see Work with multiple ranges simultaneously
in Excel add-ins.
Filter data
An AutoFilter applies data filters across a range within the worksheet. This is created
with Worksheet.autoFilter.apply , which has the following parameters.
range : The range to which the filter is applied, specified as either a Range object or
a string.
columnIndex : The zero-based column index against which the filter criteria is
evaluated.
criteria : A FilterCriteria object determining which rows should be filtered based
on the column's cell.
The first code sample shows how to add a filter to the worksheet's used range. This filter
will hide entries that are not in the top 25%, based on the values in column 3.
JavaScript
// This filter will only show the rows with the top 25% of values in
column 3.
sheet.autoFilter.apply(farmData, 3, { criterion1: "25", filterOn:
Excel.FilterOn.topPercent });
await context.sync();
});
The next code sample shows how to refresh the auto-filter using the reapply method.
This should be done when the data in the range changes.
JavaScript
// This method refreshes the AutoFilter to ensure that changes are captured.
await Excel.run(async (context) => {
let sheet = context.workbook.worksheets.getActiveWorksheet();
sheet.autoFilter.reapply();
await context.sync();
});
The following code sample shows how to use the clearColumnCriteria method to clear
the auto-filter from only one column, while leaving the filter active on other columns.
JavaScript
The final auto-filter code sample shows how to remove the auto-filter from the
worksheet with the remove method.
JavaScript
An AutoFilter can also be applied to individual tables. See Work with tables using the
Excel JavaScript API for more information.
Data protection
Your add-in can control a user's ability to edit data in a worksheet. The worksheet's
protection property is a WorksheetProtection object with a protect() method. The
following example shows a basic scenario toggling the complete protection of the active
worksheet.
JavaScript
if (!activeSheet.protection.protected) {
activeSheet.protection.protect();
}
});
restrictions.
password : A string representing the password needed for a user to bypass
The article Protect a worksheet has more information about worksheet protection and
how to change it through the Excel UI.
The following code sample shows how to register the onProtectionChanged event
handler and use the WorksheetProtectionChangedEventArgs object to retrieve the
isProtected , worksheetId , and source properties of the event.
JavaScript
JavaScript
The following code sample centers the page (both vertically and horizontally), sets a title
row that will be printed at the top of every page, and sets the printed area to a
subsection of the worksheet.
JavaScript
// Set the first row as the title row for every page.
sheet.pageLayout.setPrintTitleRows("$1:$1");
See also
Excel JavaScript object model in Office Add-ins
Troubleshooting Excel add-ins
Article • 03/09/2023
This article discusses troubleshooting issues that are unique to Excel. Please use the
feedback tool at the bottom of the page to suggest other issues that can be added to
the article.
Chart.activate GeneralException
Range.select GeneralException
Table.clearFilters GeneralException
Workbook.getActiveCell InvalidSelection
Workbook.getSelectedRange InvalidSelection
Workbook.getSelectedRanges InvalidSelection
Worksheet.activate GeneralException
Worksheet.delete InvalidSelection
Worksheet.gridlines GeneralException
Worksheet.showHeadings GeneralException
WorksheetCollection.add GeneralException
WorksheetFreezePanes.freezeAt GeneralException
WorksheetFreezePanes.freezeColumns GeneralException
WorksheetFreezePanes.freezeRows GeneralException
Excel JavaScript API Error thrown
WorksheetFreezePanes.getLocationOrNullObject GeneralException
WorksheetFreezePanes.unfreeze GeneralException
7 Note
Coauthoring
See Coauthoring in Excel add-ins for patterns to use with events in a coauthoring
environment. The article also discusses potential merge conflicts when using certain
APIs, such as TableRowCollection.add.
Known Issues
The following code sample shows how to use this temporary binding ID to retrieve the
related Binding object. In the sample, an event listener is assigned to a binding. The
listener calls the getBindingId method when the onDataChanged event is triggered. The
getBindingId method uses the ID of the temporary Binding object to retrieve the
Binding object that raised the event.
JavaScript
await context.sync();
// You now have the binding object that raised the event:
`originalBindingObject`.
});
}
Custom functions enable developers to add new functions to Excel by defining those
functions in JavaScript as part of an add-in. Users within Excel can access custom
functions just as they would any native function in Excel, such as SUM() .
7 Note
) Important
Note that Excel custom functions are available on the following platforms.
Office on Windows
Microsoft 365 subscription
retail perpetual Office 2016 and later
Office on Mac
Office on the web
Office on iPad
volume-licensed perpetual versions of Office 2019 or earlier
The following animated image shows your workbook calling a function you've created
with JavaScript or TypeScript. In this example, the custom function
=MYFUNCTION.SPHEREVOLUME calculates the volume of a sphere.
The following code defines the custom function =MYFUNCTION.SPHEREVOLUME .
JavaScript
/**
* Returns the volume of a sphere.
* @customfunction
* @param {number} radius
*/
function sphereVolume(radius) {
return Math.pow(radius, 3) * 4 * Math.PI / 3;
}
The Yeoman generator for Office Add-ins offers multiple Excel Custom Functions
projects. We recommend selecting the project type Excel Custom Functions using
a Shared Runtime and the script type JavaScript.
Script file
The script file (./src/functions/functions.js or ./src/functions/functions.ts) contains the
code that defines custom functions and comments which define the function.
The following code defines the custom function add . The code comments are used to
generate a JSON metadata file that describes the custom function to Excel. The required
@customfunction comment is declared first, to indicate that this is a custom function.
Next, two parameters are declared, first and second , followed by their description
properties. Finally, a returns description is given. For more information about what
comments are required for your custom function, see Autogenerate JSON metadata for
custom functions.
JavaScript
/**
* Adds two numbers.
* @customfunction
* @param first First number.
* @param second Second number.
* @returns The sum of the two numbers.
*/
Manifest file
The XML manifest file for an add-in that defines custom functions (./manifest.xml in the
project that the Yeoman generator for Office Add-ins creates) does several things.
Defines the namespace for your custom functions. A namespace prepends itself to
your custom functions to help customers identify your functions as part of your
add-in.
Uses <ExtensionPoint> and <Resources> elements that are unique to a custom
functions manifest. These elements contain the information about the locations of
the JavaScript, JSON, and HTML files.
Specifies which runtime to use for your custom function. We recommend always
using a shared runtime unless you have a specific need for another runtime,
because a shared runtime allows for the sharing of data between functions and the
task pane.
To see a full working manifest from a sample add-in, see the manifest in the one of our
Office Add-in samples Github repositories .
Tip
By following this guidance, you'll streamline the testing process and avoid issues
that would otherwise occur when an add-in is simultaneously sideloaded for
multiple environments.
Coauthoring
Excel on the web and on Windows connected to a Microsoft 365 subscription allow end
users to coauthor in Excel. If an end user's workbook uses a custom function, that end
user's coauthoring colleague is prompted to load the corresponding custom functions
add-in. Once both users have loaded the add-in, the custom function shares results
through coauthoring.
Next steps
Want to try out custom functions? Check out the simple custom functions quick start or
the more in-depth custom functions tutorial if you haven't already.
Another easy way to try out custom functions is to use Script Lab , an add-in that
allows you to experiment with custom functions right in Excel. You can try out creating
your own custom function or play with the provided samples.
See also
Learn about the Microsoft 365 Developer Program
Custom functions requirement sets
Custom functions naming guidelines
Make your custom functions compatible with XLL user-defined functions
Configure your Office Add-in to use a shared runtime
Runtimes in Office Add-ins
Get started developing Excel custom
functions
Article • 03/28/2023
With custom functions, developers can add new functions to Excel by defining them in
JavaScript or TypeScript as part of an add-in. Excel users can access custom functions
just as they would any native function in Excel, such as SUM() .
Prerequisites
7 Note
If you aren't familiar with Node.js or npm, you should start by setting up your
development environment.
The latest version of Yeoman and the Yeoman generator for Office Add-ins. To
install these tools globally, run the following command via the command prompt.
command line
7 Note
7 Note
If you don't already have Office, you can join the Microsoft 365 developer
program to get a free, 90-day renewable Microsoft 365 subscription to use
during development.
Build your first custom functions project
To start, you'll use the Yeoman generator to create the custom functions project. This
will set up your project with the correct folder structure, source files, and dependencies
to begin coding your custom functions.
1. Run the following command to create an add-in project using the Yeoman
generator.
command line
yo office
7 Note
When you run the yo office command, you may receive prompts about the
data collection policies of Yeoman and the Office Add-in CLI tools. Use the
information that's provided to respond to the prompts as you see fit.
When prompted, provide the following information to create your add-in project.
The Yeoman generator will create the project files and install supporting Node
components.
2. The Yeoman generator will give you some instructions in your command line about
what to do with the project, but ignore them and continue to follow our
instructions. Navigate to the root folder of the project.
command line
command line
4. Start the local web server, which runs in Node.js. You can try out the custom
function add-in in Excel. You may be prompted to open the add-in's task pane,
although this is optional. You can still run your custom functions without opening
your add-in's task pane.
To test your add-in in Excel on Windows or Mac, run the following command. When
you run this command, the local web server will start and Excel will open with your
add-in loaded.
command line
7 Note
Office Add-ins should use HTTPS, not HTTP, even when you are developing. If
you are prompted to install a certificate after you run one of the following
commands, accept the prompt to install the certificate that the Yeoman
generator provides. You may also have to run your command prompt or
terminal as an administrator for the changes to be made.
1. Select a cell and type =CONTOSO . Notice that the autocomplete menu shows the list
of all functions in the CONTOSO namespace.
2. Run the CONTOSO.ADD function, using numbers 10 and 200 as input parameters, by
typing the value =CONTOSO.ADD(10,200) in the cell and pressing enter.
The ADD custom function computes the sum of the two numbers that you specify as
input parameters. Typing =CONTOSO.ADD(10,200) should produce the result 210 in the cell
after you press enter.
If the CONTOSO namespace isn't available in the autocomplete menu, take the following
steps to register the add-in in Excel.
1. In Excel, choose the Insert tab and then choose the down-arrow located to the
right of My Add-ins.
2. In the list of available add-ins, find the Developer Add-ins section and select
My custom functions add-in to register it.
Next steps
Congratulations, you've successfully created a custom function in an Excel add-in! Next,
build a more complex add-in with streaming data capability. The following link takes
you through the next steps in the Excel add-in with custom functions tutorial.
Troubleshooting
You may encounter issues if you run the quick start multiple times. If the Office cache
already has an instance of a function with the same name, your add-in gets an error
when it sideloads. You can prevent this by clearing the Office cache before running npm
run start .
See also
Custom functions overview
Custom functions metadata
Runtime for Excel custom functions
Using Visual Studio Code to publish
Tutorial: Create custom functions in
Excel
Article • 03/28/2023
Custom functions enable you to add new functions to Excel by defining those functions
in JavaScript as part of an add-in. Users within Excel can access custom functions as they
would any native function in Excel, such as SUM() . You can create custom functions that
perform simple tasks like calculations or more complex tasks such as streaming real-
time data from the web into a worksheet.
" Create a custom function add-in using the Yeoman generator for Office Add-ins.
" Use a prebuilt custom function to perform a simple calculation.
" Create a custom function that gets data from the web.
" Create a custom function that streams real-time data from the web.
Prerequisites
Node.js (the latest LTS version).
The latest version of Yeoman and the Yeoman generator for Office Add-ins. To
install these tools globally, run the following command via the command prompt.
command line
7 Note
7 Note
If you don't already have Office, you can join the Microsoft 365 developer
program to get a free, 90-day renewable Microsoft 365 subscription to use
during development.
7 Note
If you recreate the yo office project, you may get an error because the Office cache
already has an instance of a function with the same name. You can prevent this by
clearing the Office cache before running npm run start .
1. Run the following command to create an add-in project using the Yeoman
generator.
command line
yo office
7 Note
When you run the yo office command, you may receive prompts about the
data collection policies of Yeoman and the Office Add-in CLI tools. Use the
information that's provided to respond to the prompts as you see fit.
When prompted, provide the following information to create your add-in project.
Tip
You can ignore the next steps guidance that the Yeoman generator provides
after the add-in project's been created. The step-by-step instructions within
this article provide all of the guidance you'll need to complete this tutorial.
command line
command line
7 Note
Office Add-ins should use HTTPS, not HTTP, even when you are developing. If
you are prompted to install a certificate after you run npm run build , accept
the prompt to install the certificate that the Yeoman generator provides.
4. Start the local web server, which runs in Node.js. You can try out the custom
function add-in in Excel.
Excel on Windows or Mac
To test your add-in in Excel on Windows or Mac, run the following command. When
you run this command, the local web server will start and Excel will open with your
add-in loaded.
command line
7 Note
Office Add-ins should use HTTPS, not HTTP, even when you are developing. If
you are prompted to install a certificate after you run one of the following
commands, accept the prompt to install the certificate that the Yeoman
generator provides. You may also have to run your command prompt or
terminal as an administrator for the changes to be made.
Next, try out the ADD custom function by completing the following steps.
1. In Excel, go to any cell and enter =CONTOSO . Notice that the autocomplete menu
shows the list of all functions in the CONTOSO namespace.
2. Run the CONTOSO.ADD function, with numbers 10 and 200 as input parameters, by
typing the value =CONTOSO.ADD(10,200) in the cell and pressing enter.
The ADD custom function computes the sum of the two numbers that you provided and
returns the result of 210.
If the CONTOSO namespace isn't available in the autocomplete menu, take the following
steps to register the add-in in Excel.
2. In the list of available add-ins, find the Developer Add-ins section and select
My custom functions add-in to register it.
7 Note
See the Troubleshooting section of this article if you encounter errors when
sideloading the add-in.
JS
/**
* Gets the star count for a given Github repository.
* @customfunction
* @param {string} userName string name of Github user or
organization.
* @param {string} repoName string name of the Github repository.
* @return {number} number of stars given to a Github repository.
*/
async function getStarCount(userName, repoName) {
try {
//You can change this URL to any web request you want to work
with.
const url = "https://api.github.com/repos/" + userName + "/" +
repoName;
const response = await fetch(url);
//Expect that status code is in 200-299 range
if (!response.ok) {
throw new Error(response.statusText)
}
const jsonResponse = await response.json();
return jsonResponse.watchers_count;
}
catch (error) {
return error;
}
}
command line
4. Complete the following steps (for Excel on the web, Windows, or Mac) to re-
register the add-in in Excel. You must complete these steps before the new
function will be available.
2. In Excel, choose the Insert tab and then choose the down-arrow located to the
right of My Add-ins.
3. In the list of available add-ins, find the Developer Add-ins section and select
My custom functions add-in to register it.
4. Try out the new function. In cell B1, type the text
=CONTOSO.GETSTARCOUNT("OfficeDev", "Office-Add-in-Samples") and
press Enter. You should see that the result in cell B1 is the current number of
stars given to the Office-Add-in-Samples repository .
7 Note
See the Troubleshooting section of this article if you encounter errors when
sideloading the add-in.
In the following code sample, notice that there are two functions, currentTime and
clock . The currentTime function is a static function that doesn't use streaming. It
returns the date as a string. The clock function uses the currentTime function to
provide the new time every second to a cell in Excel. It uses invocation.setResult to
deliver the time to the Excel cell and invocation.onCanceled to handle function
cancellation.
The My custom functions add-in project already contains the following two functions in
the ./src/functions/functions.js file.
JS
/**
* Returns the current time
* @returns {string} String with the current time formatted for the current
locale.
*/
function currentTime() {
return new Date().toLocaleTimeString();
}
/**
* Displays the current time once a second
* @customfunction
* @param {CustomFunctions.StreamingInvocation<string>} invocation Custom
function invocation
*/
function clock(invocation) {
const timer = setInterval(() => {
const time = currentTime();
invocation.setResult(time);
}, 1000);
invocation.onCanceled = () => {
clearInterval(timer);
};
}
To try out the functions, type the text =CONTOSO.CLOCK() in cell C1 and press enter.
You should see the current date, which streams an update every second. While this clock
is just a timer on a loop, you can use the same idea of setting a timer on more complex
functions that make web requests for real-time data.
Troubleshooting
You may encounter issues if you run the tutorial multiple times. If the Office cache
already has an instance of a function with the same name, your add-in gets an error
when it sideloads.
You can prevent this conflict by clearing the Office cache before running npm run start .
If your npm process is already running, enter npm stop , clear the Office cache, and then
restart npm.
Next steps
Congratulations! You've created a new custom functions project, tried out a prebuilt
function, created a custom function that requests data from the web, and created a
custom function that streams data. Next, learn how to Share custom function data with
the task pane.
Tutorial: Share data and events between
Excel custom functions and the task
pane
Article • 03/28/2023
Share global data and send events between the task pane and custom functions of your
Excel add-in with a shared runtime.
2. On line 1, insert the following code at the very top. This will initialize a global
variable named sharedState.
JavaScript
window.sharedState = "empty";
3. Add the following code to create a custom function that stores values to the
sharedState variable.
JavaScript
/**
* Saves a string value to shared state with the task pane
* @customfunction STOREVALUE
* @param {string} value String to write to shared state with task
pane.
* @return {string} A success value
*/
function storeValue(sharedValue) {
window.sharedState = sharedValue;
return "value stored";
}
4. Add the following code to create a custom function that gets the current value of
the sharedState variable.
JavaScript
/**
* Gets a string value from shared state with the task pane
* @customfunction GETVALUE
* @returns {string} String value of the shared state with task pane.
*/
function getValue() {
return window.sharedState;
}
2. After the closing </main> element, add the following HTML. The HTML creates two
text boxes and buttons used to get or store global data.
HTML
<ol>
<li>
Enter a value to send to the custom function and select
<strong>Store</strong>.
</li>
<li>
Enter <strong>=CONTOSO.GETVALUE()</strong> into a cell to retrieve
it.
</li>
<li>
To send data to the task pane, in a cell, enter
<strong>=CONTOSO.STOREVALUE("new value")</strong>
</li>
<li>Select <strong>Get</strong> to display the value in the task
pane.</li>
</ol>
3. Before the closing </body> element, add the following script. This code will handle
the button click events when the user wants to store or get global data.
HTML
<script>
function storeSharedValue() {
let sharedValue = document.getElementById('storeBox').value;
window.sharedState = sharedValue;
}
function getSharedValue() {
document.getElementById('getBox').value = window.sharedState;
}
</script>
command line
command line
Once Excel starts, you can use the task pane buttons to store or get shared data. Enter
=CONTOSO.GETVALUE() into a cell for the custom function to retrieve the same shared
data. Or use =CONTOSO.STOREVALUE("new value") to change the shared data to a new
value.
7 Note
Calling some Office APIs from custom functions using a shared runtime is possible.
See Call Microsoft Excel APIs from a custom function for more details.
See also
Excel custom functions tutorial
Configure your Office Add-in to use a shared runtime
Custom functions naming guidelines
Article • 03/22/2022
A custom function is identified by an id and name property in the JSON metadata file.
) Important
Note that Excel custom functions are available on the following platforms.
Office on Windows
Microsoft 365 subscription
retail perpetual Office 2016 and later
Office on Mac
Office on the web
Office on iPad
volume-licensed perpetual versions of Office 2019 or earlier
A function name can differ from the function id , such as for localization purposes. In
general, a function's name should stay the same as the id if there is no reason for them
to differ.
A function's id may only use characters A through Z, numbers zero through nine,
underscores, and periods.
A function's name may use any Unicode alphabetic characters, underscores, and
periods.
Both function name and id must start with a letter and have a minimum limit of
three characters.
Excel uses uppercase letters for built-in function names (such as SUM ). Use uppercase
letters for your custom function's name and id as a best practice.
A function's name shouldn't be the same as:
Any Excel 4.0 Macro Function (such as RUN , ECHO ). For a full list of these functions,
see this Excel Macro Functions Reference document .
Naming conflicts
If your function name is the same as a function name in an add-in that already exists, the
#REF! error will appear in your workbook.
To fix a naming conflict, change the name in your add-in and try the function again. You
can also uninstall the add-in with the conflicting name. Or, if you're testing your add-in
in different environments, try using a different namespace to differentiate your function
(such as NAMESPACE_NAMEOFFUNCTION ).
Best practices
Consider adding multiple arguments to a function rather than creating multiple
functions with the same or similar names.
Avoid ambiguous abbreviations in function names. Clarity is more important than
brevity. Choose a name like =INCREASETIME rather than =INC .
Function names should indicate the action of the function, such as =GETZIPCODE
instead of ZIPCODE.
Consistently use the same verbs for functions which perform similar actions. For
example, use =DELETEZIPCODE and =DELETEADDRESS , rather than =DELETEZIPCODE and
=REMOVEADDRESS .
When naming a streaming function, consider adding a note to that effect in the
description of the function or adding STREAM to the end of the function's name.
Tip
By following this guidance, you'll streamline the testing process and avoid issues
that would otherwise occur when an add-in is simultaneously sideloaded for
multiple environments.
localized functions.
Next steps
Learn about error handling best practices.
See also
Manually create JSON metadata for custom functions
Excel custom functions tutorial
Custom functions parameter options
Article • 07/05/2023
) Important
Note that Excel custom functions are available on the following platforms.
Office on Windows
Microsoft 365 subscription
retail perpetual Office 2016 and later
Office on Mac
Office on the web
Office on iPad
volume-licensed perpetual versions of Office 2019 or earlier
Optional parameters
When a user invokes a function in Excel, optional parameters appear in brackets. In the
following sample, the add function can optionally add a third number. This function
appears as =CONTOSO.ADD(first, second, [third]) in Excel.
JavaScript
JavaScript
/**
* Calculates the sum of the specified numbers
* @customfunction
* @param {number} first First number.
* @param {number} second Second number.
* @param {number} [third] Third number to add. If omitted, third = 0.
* @returns {number} The sum of the numbers.
*/
function add(first, second, third) {
if (third === null) {
third = 0;
}
return first + second + third;
}
7 Note
When no value is specified for an optional parameter, Excel assigns it the value
null . This means default-initialized parameters in TypeScript will not work as
When you define a function that contains one or more optional parameters, specify
what happens when the optional parameters are null. In the following example, zipCode
and dayOfWeek are both optional parameters for the getWeatherReport function. If the
zipCode parameter is null, the default value is set to 98052 . If the dayOfWeek parameter
JavaScript
JavaScript
/**
* Gets a weather report for a specified zipCode and dayOfWeek
* @customfunction
* @param {number} [zipCode] Zip code. If omitted, zipCode = 98052.
* @param {string} [dayOfWeek] Day of the week. If omitted, dayOfWeek =
Wednesday.
* @returns {string} Weather report for the day of the week in that zip
code.
*/
function getWeatherReport(zipCode, dayOfWeek) {
if (zipCode === null) {
zipCode = 98052;
}
For example, suppose that your function returns the second highest value from a range
of numbers stored in Excel. The following function accepts the parameter values , and
the JSDOC syntax number[][] sets the parameter's dimensionality property to matrix
in the JSON metadata for this function.
JavaScript
/**
* Returns the second highest value in a matrixed range of values.
* @customfunction
* @param {number[][]} values Multiple ranges of values.
*/
function secondHighest(values) {
let highest = values[0][0],
secondHighest = values[0][0];
for (let i = 0; i < values.length; i++) {
for (let j = 0; j < values[i].length; j++) {
if (values[i][j] >= highest) {
secondHighest = highest;
highest = values[i][j];
} else if (values[i][j] >= secondHighest) {
secondHighest = values[i][j];
}
}
}
return secondHighest;
}
Repeating parameters
A repeating parameter allows a user to enter a series of optional arguments to a
function. When the function is called, the values are provided in an array for the
parameter. If the parameter name ends with a number, each argument's number will
increase incrementally, such as ADD(number1, [number2], [number3],…) . This matches the
convention used for built-in Excel functions.
The following function sums the total of numbers, cell addresses, as well as ranges, if
entered.
TS
/**
* The sum of all of the numbers.
* @customfunction
* @param operands A number (such as 1 or 3.1415), a cell address (such as A1
or $E$11), or a range of cell addresses (such as B3:F12)
*/
operands.forEach(range => {
range.forEach(row => {
row.forEach(num => {
total += num;
});
});
});
return total;
}
JS
/**
* @customfunction
* @param {number[]} singleValue An array of numbers that are repeating
parameters.
*/
function addSingleValue(singleValue) {
let total = 0;
singleValue.forEach(value => {
total += value;
})
return total;
}
Single range parameter
A single range parameter isn't technically a repeating parameter, but is included here
because the declaration is very similar to repeating parameters. It would appear to the
user as ADD(A2:B3) where a single range is passed from Excel. The following sample
shows how to declare a single range parameter.
JS
/**
* @customfunction
* @param {number[][]} singleRange
*/
function addSingleRange(singleRange) {
let total = 0;
singleRange.forEach(setOfSingleValues => {
setOfSingleValues.forEach(value => {
total += value;
})
})
return total;
}
In JavaScript, use @param values {number[]} for one-dimensional arrays, @param <name>
{number[][]} for two-dimensional arrays, and so on for more dimensions.
7 Note
The invocation parameter doesn't appear as a custom function argument for users
in Excel.
The following sample shows how to use the invocation parameter to return the address
of the cell that invoked your custom function. This sample uses the address property of
the Invocation object. To access the Invocation object, first declare
CustomFunctions.Invocation as a parameter in your JSDoc. Next, declare
@requiresAddress in your JSDoc to access the address property of the Invocation
object. Finally, within the function, retrieve and then return the address property.
JavaScript
/**
* Return the address of the cell that invoked the custom function.
* @customfunction
* @param {number} first First parameter.
* @param {number} second Second parameter.
* @param {CustomFunctions.Invocation} invocation Invocation object.
* @requiresAddress
*/
function getAddress(first, second, invocation) {
const address = invocation.address;
return address;
}
In Excel, a custom function calling the address property of the Invocation object will
return the absolute address following the format SheetName!RelativeCellAddress in the
cell that invoked the function. For example, if the input parameter is located on a sheet
called Prices in cell F6, the returned parameter address value will be Prices!F6 .
7 Note
If a blank space or any of the following characters is in a worksheet name: ~ ` ! @ #
$ % ^ & ( ) - _ = + { } | ; : , ' < . >, then the worksheet name in the returned address
is enclosed in single quotation marks, so the format is
'SheetName'!RelativeCellAddress ; for example, 'Latest Prices'!F6 . If the single
quotation mark (apostrophe) character, ', is in the name, the returned address has
two such characters in a row; for example, 'Bob''s Region'!F6 .
The invocation parameter can also be used to send information to Excel. See Make a
streaming function to learn more.
This is useful in scenarios where input data types may vary. The address of an input
parameter can be used to check the number format of the input value. The number
format can then be adjusted prior to input, if necessary. The address of an input
parameter can also be used to detect whether the input value has any related properties
that may be relevant to subsequent calculations.
7 Note
The following custom function takes in three input parameters, retrieves the
parameterAddresses property of the Invocation object for each parameter, and then
JavaScript
/**
* Return the addresses of three parameters.
* @customfunction
* @param {string} firstParameter First parameter.
* @param {string} secondParameter Second parameter.
* @param {string} thirdParameter Third parameter.
* @param {CustomFunctions.Invocation} invocation Invocation object.
* @returns {string[][]} The addresses of the parameters, as a 2-dimensional
array.
* @requiresParameterAddresses
*/
function getParameterAddresses(firstParameter, secondParameter,
thirdParameter, invocation) {
const addresses = [
[invocation.parameterAddresses[0]],
[invocation.parameterAddresses[1]],
[invocation.parameterAddresses[2]]
];
return addresses;
}
When a custom function calling the parameterAddresses property runs, the parameter
address is returned following the format SheetName!RelativeCellAddress in the cell that
invoked the function. For example, if the input parameter is located on a sheet called
Costs in cell D8, the returned parameter address value will be Costs!D8 . If the custom
function has multiple parameters and more than one parameter address is returned, the
returned addresses will spill across multiple cells, descending vertically from the cell that
invoked the function.
7 Note
quotation mark (apostrophe) character, ', is in the name, the returned address has
two such characters in a row; for example, 'Bob''s Region'!F6 .
Next steps
Learn how to use volatile values in your custom functions.
See also
Receive and handle data with custom functions
Autogenerate JSON metadata for custom functions
Manually create JSON metadata for custom functions
Create custom functions in Excel
Excel custom functions tutorial
Handle and return errors from your
custom function
Article • 07/21/2022
If something goes wrong while your custom function runs, return an error to inform the
user. If you have specific parameter requirements, such as only positive numbers, test
the parameters and throw an error if they aren't correct. You can also use a try...catch
block to catch any errors that occur while your custom function runs.
TypeScript
/**
* Gets a city name for the given U.S. zip code.
* @customfunction
* @param {string} zipCode
* @returns The city of the zip code.
*/
function getCity(zipCode: string): string {
let isValidZip = /(^\d{5}$)|(^\d{5}-\d{4}$)/.test(zipCode);
if (isValidZip) return cityLookup(zipCode);
let error = new
CustomFunctions.Error(CustomFunctions.ErrorCode.invalidValue, "Please
provide a valid U.S. zip code.");
throw error;
}
invalidName #NAME? There is a typo in the function name. Note that this error is
supported as a custom function input error, but not as a custom
function output error.
invalidReference #REF! The function refers to an invalid cell. Note that this error is
supported as a custom function input error, but not as a custom
function output error.
The following code sample shows how to create and return an error for an invalid
number ( #NUM! ).
TypeScript
The #VALUE! and #N/A errors also support custom error messages. Custom error
messages are displayed in the error indicator menu, which is accessed by hovering over
the error flag on each cell with an error. The following example shows how to return a
custom error message with the #VALUE! error.
TypeScript
// You can only return a custom error message with the #VALUE! and #N/A
errors.
let error = new
CustomFunctions.Error(CustomFunctions.ErrorCode.invalidValue, "The parameter
can only contain lowercase characters.");
throw error;
custom function, replace one of the input parameters with a #NUM! error, and then
return a 2-dimensional array with the results of processing each input parameter.
JavaScript
/**
* Returns the #NUM! error as part of a 2-dimensional array.
* @customfunction
* @param {number} first First parameter.
* @param {number} second Second parameter.
* @param {number} third Third parameter.
* @returns {number[][]} Three results, as a 2-dimensional array.
*/
function returnInvalidNumberError(first, second, third) {
// Use the `CustomFunctions.Error` object to retrieve an invalid number
error.
const error = new CustomFunctions.Error(
CustomFunctions.ErrorCode.invalidNumber, // Corresponds to the #NUM!
error in the Excel UI.
);
// Enter logic that processes the first, second, and third input
parameters.
// Imagine that the second calculation results in an invalid number error.
const firstResult = first;
const secondResult = error;
const thirdResult = third;
// Return the results of the first and third parameter calculations and a
#NUM! error in place of the second result.
return [[firstResult], [secondResult], [thirdResult]];
}
To process inputs that contain errors, a custom function must have the JSON metadata
property allowErrorForDataTypeAny set to true . See Manually create JSON metadata for
custom functions for more information.
) Important
The allowErrorForDataTypeAny property can only be used with manually created
JSON metadata. This property doesn't work with the autogenerated JSON
metadata process.
In the following code sample, the custom function makes a fetch call to a REST service.
It's possible that the call will fail, for example, if the REST service returns an error or the
network goes down. If this happens, the custom function will return #N/A to indicate
that the web call failed.
TypeScript
/**
* Gets a comment from the hypothetical contoso.com/comments API.
* @customfunction
* @param {number} commentID ID of a comment.
*/
function getComment(commentID) {
let url = "https://www.contoso.com/comments/" + commentID;
return fetch(url)
.then(function (data) {
return data.json();
})
.then(function (json) {
return json.body;
})
.catch(function (error) {
throw new
CustomFunctions.Error(CustomFunctions.ErrorCode.notAvailable);
})
}
Next steps
Learn how to troubleshoot problems with your custom functions.
See also
Custom functions debugging
Custom functions requirement sets
Create custom functions in Excel
Autogenerate JSON metadata for
custom functions
Article • 07/13/2023
When an Excel custom function is written in JavaScript or TypeScript, JSDoc tags are
used to provide extra information about the custom function. We provide a Webpack
plugin that uses these JSDoc tags to automatically create the JSON metadata file at
build time. Using the plugin saves you from the effort of manually editing the JSON
metadata file.
) Important
Note that Excel custom functions are available on the following platforms.
Office on Windows
Microsoft 365 subscription
retail perpetual Office 2016 and later
Office on Mac
Office on the web
Office on iPad
volume-licensed perpetual versions of Office 2019 or earlier
CustomFunctionsMetadataPlugin
The plugin is CustomFunctionsMetadataPlugin . To install and configure it, use the
following steps.
7 Note
1. Open a Command Prompt or bash shell and, in the root of the project, run npm
install custom-functions-metadata-plugin .
2. Open the webpack.config.js file and add the following line at the top: const
CustomFunctionsMetadataPlugin = require("custom-functions-metadata-plugin"); .
3. Scroll down to the plugins array and add the following to the top of the array.
Change the input path and filename as needed to match your project, but the
output value must be "functions.json". If you're using TypeScript, use the *.ts
JavaScript
new CustomFunctionsMetadataPlugin({
output: "functions.json",
input: "./src/functions/functions.js",
}),
1. In the webpack.config.js file, replace the string value of input with an array of
string URLs that point to each of the files. The following is an example:
JavaScript
new CustomFunctionsMetadataPlugin({
output: "functions.json",
input: [
"./src/functions/someFunctions.js",
"./src/functions/otherFunctions.js"
],
}),
2. Scroll to the entry.functions property, and replace its value with the same array
you used in the preceding step. The following is an example:
JavaScript
entry: {
polyfill: ["core-js/stable", "regenerator-runtime/runtime"],
taskpane: ["./src/taskpane/taskpane.js",
"./src/taskpane/taskpane.html"],
functions: [
"./src/functions/someFunctions.js",
"./src/functions/otherFunctions.js"
],
},
The function parameter types may be provided using the @param tag in JavaScript, or
from the Function type in TypeScript. For more information, see the @param tag and
Types sections.
To see examples of the built-in function descriptions, open Excel, go to the Formulas
tab, and choose Insert function. You can then browse through all the function
descriptions, and also see your own custom functions listed.
In the following example, the phrase "Calculates the volume of a sphere." is the
description for the custom function.
JavaScript
/**
/* Calculates the volume of a sphere.
/* @customfunction VOLUME
...
*/
@cancelable
@customfunction id name
@helpurl url
@param {type} name description
@requiresAddress
@requiresParameterAddresses
@returns {type}
@streaming
@volatile
@cancelable
Indicates that a custom function performs an action when the function is canceled.
@customfunction
Syntax: @customfunction id name
This tag indicates that the JavaScript/TypeScript function is an Excel custom function. It
is required to create metadata for the custom function.
JavaScript
/**
* Increments a value once a second.
* @customfunction
* ...
*/
id
The id identifies a custom function.
In the following example, increment is the id and the name of the function.
JavaScript
/**
* Increments a value once a second.
* @customfunction INCREMENT
* ...
*/
name
Provides the display name for the custom function.
In the following example, INC is the id of the function and increment is the name .
JavaScript
/**
* Increments a value once a second.
* @customfunction INC INCREMENT
* ...
*/
description
A description appears to users in Excel as they are entering the function and specifies
what the function does. A description doesn't require any specific tag. Add a description
to a custom function by adding a phrase to describe what the function does inside the
JSDoc comment. By default, whatever text is untagged in the JSDoc comment section
will be the description of the function.
In the following example, the phrase "A function that adds two numbers" is the
description for the custom function with the id property of ADD .
JavaScript
/**
* A function that adds two numbers.
* @customfunction ADD
* ...
*/
@helpurl
Syntax: @helpurl url
JavaScript
/**
* A function which streams the temperature in a town you specify.
* @customfunction getTemperature
* @helpurl http://www.contoso.com/weatherhelp
* ...
*/
@param
JavaScript
JavaScript Syntax: @param {type} name description
{type} specifies the type info within curly braces. See the Types section for more
information about the types which may be used. If no type is specified, the default
type any will be used.
name specifies the parameter that the @param tag applies to. It is required.
description provides the description which appears in Excel for the function
parameter. It is optional.
To denote a custom function parameter as optional, put square brackets around the
parameter name. For example, @param {string} [text] Optional text .
7 Note
The following example shows an ADD function that adds two or three numbers, with the
third number as an optional parameter.
JavaScript
/**
* A function which sums two, or optionally three, numbers.
* @customfunction ADDNUMBERS
* @param firstNumber {number} First number to add.
* @param secondNumber {number} Second number to add.
* @param [thirdNumber] {number} Optional third number you wish to add.
* ...
*/
TypeScript
TypeScript Syntax: @param name description
name specifies the parameter that the @param tag applies to. It is required.
description provides the description which appears in Excel for the function
parameter. It is optional.
See the Types section for more information about the function parameter types which
may be used.
7 Note
The following example shows the add function that adds two numbers.
ts
/**
* Adds two numbers.
* @customfunction
* @param first First number
* @param second Second number
* @returns The sum of the two numbers.
*/
function add(first: number, second: number): number {
return first + second;
}
@requiresAddress
Indicates that the address of the cell where the function is being evaluated should be
provided.
The following sample shows how to use the invocation parameter in combination with
@requiresAddress to return the address of the cell that invoked your custom function.
See Invocation parameter for more information.
JavaScript
/**
* Return the address of the cell that invoked the custom function.
* @customfunction
* @param {number} first First parameter.
* @param {number} second Second parameter.
* @param {CustomFunctions.Invocation} invocation Invocation object.
* @requiresAddress
*/
function getAddress(first, second, invocation) {
const address = invocation.address;
return address;
}
@requiresParameterAddresses
Indicates that the function should return the addresses of input parameters.
When the function is called, the parameterAddresses property will contain the addresses
of the input parameters.
The following sample shows how to use the invocation parameter in combination with
@requiresParameterAddresses to return the addresses of three input parameters. See
JavaScript
/**
* Return the addresses of three parameters.
* @customfunction
* @param {string} firstParameter First parameter.
* @param {string} secondParameter Second parameter.
* @param {string} thirdParameter Third parameter.
* @param {CustomFunctions.Invocation} invocation Invocation object.
* @returns {string[][]} The addresses of the parameters, as a 2-dimensional
array.
* @requiresParameterAddresses
*/
function getParameterAddresses(firstParameter, secondParameter,
thirdParameter, invocation) {
const addresses = [
[invocation.parameterAddresses[0]],
[invocation.parameterAddresses[1]],
[invocation.parameterAddresses[2]]
];
return addresses;
}
@returns
Syntax: @returns {type}
If {type} is omitted, the TypeScript type info will be used. If there is no type info, the
type will be any .
The following example shows the add function that uses the @returns tag.
ts
/**
* Adds two numbers.
* @customfunction
* @param first First number
* @param second Second number
* @returns The sum of the two numbers.
*/
function add(first: number, second: number): number {
return first + second;
}
@streaming
Used to indicate that a custom function is a streaming function.
Streaming functions don't return values directly, instead they call setResult(result:
ResultType) using the last parameter.
Exceptions thrown by a streaming function are ignored. setResult() may be called with
Error to indicate an error result. For an example of a streaming function and more
information, see Make a streaming function.
@volatile
A volatile function is one whose result isn't the same from one moment to the next,
even if it takes no arguments or the arguments haven't changed. Excel re-evaluates cells
that contain volatile functions, together with all dependents, every time that a
calculation is done. For this reason, too much reliance on volatile functions can make
recalculation times slow, so use them sparingly.
JavaScript
/**
* Simulates rolling a 6-sided die.
* @customfunction
* @volatile
*/
function roll6sided(): number {
return Math.floor(Math.random() * 6) + 1;
}
Types
By specifying a parameter type, Excel will convert values into that type before calling the
function. If the type is any , no conversion will be performed.
Value types
A single value may be represented using one of the following types: boolean , number ,
string .
Matrix type
Use a two-dimensional array type to have the parameter or return value be a matrix of
values. For example, the type number[][] indicates a matrix of numbers and string[][]
indicates a matrix of strings.
Error type
A non-streaming function can indicate an error by returning an Error type.
A streaming function can indicate an error by calling setResult() with an Error type.
Promise
A custom function can return a promise that provides the value when the promise is
resolved. If the promise is rejected, then the custom function will throw an error.
Other types
Any other type will be treated as an error.
Next steps
Learn about naming conventions for custom functions. Alternatively, learn how to
localize your functions which requires you to write your JSON file by hand.
See also
Manually create JSON metadata for custom functions
Create custom functions in Excel
Use data types with custom functions in
Excel
Article • 03/09/2023
Data types expand the Excel JavaScript API to support data types beyond the original
four cell value types (string, number, boolean, and error). Data types include support for
web images, formatted number values, entities, and arrays within entities.
These data types amplify the power of custom functions, because custom functions
accept data types as both input and output values. You can generate data types through
custom functions, or take existing data types as function arguments into calculations.
Once the JSON schema of a data type is set, this schema is maintained throughout the
calculations.
To learn more about using data types with an Excel add-in, see Overview of data types in
Excel add-ins.
7 Note
Custom functions do not support the full functionality of the enhanced error
objects offered by data types. A custom function can accept a data types error
object, but it won't be maintained throughout calculation. At this time, custom
functions only support the errors included in the CustomFunctions.Error object.
JavaScript
/**
* Take a number as the input value and return a formatted number value as
the output.
* @customfunction
* @param {number} value
* @param {string} format (e.g. "0.00%")
* @returns A formatted number value.
*/
function createFormattedNumber(value, format) {
return {
type: "FormattedNumber",
basicValue: value,
numberFormat: format
}
}
JavaScript
/**
* Accept an entity value data type as a function input.
* @customfunction
* @param {any} value
* @param {string} attribute
* @returns {any} The text value of the entity.
*/
function getEntityAttribute(value, attribute) {
if (value.type == "Entity") {
if (attribute == "text") {
return value.text;
} else {
return value.properties[attribute].basicValue;
}
} else {
return JSON.stringify(value);
}
}
Next steps
To experiment with custom functions and data types, install Script Lab in Excel and try
out the Data types: Custom functions snippet in our Samples library.
See also
Overview of data types in Excel add-ins
Excel data types core concepts
Configure your Office Add-in to use a shared runtime
Call Excel JavaScript APIs from a custom
function
Article • 03/28/2023
Call Excel JavaScript APIs from your custom functions to get range data and obtain more
context for your calculations. Calling Excel JavaScript APIs through a custom function
can be helpful when:
A custom function needs to get information from Excel before calculation. This
information might include document properties, range formats, custom XML parts,
a workbook name, or other Excel-specific information.
A custom function will set the cell's number format for the return values after
calculation.
) Important
To call Excel JavaScript APIs from your custom function, you'll need to use a shared
runtime. Use the Yeoman generator for Office Add-ins to install an Excel Custom
Functions using a Shared Runtime project or see Configure your Office Add-in to
use a shared runtime to learn more.
Code sample
To call Excel JavaScript APIs from a custom function, you first need a context. Use the
Excel.RequestContext object to get a context. Then use the context to call the APIs you
need in the workbook.
The following code sample shows how to use Excel.RequestContext to get a value from
a cell in the workbook. In this sample, the address parameter is passed into the Excel
JavaScript API Worksheet.getRange method and must be entered as a string. For
example, the custom function entered into the Excel UI must follow the pattern
=CONTOSO.GETRANGEVALUE("A1") , where "A1" is the address of the cell from which to
JavaScript
/**
* @customfunction
* @param {string} address The address of the cell from which to retrieve
the value.
* @returns The value of the cell at the input address.
**/
async function getRangeValue(address) {
// Retrieve the context object.
const context = new Excel.RequestContext();
// Use the context object to access the cell at the input address.
const range =
context.workbook.worksheets.getActiveWorksheet().getRange(address);
range.load("values");
await context.sync();
Your custom functions add-in can read information from cells outside the cell running
the custom function, but it shouldn't perform write operations to other cells. Instead,
make changes to other cells or to the Excel environment from the context of a ribbon
button or a task pane. In addition, custom function calculations shouldn't run while an
Excel recalculation is taking place, as this scenario creates unpredictable results.
Next steps
Fundamental programming concepts with the Excel JavaScript API
See also
Share data and events between Excel custom functions and task pane tutorial
Configure your Office Add-in to use a shared runtime
Extend custom functions with XLL user-
defined functions
Article • 03/22/2022
7 Note
An XLL add-in is an Excel add-in file with the file extension .xll. An XLL file is a type
of dynamic link library (DLL) file that can only be opened by Excel. XLL add-in files
must be written in C or C++. See Developing Excel XLLs to learn more.
If you have existing Excel XLL add-ins, you can build equivalent custom function add-ins
using the Excel JavaScript API to extend your solution features to other platforms, such
as Excel on the web or on a Mac. However, Excel JavaScript API add-ins don't have all of
the functionality available in XLL add-ins. Depending on the functionality your solution
uses, the XLL add-in may provide a better experience than the Excel JavaScript API add-
in in Excel on Windows.
) Important
The following example shows how to specify both a COM add-in and an XLL add-in as
equivalents in an Excel JavaScript API add-in manifest file. Often you will specify both.
For completeness, this example shows both in context. They are identified by their
ProgId and FileName respectively. The EquivalentAddins element must be positioned
immediately before the closing VersionOverrides tag. For more information on COM
add-in compatibility, see Make your Office Add-in compatible with an existing COM
add-in.
XML
<VersionOverrides>
...
<EquivalentAddins>
<EquivalentAddin>
<ProgId>ContosoCOMAddin</ProgId>
<Type>COM</Type>
</EquivalentAddin>
<EquivalentAddin>
<FileName>contosofunctions.xll</FileName>
<Type>XLL</Type>
</EquivalentAddin>
</EquivalentAddins>
</VersionOverrides>
7 Note
The following table compares features across XLL user-defined functions, XLL
compatible custom functions, and Excel JavaScript API add-in custom functions.
Supported file XLSX, XLSB, XLSM, XLS XLSX, XLSB, XLSM XLSX, XLSB, XLSM
formats
Calculation No UI. Excel can be Users will see #BUSY! until a Users will see
behavior unresponsive during result is returned. #BUSY! until a result
calculation. is returned.
See also
Make your Office Add-in compatible with an existing COM add-in
Excel custom functions tutorial
Localize custom functions
Article • 03/22/2022
You can localize both your add-in and your custom function names. To do so, provide
localized function names in the functions' JSON file and locale information in the XML
manifest file.
) Important
Autogenerated metadata doesn't work for localization so you need to update the
JSON file manually. To learn how to do this, see Manually create JSON metadata
for custom functions
) Important
Note that Excel custom functions are available on the following platforms.
Office on Windows
Microsoft 365 subscription
retail perpetual Office 2016 and later
Office on Mac
Office on the web
Office on iPad
volume-licensed perpetual versions of Office 2019 or earlier
The name and description appear in Excel and are localized. However, the id of each
function isn't localized. The id property is how Excel identifies your function as unique
and shouldn't be changed once it is set.
The following JSON shows how to define a function with the id property "MULTIPLY."
The name and description property of the function is localized for German. Each
parameter name and description is also localized for German.
JSON
{
"id": "MULTIPLY",
"name": "SUMME",
"description": "Summe zwei Zahlen",
"helpUrl": "http://www.contoso.com",
"result": {
"type": "number",
"dimensionality": "scalar"
},
"parameters": [
{
"name": "eins",
"description": "Erste Nummer",
"dimensionality": "scalar"
},
{
"name": "zwei",
"description": "Zweite Nummer",
"dimensionality": "scalar"
},
],
}
Compare the previous JSON with the following JSON for English.
JSON
{
"id": "MULTIPLY",
"name": "Multiply",
"description": "Multiplies two numbers",
"helpUrl": "http://www.contoso.com",
"result": {
"type": "number",
"dimensionality": "scalar"
},
"parameters": [
{
"name": "one",
"description": "first number",
"dimensionality": "scalar"
},
{
"name": "two",
"description": "second number",
"dimensionality": "scalar"
},
],
}
XML
<DefaultLocale>en-us</DefaultLocale>
...
<Resources>
<bt:Urls>
<bt:Url id="Contoso.Functions.Metadata.Url"
DefaultValue="https://localhost:3000/dist/functions.json"/>
<bt:Override Locale="de-de"
Value="https://localhost:3000/dist/functions-de.json" />
</bt:url>
</bt:Urls>
</Resources>
For more information on the process of localizing an add-in, see Localization for Office
Add-ins.
Next steps
Learn about naming conventions for custom functions or discover error handling best
practices.
See also
Manually create JSON metadata for custom functions
Autogenerate JSON metadata for custom functions
Create custom functions in Excel
Manually create JSON metadata for
custom functions
Article • 03/14/2023
As described in the custom functions overview article, a custom functions project must
include both a JSON metadata file and a script (either JavaScript or TypeScript) file to
register a function, making it available for use. Custom functions are registered when
the user runs the add-in for the first time and after that are available to the same user in
all workbooks.
) Important
Note that Excel custom functions are available on the following platforms.
Office on Windows
Microsoft 365 subscription
retail perpetual Office 2016 and later
Office on Mac
Office on the web
Office on iPad
volume-licensed perpetual versions of Office 2019 or earlier
We recommend using JSON autogeneration when possible instead of creating your own
JSON file. Autogeneration is less prone to user error and the yo office scaffolded files
already include this. For more information on JSDoc tags and the JSON autogeneration
process, see Autogenerate JSON metadata for custom functions.
However, you can make a custom functions project from scratch. This process requires
you to:
The following image explains the differences between using yo office scaffold files and
writing JSON from scratch.
7 Note
Remember to connect your manifest to the JSON file you create, through the
<Resources> section in your XML manifest file if you do not use the Yeoman
generator for Office Add-ins.
Ensure your XML manifest file references your JSON file in the <Resources> section,
similar to the following example.
JSON
<Resources>
<bt:Urls>
<bt:Url id="JSON-URL"
DefaultValue="https://subdomain.contoso.com/config/customfunctions.json"/>
<bt:Url id="JS-URL"
DefaultValue="https://subdomain.contoso.com/dist/win32/ship/index.win32.bund
le"/>
<bt:Url id="HTML-URL"
DefaultValue="https://subdomain.contoso.com/index.html"/>
</bt:Urls>
<bt:ShortStrings>
<bt:String id="namespace" DefaultValue="CONTOSO"/>
</bt:ShortStrings>
</Resources>
JSON
{
"allowCustomDataForDataTypeAny": true,
"allowErrorForDataTypeAny": true,
"functions": [
{
"id": "ADD",
"name": "ADD",
"description": "Add two numbers",
"helpUrl": "http://www.contoso.com/help",
"result": {
"type": "number",
"dimensionality": "scalar"
},
"parameters": [
{
"name": "first",
"description": "first number to add",
"type": "number",
"dimensionality": "scalar"
},
{
"name": "second",
"description": "second number to add",
"type": "number",
"dimensionality": "scalar"
}
]
},
{
"id": "GETDAY",
"name": "GETDAY",
"description": "Get the day of the week",
"helpUrl": "http://www.contoso.com/help",
"result": {
"dimensionality": "scalar"
},
"parameters": []
},
{
"id": "INCREMENTVALUE",
"name": "INCREMENTVALUE",
"description": "Count up from zero",
"helpUrl": "http://www.contoso.com/help",
"result": {
"dimensionality": "scalar"
},
"parameters": [
{
"name": "increment",
"description": "the number to be added each time",
"type": "number",
"dimensionality": "scalar"
}
],
"options": {
"stream": true,
"cancelable": true
}
},
{
"id": "SECONDHIGHEST",
"name": "SECONDHIGHEST",
"description": "Get the second highest number from a range",
"helpUrl": "http://www.contoso.com/help",
"result": {
"dimensionality": "scalar"
},
"parameters": [
{
"name": "range",
"description": "the input range",
"type": "number",
"dimensionality": "matrix"
}
]
}
]
}
7 Note
Metadata reference
allowCustomDataForDataTypeAny
The allowCustomDataForDataTypeAny property is a boolean data type. Setting this value
to true allows a custom function to accept data types as parameters and return values.
To learn more, see Custom functions and data types.
7 Note
allowErrorForDataTypeAny
The allowErrorForDataTypeAny property is a boolean data type. Setting the value to
true allows a custom function to process errors as input values. All parameters with the
type any or any[][] can accept errors as input values when allowErrorForDataTypeAny
is set to true . The default allowErrorForDataTypeAny value is false .
7 Note
functions
The functions property is an array of custom function objects. The following table lists
the properties of each object.
Property Data Required Description
type
description string No The description of the function that end users see in Excel.
For example, Converts a Celsius value to Fahrenheit.
helpUrl string No URL that provides information about the function. (It is
displayed in a task pane.) For example,
http://contoso.com/help/convertcelsiustofahrenheit.html .
id string Yes A unique ID for the function. This ID can only contain
alphanumeric characters and periods and should not be
changed after it is set.
name string Yes The name of the function that end users see in Excel. In Excel,
this function name is prefixed by the custom functions
namespace that's specified in the XML manifest file.
options object No Enables you to customize some aspects of how and when
Excel executes the function. See options for details.
parameters array Yes Array that defines the input parameters for the function. See
parameters for details.
result object Yes Object that defines the type of information that is returned
by the function. See result for details.
options
The options object enables you to customize some aspects of how and when Excel
executes the function. The following table lists the properties of the options object.
parameters
The parameters property is an array of parameter objects. The following table lists the
properties of each object.
name string Yes The name of the parameter. This name is displayed in
Excel's IntelliSense.
result
The result object defines the type of information that is returned by the function. The
following table lists the properties of the result object.
type string No The data type of the result. Can be boolean , number ,
string , or any (which allows you to use of any of the
previous three types). If this property is not specified, the
data type defaults to any .
JavaScript
/**
* Add two numbers
* @customfunction
* @param {number} first First number
* @param {number} second Second number
* @returns {number} The sum of the two numbers.
*/
function add(first, second) {
return first + second;
}
CustomFunctions.associate("ADD", add);
The following JSON shows the JSON metadata that is associated with the previous
custom function JavaScript code.
JSON
{
"functions": [
{
"description": "Add two numbers",
"id": "ADD",
"name": "ADD",
"parameters": [
{
"description": "First number",
"name": "first",
"type": "number"
},
{
"description": "Second number",
"name": "second",
"type": "number"
}
],
"result": {
"type": "number"
}
}
]
}
Keep in mind the following best practices when creating custom functions in your
JavaScript file and specifying corresponding information in the JSON metadata file.
In the JSON metadata file, ensure that the value of each id property contains only
alphanumeric characters and periods.
In the JSON metadata file, ensure that the value of each id property is unique
within the scope of the file. That is, no two function objects in the metadata file
should have the same id value.
Do not change the value of an id property in the JSON metadata file after it's
been associated with a corresponding JavaScript function name. You can change
the function name that end users see in Excel by updating the name property
within the JSON metadata file, but you should never change the value of an id
property after it's been established.
The following sample shows the JSON metadata that corresponds to the functions
defined in the preceding JavaScript code sample. The id and name property values are
in uppercase, which is a best practice when describing your custom functions. You only
need to add this JSON if you are preparing your own JSON file manually and not using
autogeneration. For more information on autogeneration, see Autogenerate JSON
metadata for custom functions.
JSON
{
"$schema": "https://developer.microsoft.com/json-schemas/office-js/custom-
functions.schema.json",
"functions": [
{
"id": "ADD",
"name": "ADD",
...
},
{
"id": "INCREMENT",
"name": "INCREMENT",
...
}
]
}
Next steps
Learn the best practices for naming your function or discover how to localize your
function using the previously described handwritten JSON method.
See also
Autogenerate JSON metadata for custom functions
Custom functions parameter options
Create custom functions in Excel
Return multiple results from your
custom function
Article • 12/08/2022
You can return multiple results from your custom function which will be returned to
neighboring cells. This behavior is called spilling. When your custom function returns an
array of results, it's known as a dynamic array formula. For more information on dynamic
array formulas in Excel, see Dynamic arrays and spilled array behavior .
The following image shows how the SORT function spills down into neighboring cells.
Your custom function can also return multiple results like this.
To create a custom function that is a dynamic array formula, it must return a two-
dimensional array of values. If the results spill into neighboring cells that already have
values, the formula will display a #SPILL! error.
Code samples
The first example shows how to return a dynamic array that spills down.
JavaScript
/**
* Get text values that spill down.
* @customfunction
* @returns {string[][]} A dynamic array with multiple results.
*/
function spillDown() {
return [['first'], ['second'], ['third']];
}
The second example shows how to return a dynamic array that spills right.
JavaScript
/**
* Get text values that spill to the right.
* @customfunction
* @returns {string[][]} A dynamic array with multiple results.
*/
function spillRight() {
return [['first', 'second', 'third']];
}
The third example shows how to return a dynamic array that spills both down and right.
JavaScript
/**
* Get text values that spill both right and down.
* @customfunction
* @returns {string[][]} A dynamic array with multiple results.
*/
function spillRectangle() {
return [
['apples', 1, 'pounds'],
['oranges', 3, 'pounds'],
['pears', 5, 'crates']
];
}
The fourth example shows how to return a dynamic spill array from a streaming
function. The results spill down, like the first example, and increment once a second
based on the amount parameter. To learn more about streaming functions, see Make a
streaming function.
JavaScript
/**
* Increment the cells with a given amount every second. Creates a dynamic
spilled array with multiple results
* @customfunction
* @param {number} amount The amount to add to the cell value on each
increment.
* @param {CustomFunctions.StreamingInvocation<number[][]>} invocation
Parameter to send results to Excel or respond to the user canceling the
function. A dynamic array.
*/
function increment(amount: number, invocation:
CustomFunctions.StreamingInvocation<number[][]>): void {
let firstResult = 0;
let secondResult = 1;
let thirdResult = 2;
invocation.onCanceled = () => {
clearInterval(timer);
};
}
See also
Dynamic arrays and spilled array behavior
Options for Excel custom functions
Authentication for custom functions
without a shared runtime
Article • 08/23/2022
In some scenarios, a custom function that doesn't use a shared runtime will need to
authenticate the user in order to access protected resources. Custom functions that
don't use a shared runtime run in a JavaScript-only runtime. Because of this, if the add-
in has a task pane, you'll need to pass data back and forth between the JavaScript-only
runtime and the HTML-supporting runtime used by the task pane. You do this by using
the OfficeRuntime.storage object and a special Dialog API.
) Important
Note that Excel custom functions are available on the following platforms.
Office on Windows
Microsoft 365 subscription
retail perpetual Office 2016 and later
Office on Mac
Office on the web
Office on iPad
volume-licensed perpetual versions of Office 2019 or earlier
7 Note
We recommend using custom functions with a shared runtime, unless you have a
specific reason not to use a shared runtime. Note that using a shared runtime
means your add-in will use WebView2 (Microsoft Edge Chromium-based) if
conditions are met, and otherwise your add-in will use Trident (Internet Explorer 11)
regardless of the Windows or Microsoft 365 version. For a description of the
WebView2 conditions, see Browsers and webview controls used by Office Add-ins.
For more information about runtimes, see Runtimes in Office Add-ins and
Runtimes.
OfficeRuntime.storage object
The JavaScript-only runtime doesn't have a localStorage object available on the global
window, where you typically store data. Instead, your code should share data between
custom functions and task panes by using OfficeRuntime.storage to set and get data.
Suggested usage
When you need to authenticate from a custom function add-in that doesn't use a
shared runtime, your code should check OfficeRuntime.storage to see if the access
token was already acquired. If not, use OfficeRuntime.displayWebDialog to authenticate
the user, retrieve the access token, and then store the token in OfficeRuntime.storage
for future use.
Dialog API
If a token doesn't exist, you should use the OfficeRuntime.dialog API to ask the user to
sign in. After a user enters their credentials, the resulting access token can be stored as
an item in OfficeRuntime.storage .
7 Note
The JavaScript-only runtime uses a dialog object that is slightly different from the
dialog object in the browser runtime used by task panes. They're both referred to
as the "Dialog API", but use OfficeRuntime.displayWebDialog to authenticate users
in the JavaScript-only runtime, not Office.ui.displayDialogAsync.
The following diagram outlines this basic process. The dotted line indicates that custom
functions and your add-in's task pane are both part of your add-in as a whole, though
they use separate runtimes.
If the custom function authenticates, then it receives the access token and will need to
store it in OfficeRuntime.storage . The following code sample shows how to call the
storage.setItem method to store a value. The storeValue function is a custom function
that stores a value from the user. You can modify this to store any token value you need.
JavaScript
/**
* Stores a key-value pair into OfficeRuntime.storage.
* @customfunction
* @param {string} key Key of item to put into storage.
* @param {*} value Value of item to put into storage.
*/
function storeValue(key, value) {
return OfficeRuntime.storage.setItem(key, value).then(function (result) {
return "Success: Item with key '" + key + "' saved to storage.";
}, function (error) {
return "Error: Unable to save item with key '" + key + "' to storage.
" + error;
});
}
When the task pane needs the access token, it can retrieve the token from the
OfficeRuntime.storage item. The following code sample shows how to use the
storage.getItem method to retrieve the token.
JavaScript
/**
* Read a token from storage.
* @customfunction GETTOKEN
*/
function receiveTokenFromCustomFunction() {
const key = "token";
const tokenSendStatus = document.getElementById('tokenSendStatus');
OfficeRuntime.storage.getItem(key).then(function (result) {
tokenSendStatus.value = "Success: Item with key '" + key + "' read from
storage.";
document.getElementById('tokenTextBox2').value = result;
}, function (error) {
tokenSendStatus.value = "Error: Unable to read item with key '" + key +
"' from storage. " + error;
});
}
General guidance
Office Add-ins are web-based and you can use any web authentication technique. There
is no particular pattern or method you must follow to implement your own
authentication with custom functions. You may wish to consult the documentation
about various authentication patterns, starting with this article about authorizing via
external services.
Avoid using the following locations to store data when developing custom functions:
localStorage : custom functions that don't use a shared runtime don't have access
to the global window object and therefore have no access to data stored in
localStorage .
Office.context.document.settings : This location isn't secure and information can
/**
* Function retrieves a cached token or opens a dialog box if there is no
saved token. Note that this isn't a sufficient example of authentication but
is intended to show the capabilities of the displayWebDialog method.
* @param {string} url URL for a stored token.
*/
function getTokenViaDialog(url) {
return new Promise (function (resolve, reject) {
if (_dialogOpen) {
// Can only have one dialog box open at once. Wait for previous dialog
box's token.
let timeout = 5;
let count = 0;
const intervalId = setInterval(function () {
count++;
if(_cachedToken) {
resolve(_cachedToken);
clearInterval(intervalId);
}
if(count >= timeout) {
reject("Timeout while waiting for token");
clearInterval(intervalId);
}
}, 1000);
} else {
_dialogOpen = true;
OfficeRuntime.displayWebDialog(url, {
height: '50%',
width: '50%',
onMessage: function (message, dialog) {
_cachedToken = message;
resolve(message);
dialog.close();
return;
},
onRuntimeError: function(error, dialog) {
reject(error);
},
}).catch(function (e) {
reject(e);
});
}
});
}
Next steps
Learn how to debug custom functions.
See also
JavaScript-only runtime for custom functions
Excel custom functions tutorial
JavaScript-only runtime
JavaScript-only runtime for custom
functions
Article • 08/23/2022
Custom functions that don't use a shared runtime use a JavaScript-only runtime that is
designed to optimize performance of calculations.
) Important
Note that Excel custom functions are available on the following platforms.
Office on Windows
Microsoft 365 subscription
retail perpetual Office 2016 and later
Office on Mac
Office on the web
Office on iPad
volume-licensed perpetual versions of Office 2019 or earlier
7 Note
We recommend using custom functions with a shared runtime, unless you have a
specific reason not to use a shared runtime. Note that using a shared runtime
means your add-in will use WebView2 (Microsoft Edge Chromium-based) if
conditions are met, and otherwise your add-in will use Trident (Internet Explorer 11)
regardless of the Windows or Microsoft 365 version. For a description of the
WebView2 conditions, see Browsers and webview controls used by Office Add-ins.
For more information about runtimes, see Runtimes in Office Add-ins and
Runtimes.
Be aware that custom functions must use additional security measures when making
XmlHttpRequests, requiring Same Origin Policy and simple CORS .
A simple CORS implementation cannot use cookies and only supports simple methods
(GET, HEAD, POST). Simple CORS accepts simple headers with field names Accept ,
Accept-Language , Content-Language . You can also use a Content-Type header in simple
CORS, provided that the content type is application/x-www-form-urlencoded ,
text/plain , or multipart/form-data .
one add-in.
The Storage object is a shared storage solution, meaning multiple parts of an add-in are
able to access the same data. For example, tokens for user authentication may be stored
in the Storage object because it can be accessed by both a custom function (using the
JavaScript-only runtime) and a task pane (using a full webview runtime). Similarly, if two
add-ins share the same domain (for example, www.contoso.com/addin1 ,
www.contoso.com/addin2 ), they are also permitted to share information back and forth
through the Storage object. Note that add-ins which have different subdomains will
have different instances of Storage (for example, subdomain.contoso.com/addin1 ,
differentsubdomain.contoso.com/addin2 ).
Because the Storage object can be a shared location, it is important to realize that it is
possible to override key-value pairs.
getItem
getItems
setItem
setItems
removeItem
removeItems
getKeys
7 Note
There's no method for clearing all information (such as clear ). Instead, you should
instead use removeItems to remove multiple entries at a time.
OfficeRuntime.storage example
The following code sample calls the OfficeRuntime.storage.setItem method to set a key
and value into storage .
JavaScript
Next steps
Learn how to debug custom functions.
See also
Authentication for custom functions without a shared runtime
Create custom functions in Excel
Custom functions tutorial
JavaScript-only runtime
Custom functions debugging
Article • 03/09/2023
This article discusses debugging only for custom functions that don't use a shared
runtime. To debug custom functions add-ins that use a shared runtime, see Configure
your Office Add-in to use a shared runtime: Debug.
) Important
Note that Excel custom functions are available on the following platforms.
Office on Windows
Microsoft 365 subscription
retail perpetual Office 2016 and later
Office on Mac
Office on the web
Office on iPad
volume-licensed perpetual versions of Office 2019 or earlier
7 Note
We recommend using custom functions with a shared runtime, unless you have a
specific reason not to use a shared runtime. Note that using a shared runtime
means your add-in will use WebView2 (Microsoft Edge Chromium-based) if
conditions are met, and otherwise your add-in will use Trident (Internet Explorer 11)
regardless of the Windows or Microsoft 365 version. For a description of the
WebView2 conditions, see Browsers and webview controls used by Office Add-ins.
For more information about runtimes, see Runtimes in Office Add-ins and
Runtimes.
Tip
The debugging techniques that are described in this article don't work with projects
that are created with the Office Add-in project containing the manifest only
option in the Yeoman generator. The scripts that are referred to later in this article
aren't installed with that option. To debug an add-in that is created with this
option, see the instructions in one of the following articles, as appropriate.
The process of debugging a custom function for add-ins that don't use a shared runtime
varies depending on the target platform (Windows, Mac, or web) and on whether you
are using Visual Studio Code or a different IDE. Use the links in the following table to
visit sections of this article that are relevant to your debugging scenario. In this table,
"CF-NSR" refers to custom functions in a non-shared runtime.
Excel on Use VS Code and the browser Debugging CF-NSR that are running in
Windows development tools Excel on Windows outside VS Code isn't
supported. Debug against Excel on the
web.
Excel on Use VS Code and the browser Use the command line tools
the web development tools
Excel on VS Code debugging of CF-NSR that are Use the command line tools
Mac running in Excel on Mac isn't
supported. Debug against Excel on the
web.
3. Open the Insert tab on the ribbon and, in the Add-ins section, choose Office Add-
ins.
4. On the Office Add-ins dialog, select the MY ADD-INS tab, choose Manage My
Add-ins, and then Upload My Add-in.
7 Note
Once you've sideloaded to the document, it will remain sideloaded each time you
open the document.
Start debugging
1. Open developer tools in the browser. For Chrome and most browsers F12 will open
the developer tools.
2. In developer tools, open your source code script file using Cmd+P or Ctrl+P
(functions.js or functions.ts).
3. Set a breakpoint in the custom function source code.
If you need to change the code you can make edits in VS Code and save the changes.
Refresh the browser to see the changes loaded.
1. From the command line run npm run watch to watch for and rebuild when code
changes occur.
2. Open a second command line window (the first one will be blocked while running
the watch.)
3. If you want to start your add-in in the desktop version of Excel, run the following
command.
Or if you prefer to start your add-in in Excel on the web run the following
command.
npm run start:web -- --document {url} (where {url} is the URL of an Excel file on
OneDrive or SharePoint)
7 Note
If you are developing on a Mac, enclose the {url} in single quotation marks.
Do not do this on Windows.
If your add-in doesn't sideload in the document, follow the steps in Sideload your
add-in to sideload your add-in. Then continue to the next section to start
debugging.
4. Open developer tools in the browser. For Chrome and most browsers F12 will open
the developer tools.
5. In developer tools, open your source code script file (functions.js or functions.ts).
Your custom functions code may be located near the end of the file.
6. In the custom function source code, apply a breakpoint by selecting a line of code.
If you need to change the code you can make edits in Visual Studio and save the
changes. Refresh the browser to see the changes loaded.
npm run watch : builds for development and automatically rebuilds when a source
file is saved
npm run build-dev : builds for development once
You can use the following tasks to start debugging on desktop or online.
npm run start:desktop : Starts Excel on desktop and sideloads your add-in.
npm run start:web -- --document {url} (where {url} is the URL of an Excel file on
OneDrive or SharePoint): Starts Excel on the web and sideloads your add-in.
7 Note
If you are developing on a Mac, enclose the {url} in single quotation marks.
Do not do this on Windows.
Next steps
Learn about Authentication for custom functions without a shared runtime.
See also
Custom functions troubleshooting
Error handling for custom functions in Excel
Create custom functions in Excel
JavaScript-only runtime
Volatile values in functions
Article • 03/22/2022
Volatile functions are functions in which the value changes each time the cell is
calculated. The value can change even if none of the function's arguments change.
These functions recalculate every time Excel recalculates. For example, imagine a cell
that calls the function NOW . Every time NOW is called, it will automatically return the
current date and time.
) Important
Note that Excel custom functions are available on the following platforms.
Office on Windows
Microsoft 365 subscription
retail perpetual Office 2016 and later
Office on Mac
Office on the web
Office on iPad
volume-licensed perpetual versions of Office 2019 or earlier
Excel contains several built-in volatile functions, such as RAND and TODAY . For a
comprehensive list of Excel's volatile functions, see Volatile and Non-Volatile Functions.
Custom functions allow you to create your own volatile functions, which may be useful
when handling dates, times, random numbers, and modeling. For example, Monte Carlo
simulations require the generation of random inputs to determine an optimal
solution.
If choosing to autogenerate your JSON file, declare a volatile function with the JSDoc
comment tag @volatile . From more information on autogeneration, see Autogenerate
JSON metadata for custom functions.
/**
* Simulates rolling a 6-sided dice.
* @customfunction
* @volatile
*/
function roll6sided() {
return Math.floor(Math.random() * 6) + 1;
}
Next steps
Learn about custom functions parameter options.
See also
Manually create JSON metadata for custom functions
Create custom functions in Excel
Receive and handle data with custom
functions
Article • 04/13/2023
One of the ways that custom functions enhances Excel's power is by receiving data from
locations other than the workbook, such as the web or a server (through WebSockets ).
You can request external data through an API like Fetch or by using XmlHttpRequest
(XHR) , a standard web API that issues HTTP requests to interact with servers.
) Important
Note that Excel custom functions are available on the following platforms.
Office on Windows
Microsoft 365 subscription
retail perpetual Office 2016 and later
Office on Mac
Office on the web
Office on iPad
volume-licensed perpetual versions of Office 2019 or earlier
Fetch example
In the following code sample, the webRequest function reaches out to a hypothetical
external API that tracks the number of people currently on the International Space
Station. The function returns a JavaScript Promise and uses fetch to request
information from the hypothetical API. The resulting data is transformed into JSON and
the names property is converted into a string, which is used to resolve the promise.
When developing your own functions, you may want to perform an action if the web
request does not complete in a timely manner or consider batching up multiple API
requests.
JS
/**
* Requests the names of the people currently on the International Space
Station.
* Note: This function requests data from a hypothetical URL. In practice,
replace the URL with a data source for your scenario.
* @customfunction
*/
function webRequest() {
let url = "https://www.contoso.com/NumberOfPeopleInSpace"; // This is a
hypothetical URL.
return new Promise(function (resolve, reject) {
fetch(url)
.then(function (response){
return response.json();
}
)
.then(function (json) {
resolve(JSON.stringify(json.names));
})
})
}
7 Note
Using fetch avoids nested callbacks and may be preferable to XHR in some cases.
XHR example
In the following code sample, the getStarCount function calls the Github API to discover
the amount of stars given to a particular user's repository. This is an asynchronous
function which returns a JavaScript Promise . When data is obtained from the web call,
the promise is resolved which returns the data to the cell.
TS
/**
* Gets the star count for a given Github organization or user and
repository.
* @customfunction
* @param userName string name of organization or user.
* @param repoName string name of the repository.
* @return number of stars.
*/
async function getStarCount(userName: string, repoName: string) {
if (xhttp.status == 200) {
resolve(JSON.parse(xhttp.responseText).watchers_count);
} else {
reject({
status: xhttp.status,
statusText: xhttp.statusText
});
}
};
xhttp.send();
});
}
To declare a streaming function, you can use either of the following two options.
The @streaming JSDoc tag.
The CustomFunctions.StreamingInvocation invocation parameter.
The following code sample is a custom function that adds a number to the result every
second. Note the following about this code.
Excel displays each new value automatically using the setResult method.
The second input parameter, invocation , is not displayed to end users in Excel
when they select the function from the autocomplete menu.
The onCanceled callback defines the function that runs when the function is
canceled.
Streaming isn't necessarily tied to making a web request. In this case, the function
isn't making a web request but is still getting data at set intervals, so it requires the
use of the streaming invocation parameter.
JS
/**
* Increments a value once a second.
* @customfunction INC increment
* @param {number} incrementBy Amount to increment
* @param {CustomFunctions.StreamingInvocation<number>} invocation
*/
function increment(incrementBy, invocation) {
let result = 0;
const timer = setInterval(() => {
result += incrementBy;
invocation.setResult(result);
}, 1000);
invocation.onCanceled = () => {
clearInterval(timer);
};
}
7 Note
For an example of how to return a dynamic spill array from a streaming function,
see Return multiple results from your custom function: Code samples.
Cancel a function
Excel cancels the execution of a function in the following situations.
When the user edits or deletes a cell that references the function.
When one of the arguments (inputs) for the function changes. In this case, a new
function call is triggered following the cancellation.
When the user triggers recalculation manually. In this case, a new function call is
triggered following the cancellation.
You can also consider setting a default streaming value to handle cases when a request
is made but you are offline.
7 Note
There is also a category of functions called cancelable functions which use the
@cancelable JSDoc tag. Cancelable functions allow a web request to be terminated
A streaming function can't use the @cancelable tag, but streaming functions can
include an onCanceled callback function. Only asynchronous custom functions
which return one value can use the @cancelable JSDoc tag. See Autogenerate
JSON metadata: @cancelable to learn more about the @cancelable tag.
and allows you to use the setResult method and onCanceled event to define what a
function does when it streams ( setResult ) or is canceled ( onCanceled ).
See Invocation parameter to learn about other potential uses of the invocation
argument and how it corresponds with the Invocation object.
JavaScript
ws.onmessage(message) {
console.log(`Received: ${message}`);
}
ws.onerror(error){
console.err(`Failed: ${error}`);
}
Next steps
Learn about different parameter types your functions can use.
Discover how to batch multiple API calls.
See also
Volatile values in functions
Create JSON metadata for custom functions
Manually create JSON metadata for custom functions
Create custom functions in Excel
Excel custom functions tutorial
Troubleshoot custom functions
Article • 03/09/2023
When developing custom functions, you may encounter errors in the product while
creating and testing your functions.
) Important
Note that Excel custom functions are available on the following platforms.
Office on Windows
Microsoft 365 subscription
retail perpetual Office 2016 and later
Office on Mac
Office on the web
Office on iPad
volume-licensed perpetual versions of Office 2019 or earlier
To resolve issues, you can enable runtime logging to capture errors and refer to Excel's
native error messages. Also, check for common mistakes such as leaving promises
unresolved.
To debug custom functions add-ins that don't use a shared runtime, see Custom
functions debugging.
Generally, these errors correspond to the errors you might already be familiar with in
Excel. The are only a few exceptions specific to custom functions, listed here:
A #NAME error generally means there has been an issue registering your functions.
A #N/A error is also maybe a sign that that function while registered could not be
run. This is typically due to a missing CustomFunctions.associate command.
A #VALUE error typically indicates an error in the functions' script file.
A #REF! error may indicate that your function name is the same as a function
name in an add-in that already exists.
The following example shows an add function, followed by the function's name add
being associated with the corresponding JSON id ADD .
JavaScript
/**
* Add two numbers.
* @customfunction
* @param {number} first First number.
* @param {number} second Second number.
* @returns {number} The sum of the two numbers.
*/
function add(first, second) {
return first + second;
}
CustomFunctions.associate("ADD", add);
For more information on this process, see Associating function names with JSON
metadata.
Known issues
Known issues are tracked and reported in the Excel Custom Functions GitHub
repository .
Reporting feedback
If you are encountering issues that aren't documented here, let us know. There are two
ways to report issues.
In Github
Feel free to submit an issue you encounter either through the "Content feedback"
feature at the bottom of any documentation page, or by filing a new issue directly to the
custom functions repository .
Next steps
Learn how to make your custom functions compatible with XLL user-defined functions.
See also
Autogenerate JSON metadata for custom functions
Create custom functions in Excel
Custom functions debugging
OneNote add-ins documentation
With OneNote add-ins, you can use familiar web technologies such as HTML, CSS, and
JavaScript to build a solution that can run in OneNote on the web. Learn how to build,
test, debug, and publish OneNote add-ins.
e OVERVIEW
f QUICKSTART
c HOW-TO GUIDE
Use the OneNote JavaScript API to interact with objects and notebook content
e OVERVIEW
p CONCEPT
Reso rces
Resources
i REFERENCE
Ask questions
Request features
Report issues
OneNote introduces a JavaScript API for OneNote add-ins on the web. You can create
task pane add-ins, content add-ins, and add-in commands that interact with OneNote
objects and connect to web services or other web-based resources.
7 Note
If you plan to publish your add-in to AppSource and make it available within the
Office experience, make sure that you conform to the Commercial marketplace
certification policies. For example, to pass validation, your add-in must work across
all platforms that support the methods that you define (for more information, see
section 1120.3 and the Office Add-in application and availability page).
An XML manifest that specifies the URL of the add-in's webpage and any access
requirements, settings, and capabilities for the add-in. This file is stored on the
client. OneNote add-ins use the same manifest format as other Office Add-ins.
A Common API that's shared across Office applications, accessed through the
Document object.
2. Create a proxy that represents the OneNote object you want to work with. You
interact synchronously with proxy objects by reading and writing their properties
and calling their methods.
3. Call load on the proxy to fill it with the property values specified in the parameter.
This call is added to the queue of commands.
7 Note
queue.
4. Call context.sync to run all queued commands in the order that they were
queued. This synchronizes the state between your running script and the real
objects, and by retrieving properties of loaded OneNote objects for use in your
script. You can use the returned promise object for chaining additional actions.
For example:
JavaScript
See Using the application-specific API model to learn more about the load / sync
pattern and other common practices in the OneNote JavaScript APIs.
You can find supported OneNote objects and operations in the API reference.
For example:
JavaScript
function getSelectionFromPage() {
Office.context.document.getSelectedDataAsync(
Office.CoercionType.Text,
{ valueFormat: "unformatted" },
function (asyncResult) {
const error = asyncResult.error;
if (asyncResult.status === Office.AsyncResultStatus.Failed) {
console.log(error.message);
}
else $('#input').val(asyncResult.value);
});
}
API Notes
Office.context.document.setSelectedDataAsync Office.CoercionType.Text ,
Office.CoercionType.Image , and
Office.CoercionType.Html only
Office.EventType.DocumentSelectionChanged None.
In general, you use the Common API to do something that isn't supported in the
application-specific API. To learn more about using the Common API, see Common
JavaScript API object model.
OneNote object model diagram
The following diagram represents what's currently available in the OneNote JavaScript
API.
See also
Developing Office Add-ins
Learn about Microsoft 365 Developer Program
Build your first OneNote add-in
OneNote JavaScript API reference
Rubric Grader sample
Office Add-ins platform overview
Build your first OneNote task pane add-
in
Article • 05/02/2023
In this article, you'll walk through the process of building a OneNote task pane add-in.
Prerequisites
7 Note
If you aren't familiar with Node.js or npm, you should start by setting up your
development environment.
The latest version of Yeoman and the Yeoman generator for Office Add-ins. To
install these tools globally, run the following command via the command prompt.
command line
7 Note
command line
yo office
7 Note
When you run the yo office command, you may receive prompts about the data
collection policies of Yeoman and the Office Add-in CLI tools. Use the information
that's provided to respond to the prompts as you see fit.
When prompted, provide the following information to create your add-in project.
After you complete the wizard, the generator creates the project and installs supporting
Node components.
Tip
You can ignore the next steps guidance that the Yeoman generator provides after
the add-in project's been created. The step-by-step instructions within this article
provide all of the guidance you'll need to complete this tutorial.
The ./manifest.xml file in the root directory of the project defines the settings and
capabilities of the add-in.
The ./src/taskpane/taskpane.html file contains the HTML markup for the task
pane.
The ./src/taskpane/taskpane.css file contains the CSS that's applied to content in
the task pane.
The ./src/taskpane/taskpane.js file contains the Office JavaScript API code that
facilitates interaction between the task pane and the Office client application.
JavaScript
try {
await OneNote.run(async (context) => {
Try it out
1. Navigate to the root folder of the project.
command line
2. Start the local web server. Run the following command in the root directory of your
project.
command line
7 Note
Office Add-ins should use HTTPS, not HTTP, even while you're developing. If
you're prompted to install a certificate after you run one of the following
commands, accept the prompt to install the certificate that the Yeoman
generator provides. You may also have to run your command prompt or
terminal as an administrator for the changes to be made.
4. Choose Insert > Office Add-ins to open the Office Add-ins dialog.
If you're signed in with your consumer account, select the MY ADD-INS tab,
and then choose Upload My Add-in.
The following image shows the MY ADD-INS tab for consumer notebooks.
5. In the Upload Add-in dialog, browse to manifest.xml in your project folder, and
then choose Upload.
6. From the Home tab, choose the Show Taskpane button on the ribbon. The add-in
task pane opens in an iFrame next to the OneNote page.
7. At the bottom of the task pane, choose the Run link to set the page title and add
an outline to the body of the page.
Next steps
Congratulations, you've successfully created a OneNote task pane add-in! Next, learn
more about the core concepts of building OneNote add-ins.
See also
Office Add-ins platform overview
Develop Office Add-ins
OneNote JavaScript API programming overview
OneNote JavaScript API reference
Rubric Grader sample
Using Visual Studio Code to publish
OneNote JavaScript API overview
Article • 05/02/2023
A OneNote add-in interacts with objects in OneNote on the web by using the Office
JavaScript API, which includes two JavaScript object models:
OneNote JavaScript API: These are the application-specific APIs for OneNote.
Introduced with Office 2016, the OneNote JavaScript API provides strongly-typed
objects that you can use to access objects in OneNote on the web.
Common APIs: Introduced with Office 2013, the Common API can be used to
access features such as UI, dialogs, and client settings that are common across
multiple types of Office applications.
This section of the documentation focuses on the OneNote JavaScript API, which you'll
use to develop the majority of functionality in add-ins that target OneNote on the web.
For information about the Common API, see Common JavaScript API object model.
For detailed information about the OneNote JavaScript API object model, see the
OneNote JavaScript API reference documentation.
See also
OneNote add-ins documentation
OneNote add-ins overview
OneNote JavaScript API reference
Office client application and platform availability for Office Add-ins
onenote package
Reference
Classes
OneNote.Application Represents the top-level object that contains all globally
addressable OneNote objects such as notebooks, the active
notebook, and the active section.
OneNote.InkAnalysis Represents ink analysis data for a given set of ink strokes.
OneNote.InkAnalysisLine Represents ink analysis data for an identified text line formed by
ink strokes.
OneNote.InkAnalysisWord Represents ink analysis data for an identified word formed by ink
strokes.
OneNote.RequestContext
Interfaces
OneNote.ImageOcrData Represents data obtained by OCR (optical character recognition)
of an image.
OneNote.InkStrokePointer Weak reference to an ink stroke object and its content parent.
OneNote.Interfaces. An interface for updating data on the Application object, for use
ApplicationUpdateData in application.set({ ... }) .
OneNote.Interfaces.Image An interface for updating data on the Image object, for use in
UpdateData image.set({ ... }) .
OneNote.Interfaces.Ink Represents ink analysis data for an identified text line formed by
AnalysisLineLoadOptions ink strokes.
OneNote.Interfaces.Ink Represents ink analysis data for a given set of ink strokes.
AnalysisLoadOptions
OneNote.Interfaces.Ink An interface for updating data on the InkAnalysis object, for use
AnalysisUpdateData in inkAnalysis.set({ ... }) .
OneNote.Interfaces.Ink Represents ink analysis data for an identified word formed by ink
AnalysisWordLoadOptions strokes.
OneNote.Interfaces.Page An interface for updating data on the Page object, for use in
UpdateData page.set({ ... }) .
OneNote.Interfaces.Paragraph An interface for updating data on the Paragraph object, for use
UpdateData in paragraph.set({ ... }) .
OneNote.Interfaces.TableCell An interface for updating data on the TableCell object, for use in
UpdateData tableCell.set({ ... }) .
OneNote.Interfaces.Table An interface for updating data on the Table object, for use in
UpdateData table.set({ ... }) .
OneNote.EventType
OneNote.InsertLocation
OneNote.ListType
OneNote.NoteTagStatus
OneNote.NoteTagType
OneNote.NumberType
OneNote.PageContentType
OneNote.ParagraphStyle
OneNote.ParagraphType
Functions
OneNote.run(batch) Executes a batch script that performs actions on the OneNote
object model, using a new request context. When the promise is
resolved, any tracked objects that were automatically allocated
during execution will be released.
OneNote.run(object, batch) Executes a batch script that performs actions on the OneNote
object model, using the request context of a previously-created
API object.
OneNote.run(objects, batch) Executes a batch script that performs actions on the OneNote
object model, using the request context of previously-created
API objects.
Function Details
OneNote.run(batch)
Executes a batch script that performs actions on the OneNote object model, using a
new request context. When the promise is resolved, any tracked objects that were
automatically allocated during execution will be released.
TypeScript
Parameters
batch (context: OneNote.RequestContext) => Promise<T>
A function that takes in an OneNote.RequestContext and returns a promise (typically,
just the result of "context.sync()"). The context parameter facilitates requests to the
OneNote application. Since the Office add-in and the OneNote application run in
two different processes, the request context is required to get access to the OneNote
object model from the add-in.
Returns
Promise<T>
OneNote.run(object, batch)
Executes a batch script that performs actions on the OneNote object model, using
the request context of a previously-created API object.
TypeScript
Parameters
object OfficeExtension.ClientObject
A previously-created API object. The batch will use the same request context as the
passed-in object, which means that any changes applied to the object will be picked
up by "context.sync()".
Returns
Promise<T>
OneNote.run(objects, batch)
Executes a batch script that performs actions on the OneNote object model, using
the request context of previously-created API objects.
TypeScript
Parameters
objects OfficeExtension.ClientObject[]
Returns
Promise<T>
Work with OneNote page content
Article • 03/22/2022
In the OneNote add-ins JavaScript API, page content is represented by the following
object model.
Section.addPage
Page.insertPageAsSibling
Then use methods in the following objects to work with the page content, such as
Page.addOutline and Outline.appendHtml .
Page
Outline
Paragraph
The content and structure of a OneNote page are represented by HTML. Only a subset
of HTML is supported for creating or updating page content, as described below.
Supported HTML
The OneNote add-in JavaScript API supports the following HTML for creating and
updating page content.
<p>
<img>
<a>
7 Note
OneNote does its best to translate HTML into page content while ensuring security for
users. HTML and CSS standards do not exactly match OneNote's content model, so
there will be differences in appearances, particularly with CSS stylings. We recommend
using the JavaScript objects if specific formatting is needed.
See also
OneNote JavaScript API programming overview
OneNote JavaScript API reference
Rubric Grader sample
Office Add-ins platform overview
Outlook add-ins documentation
With Outlook add-ins, you can use familiar web technologies such as HTML, CSS, and
JavaScript to build a solution that can run in Outlook across multiple platforms,
including on the web, Windows, Mac, and iOS. Learn how to build, test, debug, and
publish Outlook add-ins.
e OVERVIEW
f QUICKSTART
Build your first Outlook add-in with a unified manifest for Microsoft 365 (preview)
c HOW-TO GUIDE
e OVERVIEW
p CONCEPT
Resources
i REFERENCE
Ask questions
Request features
Report issues
Outlook add-ins are integrations built by third parties into Outlook by using our web-
based platform. Outlook add-ins have three key aspects:
The same add-in and business logic works across desktop (Outlook on Windows
and Mac), web (Microsoft 365 and Outlook.com), and mobile.
Outlook add-ins consist of a manifest, which describes how the add-in integrates
into Outlook (for example, a button or a task pane), and JavaScript/HTML code,
which makes up the UI and business logic of the add-in.
Outlook add-ins can be acquired from AppSource or sideloaded by end-users or
administrators.
Outlook add-ins are different from COM or VSTO add-ins, which are older integrations
specific to Outlook running on Windows. Unlike COM add-ins, Outlook add-ins don't
have any code physically installed on the user's device or Outlook client. For an Outlook
add-in, Outlook reads the manifest and hooks up the specified controls in the UI, and
then loads the JavaScript and HTML. The web components all run in the context of a
browser or webview control in a sandbox.
) Important
COM and VSTO add-ins aren't supported in the new Outlook on Windows that's
currently in preview. These add-ins are still supported in the classic Outlook on
Windows desktop client. To learn more, see Develop Outlook add-ins for new
Outlook on Windows (preview).
The Outlook items that support add-ins include email messages, meeting requests,
responses and cancellations, and appointments. Each Outlook add-in defines the
context in which it is available, including the types of items and if the user is reading or
composing an item.
7 Note
If you plan to publish your add-in to AppSource and make it available within the
Office experience, make sure that you conform to the Commercial marketplace
certification policies. For example, to pass validation, your add-in must work across
all platforms that support the methods that you define (for more information, see
section 1120.3 and the Office Add-in application and availability page).
Extension points
Extension points are the ways that add-ins integrate with Outlook. The following are the
ways this can be done.
Add-ins can declare buttons that appear in command surfaces across messages
and appointments. For more information, see Add-in commands.
Add-ins can link off regular expression matches or detected entities in messages
and appointments. For more information, see Contextual Outlook add-ins.
) Important
) Important
* Support for delegate access scenarios (for example, folders shared from
another user's mailbox) was introduced in requirement set 1.8, while shared
mailbox support was introduced in requirement set 1.13. To learn more, see
Enable shared folders and shared mailbox scenarios.
Created through Simple MAPI. Simple MAPI is used when an Office user creates or
sends an email from an Office application on Windows while Outlook is closed. For
example, a user can create an Outlook email while working in Word which triggers
an Outlook compose window without launching the full Outlook application. If,
however, Outlook is already running when the user creates the email from Word,
that isn't a Simple MAPI scenario so Outlook add-ins work in the compose form as
long as other activation requirements are met.
In general, Outlook can activate add-ins in read form for items in the Sent Items folder,
with the exception of add-ins that activate based on string matches of well-known
entities. For more information about the reasons behind this, see Support for well-
known entities.
Currently, there are additional considerations when designing and implementing add-
ins for mobile clients. To learn more, see Add support for add-in commands in Outlook
on mobile devices.
Supported clients
Outlook add-ins are supported in Outlook on Windows, Outlook on Mac, Outlook on
the web, Outlook on iOS, Outlook on Android, and Outlook.com. Not all of the newest
features are supported in all clients at the same time. Please refer to articles and API
references for those features to see which applications they may or may not be
supported in.
See also
Learn about the Microsoft 365 Developer Program
Best practices for developing Office Add-ins
Design guidelines for Office Add-ins
License your Office and SharePoint Add-ins
Publish your Office Add-in
Make your solutions available in AppSource and within Office
Build your first Outlook add-in
Article • 03/28/2023
In this article, you'll walk through the process of building an Outlook task pane add-in
that displays at least one property of a selected message.
Yeoman generator
Prerequisites
7 Note
If you aren't familiar with Node.js or npm, you should start by setting up your
development environment.
The latest version of Yeoman and the Yeoman generator for Office Add-ins.
To install these tools globally, run the following command via the command
prompt.
command line
7 Note
command line
yo office
7 Note
When you run the yo office command, you may receive prompts about
the data collection policies of Yeoman and the Office Add-in CLI tools.
Use the information that's provided to respond to the prompts as you
see fit.
Tip
You can ignore the next steps guidance that the Yeoman generator
provides after the add-in project's been created. The step-by-step
instructions within this article provide all of the guidance you'll need to
complete this tutorial.
command line
The ./manifest.xml file in the root directory of the project defines the settings
and capabilities of the add-in.
The ./src/taskpane/taskpane.html file contains the HTML markup for the task
pane.
The ./src/taskpane/taskpane.css file contains the CSS that's applied to
content in the task pane.
The ./src/taskpane/taskpane.js file contains the Office JavaScript API code
that facilitates interaction between the task pane and Outlook.
Update the code
1. Open your project in VS Code or your preferred code editor.
Tip
On Windows, you can navigate to the root directory of the project via the
command line and then enter code . to open that folder in VS Code. On
Mac, you'll need to add the code command to the path before you
can use that command to open the project folder in VS Code.
HTML
3. In your code editor, open the file ./src/taskpane/taskpane.js, then add the
following code to the run function. This code uses the Office JavaScript API to
get a reference to the current message and write its subject property value to
the task pane.
JavaScript
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the MIT license.
* See LICENSE in the project root for license information.
*/
Office.onReady((info) => {
if (info.host === Office.HostType.Outlook) {
document.getElementById("sideload-msg").style.display = "none";
document.getElementById("app-body").style.display = "flex";
document.getElementById("run").onclick = run;
}
});
Try it out
7 Note
Office Add-ins should use HTTPS, not HTTP, even while you're developing. If
you're prompted to install a certificate after you run one of the following
commands, accept the prompt to install the certificate that the Yeoman
generator provides. You may also have to run your command prompt or
terminal as an administrator for the changes to be made.
1. Run the following command in the root directory of your project. When you
run this command, the local web server starts and your add-in will be
sideloaded.
command line
npm start
2. In Outlook, view a message in the Reading Pane , or open the message in its
own window.
3. Choose the Home tab (or the Message tab if you opened the message in a
new window), and then choose the Show Taskpane button on the ribbon to
open the add-in task pane.
7 Note
If you receive the error "We can't open this add-in from localhost" in the
task pane, follow the steps outlined in the troubleshooting article.
4. When prompted with the WebView Stop On Load dialog box, select OK.
7 Note
If you select Cancel, the dialog won't be shown again while this instance
of the add-in is running. However, if you restart your add-in, you'll see
the dialog again.
5. Scroll to the bottom of the task pane and choose the Run link to write the
message subject to the task pane.
Next steps
Congratulations, you've successfully created your first Outlook task pane add-in!
Next, learn more about the capabilities of an Outlook add-in and build a more
complex add-in by following along with the Outlook add-in tutorial.
See also
Using Visual Studio Code to publish
Build an Outlook add-in with the unified
manifest for Microsoft 365 (preview)
Article • 08/10/2023
There are two tools that you can use to create an Outlook Add-in project that uses the
unified manifest for Microsoft 365. This article describes how to do it with the Yeoman
generator for Office (also called "Yo Office"). Alternatively, you can create an Outlook
add-in project with the Teams Toolkit as described at Create Office Add-in projects with
Teams Toolkit (preview).
In this article, you'll walk through the process of building an Outlook task pane add-in
that displays a property of a selected message, triggers a notification on the reading
pane, and inserts text into a message on the compose pane. This add-in will use a
preview version of the unified, JSON-formatted manifest that Teams extensions, like
custom tabs and messaging extensions, use. For more information about this manifest,
see Unified manifest for Microsoft 365 (preview).
7 Note
The new manifest is available for preview and is supported only on Outlook for
Windows. It is subject to change based on feedback. We encourage experienced
add-in developers to experiment with it. The preview manifest should not be used
in production add-ins.
The preview is only supported in Office downloaded from a Microsoft 365 subscription
and installed on Windows.
Tip
If you want to build an Outlook add-in using the XML manifest, see Build your first
Outlook add-in.
7 Note
If you aren't familiar with Node.js or npm, you should start by setting up your
development environment.
.NET runtime for Windows. One of the tools used in the preview runs on .NET.
The latest version of Yeoman and the Yeoman generator for Office Add-ins. To
install these tools globally, run the following command via the command prompt.
command line
7 Note
command line
yo office
7 Note
When you run the yo office command, you may receive prompts about the
data collection policies of Yeoman and the Office Add-in CLI tools. Use the
information that's provided to respond to the prompts as you see fit.
When prompted, provide the following information to create your add-in project.
What do you want to name your add-in? - Add-in with Unified Manifest
7 Note
For this preview, the add-in name cannot be more than 30 characters.
After you complete the wizard, the generator will create the project and install
supporting Node components.
Tip
You can ignore the next steps guidance that the Yeoman generator provides
after the add-in project's been created. The step-by-step instructions within
this article provide all of the guidance you'll need to complete this tutorial.
command line
The ./manifest/manifest.json file in the root directory of the project defines the
settings and capabilities of the add-in.
The ./src/taskpane/taskpane.html file contains the HTML markup for the task
pane.
The ./src/taskpane/taskpane.css file contains the CSS that's applied to content in
the task pane.
The ./src/taskpane/taskpane.ts file contains code that calls the Office JavaScript
library to facilitate interaction between the task pane and Outlook.
The ./src/command/command.html file will be edited by WebPack at build time to
insert an HTML <script> tag that loads the JavaScript file that is transpiled from
the command.ts file.
The ./src/command/command.ts file has little code in it at first. Later in this article,
you'll add code to it that calls the Office JavaScript library and that executes when
a custom ribbon button is selected.
Tip
On Windows, you can navigate to the root directory of the project via the
command line and then enter code . to open that folder in VS Code.
HTML
7 Note
Office Add-ins should use HTTPS, not HTTP, even while you're developing. If you're
prompted to install a certificate after you run one of the following commands,
accept the prompt to install the certificate that the Yeoman generator provides. You
may also have to run your command prompt or terminal as an administrator for the
changes to be made.
command line
npm start
7 Note
If this is the first time you've created an add-in on the computer, or the first
time in over a month, you'll be prompted to install security certificates.
2. Use the classic ribbon in Outlook. The remainder of these instructions assume this.
3. View a message in the Reading Pane , or open the message in its own window. A
new control group named Contoso Add-in appears on the Outlook Home tab (or
the Message tab if you opened the message in a new window). The group has a
button named Show Taskpane and one named Perform an action.
5. When prompted with the WebView Stop On Load dialog box, select OK.
7 Note
If you select Cancel, the dialog won't be shown again while this instance of
the add-in is running. However, if you restart your add-in, you'll see the dialog
again.
7 Note
If you receive the error "We can't open this add-in from localhost" in the task
pane, follow the steps outlined in the troubleshooting article.
7. When prompted with the WebView Stop On Load dialog box, select OK.
7 Note
If you select Cancel, the dialog won't be shown again while this instance of
the add-in is running. However, if you restart your add-in, you'll see the dialog
again.
8. Scroll to the bottom of the task pane and choose the Run link to copy the
message's subject to the task pane.
command line
npm stop
) Important
Closing the web server window doesn't reliably shut down the web server. If it
isn't properly shut down, you'll encounter problems as you change and rerun
the project.
Tip
On Windows, you can navigate to the root directory of the project via the
command line and then enter code . to open that folder in VS Code.
2. In your code editor, open the file ./src/command/command.ts and add the
following code to the end of the file. This function will insert Hello World at the
cursor point in message body.
TypeScript
7 Note
When referring to nested JSON properties, this article uses dot notation.
When an item in an array is referenced, the bracketed zero-based number of
the item is used.
5. When an add-in command runs code instead of opening a task pane, it must run
the code in a runtime that is separate from the embedded webview where the task
pane code runs. So the manifest must specify an additional runtime. Scroll to the
property extension.runtimes and add the following object to the runtimes array.
Be sure to put a comma after the object that is already in the array. Note the
following about this markup.
The value of the actions[0].id property must be exactly the same as the
name of the function that you added to the commands.ts file, in this case
insertHelloWorld . In a later step, you'll refer to the item by this ID.
JSON
{
"id": "ComposeCommandsRuntime",
"type": "general",
"code": {
"page": "https://localhost:3000/commands.html",
"script": "https://localhost:3000/commands.js"
},
"lifetime": "short",
"actions": [
{
"id": "insertHelloWorld",
"type": "executeFunction",
"displayName": "insertHelloWorld"
}
]
}
6. The Show Taskpane button appears when the user is reading an email, but the
button for adding text should only appear when the user is composing a new
email (or replying to one). So the manifest must specify a new ribbon object. Scroll
to the property extension.ribbons and add the following object to the ribbons
array. Be sure to put a comma after the object that is already in the array. Note the
following about this JSON:
The only value in the contexts array is "mailCompose", so the button will
appear when in a compose (or reply) window but not in a message read
window where the Show Taskpane and Perform an action buttons appear.
Compare this value with the contexts array in the existing ribbon object,
whose value is ["mailRead"] .
The value of the tabs[0].groups[0].controls[0].actionId must be exactly
the same as the value of actions[0].id property in the runtime object you
created in an earlier step.
JSON
{
"contexts": ["mailCompose"],
"tabs": [
{
"builtInTabId": "TabDefault",
"groups": [
{
"id": "msgWriteGroup",
"label": "Contoso Add-in",
"icons": [
{ "size": 16, "file":
"https://localhost:3000/assets/icon-16.png" },
{ "size": 32, "file":
"https://localhost:3000/assets/icon-32.png" },
{ "size": 80, "file":
"https://localhost:3000/assets/icon-80.png" }
],
"controls": [
{
"id": "HelloWorldButton",
"type": "button",
"label": "Insert text",
"icons": [
{ "size": 16, "file":
"https://localhost:3000/assets/icon-16.png" },
{ "size": 32, "file":
"https://localhost:3000/assets/icon-32.png" },
{ "size": 80, "file":
"https://localhost:3000/assets/icon-80.png" }
],
"supertip": {
"title": "Insert text",
"description": "Inserts some text."
},
"actionId": "insertHelloWorld"
}
]
}
]
}
]
}
command line
npm start
2. In Outlook, open a new message window (or reply to an existing message). A new
control group named Contoso Add-in will appear on the Outlook Message tab.
The group has a button named Insert text.
3. Put the cursor anywhere in the message body and choose the Insert text button.
4. When prompted with the WebView Stop On Load dialog box, select OK.
7 Note
If you select Cancel, the dialog won't be shown again while this instance of
the add-in is running. However, if you restart your add-in, you'll see the dialog
again.
command line
npm stop
See also
Unified manifest for Microsoft 365 (preview)
Using Visual Studio Code to publish
Tutorial: Build a message compose
Outlook add-in
Article • 03/21/2023
This tutorial teaches you how to build an Outlook add-in that can be used in message
compose mode to insert content into the body of a message.
Prerequisites
Node.js (the latest LTS version).
The latest version of Yeoman and the Yeoman generator for Office Add-ins. To
install these tools globally, run the following command via the command prompt.
command line
7 Note
A GitHub account
Setup
The add-in that you'll create in this tutorial will read gists from the user's GitHub
account and add the selected gist to the body of a message. Complete the following
steps to create two new gists that you can use to test the add-in you're going to build.
1. Login to GitHub .
markdown
# Hello World
```json
{
"foo": "bar"
}
```
HTML
<html>
<head>
<style>
h1 {
font-family: Calibri;
}
</style>
</head>
<body>
<h1>Hello World!</h1>
<p>This is a test</p>
</body>
</html>
command line
yo office
7 Note
When you run the yo office command, you may receive prompts about the
data collection policies of Yeoman and the Office Add-in CLI tools. Use the
information that's provided to respond to the prompts as you see fit.
When prompted, provide the following information to create your add-in project.
Tip
You can ignore the next steps guidance that the Yeoman generator provides
after the add-in project's been created. The step-by-step instructions within
this article provide all of the guidance you'll need to complete this tutorial.
command line
To install these tools for your project, run the following command in the root
directory of the project.
command line
On Windows, you can navigate to the root directory of the project via the
command line and then enter code . to open that folder in VS Code. On Mac,
you'll need to add the code command to the path before you can use that
command to open the project folder in VS Code.
1. Locate the <ProviderName> element and replace the default value with your
company name.
XML
<ProviderName>Contoso</ProviderName>
2. Locate the <Description> element, replace the default value with a description of
the add-in, and save the file.
XML
7 Note
Office Add-ins should use HTTPS, not HTTP, even while you're developing. If you're
prompted to install a certificate after you run one of the following commands,
accept the prompt to install the certificate that the Yeoman generator provides. You
may also have to run your command prompt or terminal as an administrator for the
changes to be made.
1. Run the following command in the root directory of your project. When you run
this command, the local web server starts and your add-in will be sideloaded.
command line
npm start
2. In Outlook, open an existing message and select the Show Taskpane button.
3. When prompted with the WebView Stop On Load dialog box, select OK.
7 Note
If you select Cancel, the dialog won't be shown again while this instance of
the add-in is running. However, if you restart your add-in, you'll see the dialog
again.
If everything's been set up correctly, the task pane will open and render the add-
in's welcome page.
Define buttons
Now that you've verified the base add-in works, you can customize it to add more
functionality. By default, the manifest only defines buttons for the read message
window. Let's update the manifest to remove the buttons from the read message
window and define two new buttons for the compose message window:
The <Group> element defines the grouping for the new buttons, with a label set
by the groupLabel resource.
XML
1. Locate the <Resources> element in the manifest file and delete the entire element
(including its closing tag).
2. In that same location, add the following markup to replace the <Resources>
element you just removed.
XML
<Resources>
<bt:Images>
<bt:Image id="Icon.16x16"
DefaultValue="https://localhost:3000/assets/icon-16.png"/>
<bt:Image id="Icon.32x32"
DefaultValue="https://localhost:3000/assets/icon-32.png"/>
<bt:Image id="Icon.80x80"
DefaultValue="https://localhost:3000/assets/icon-80.png"/>
</bt:Images>
<bt:Urls>
<bt:Url id="Commands.Url"
DefaultValue="https://localhost:3000/commands.html"/>
<bt:Url id="Taskpane.Url"
DefaultValue="https://localhost:3000/taskpane.html"/>
</bt:Urls>
<bt:ShortStrings>
<bt:String id="GroupLabel" DefaultValue="Git the gist"/>
<bt:String id="TaskpaneButton.Label" DefaultValue="Insert gist"/>
<bt:String id="TaskpaneButton.Title" DefaultValue="Insert gist"/>
<bt:String id="FunctionButton.Label" DefaultValue="Insert default
gist"/>
<bt:String id="FunctionButton.Title" DefaultValue="Insert default
gist"/>
</bt:ShortStrings>
<bt:LongStrings>
<bt:String id="TaskpaneButton.Tooltip" DefaultValue="Displays a
list of your gists and allows you to insert their contents into the
current message."/>
<bt:String id="FunctionButton.Tooltip" DefaultValue="Inserts the
content of the gist you mark as default into the current message."/>
</bt:LongStrings>
</Resources>
2. Run the following command to start the local web server and automatically
sideload your add-in.
command line
npm start
After you've reinstalled the add-in, you can verify that it installed successfully by
checking for the commands Insert gist and Insert default gist in a compose message
window. Note that nothing will happen if you select either of these items, because you
haven't yet finished building this add-in.
If you're running this add-in in Outlook 2016 or later on Windows, you should see
two new buttons on the ribbon of the compose message window: Insert gist and
Insert default gist.
If you're running this add-in in Outlook on the web, you should see a new button
at the bottom of the compose message window. Select that button to see the
options Insert gist and Insert default gist.
Implement a first-run experience
This add-in needs to be able to read gists from the user's GitHub account and identify
which one the user has chosen as the default gist. In order to achieve these goals, the
add-in must prompt the user to provide their GitHub username and choose a default
gist from their collection of existing gists. Complete the steps in this section to
implement a first-run experience that will display a dialog to collect this information
from the user.
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<title>Settings</title>
<body class="ms-font-l">
<main>
<section class="ms-font-m ms-fontColor-neutralPrimary">
<div class="not-configured-warning ms-MessageBar ms-MessageBar--
warning">
<div class="ms-MessageBar-content">
<div class="ms-MessageBar-icon">
<i class="ms-Icon ms-Icon--Info"></i>
</div>
<div class="ms-MessageBar-text">
Oops! It looks like you haven't configured <strong>Git the
gist</strong> yet.
<br/>
Please configure your GitHub username and select a default gist,
then try that action again!
</div>
</div>
</div>
<div class="ms-font-xxl">Settings</div>
<div class="ms-Grid">
<div class="ms-Grid-row">
<div class="ms-TextField">
<label class="ms-Label">GitHub Username</label>
<input class="ms-TextField-field" id="github-user" type="text"
value="" placeholder="Please enter your GitHub username">
</div>
</div>
<div class="error-display ms-Grid-row">
<div class="ms-font-l ms-fontWeight-semibold">An error occurred:
</div>
<pre><code id="error-text"></code></pre>
</div>
<div class="gist-list-container ms-Grid-row">
<div class="list-title ms-font-xl ms-fontWeight-regular">Choose
Default Gist</div>
<form>
<div id="gist-list">
</div>
</form>
</div>
</div>
<div class="ms-Dialog-actions">
<div class="ms-Dialog-actionsRight">
<button class="ms-Dialog-action ms-Button ms-Button--primary"
id="settings-done" disabled>
<span class="ms-Button-label">Done</span>
</button>
</div>
</div>
</section>
</main>
<script type="text/javascript"
src="../../node_modules/jquery/dist/jquery.js"></script>
<script type="text/javascript" src="../helpers/gist-api.js"></script>
<script type="text/javascript" src="dialog.js"></script>
</body>
</html>
You may have noticed that the HTML file references a JavaScript file, gist-api.js, that
doesn't yet exist. This file will be created in the Fetch data from GitHub section below.
Next, create a file in the ./src/settings folder named dialog.css, and add the following
code to specify the styles that are used by dialog.html.
CSS
section {
margin: 10px 20px;
}
.not-configured-warning {
display: none;
}
.error-display {
display: none;
}
.gist-list-container {
margin: 10px -8px;
display: none;
}
.list-title {
border-bottom: 1px solid #a6a6a6;
padding-bottom: 5px;
}
ul {
margin-top: 10px;
}
.ms-ListItem-secondaryText,
.ms-ListItem-tertiaryText {
padding-left: 15px;
}
Now that you've defined the dialog UI, you can write the code that makes it actually do
something. Create a file in the ./src/settings folder named dialog.js and add the
following code. Note that this code uses jQuery to register events and uses the
messageParent method to send the user's choices back to the caller.
JavaScript
(function(){
'use strict';
// The Office initialize function must be run each time a new page is
loaded.
Office.initialize = function(reason){
jQuery(document).ready(function(){
if (window.location.search) {
// Check if warning should be displayed.
const warn = getParameterByName('warn');
if (warn) {
$('.not-configured-warning').show();
} else {
// See if the config values were passed.
// If so, pre-populate the values.
const user = getParameterByName('gitHubUserName');
const gistId = getParameterByName('defaultGistId');
$('#github-user').val(user);
loadGists(user, function(success){
if (success) {
$('.ms-ListItem').removeClass('is-selected');
$('input').filter(function() {
return this.value === gistId;
}).addClass('is-selected').attr('checked', 'checked');
$('#settings-done').removeAttr('disabled');
}
});
}
}
settings.gitHubUserName = $('#github-user').val();
sendMessage(JSON.stringify(settings));
}
});
});
};
function onGistSelected() {
$('.ms-ListItem').removeClass('is-selected').removeAttr('checked');
$(this).children('.ms-ListItem').addClass('is-selected').attr('checked',
'checked');
$('.not-configured-warning').hide();
$('#settings-done').removeAttr('disabled');
}
function sendMessage(message) {
Office.context.ui.messageParent(message);
}
Finally, open the webpack.config.js file found in the root directory of the project and
complete the following steps.
1. Locate the entry object within the config object and add a new entry for dialog .
JavaScript
dialog: "./src/settings/dialog.js",
After you've done this, the new entry object will look like this:
JavaScript
entry: {
polyfill: ["core-js/stable", "regenerator-runtime/runtime"],
taskpane: "./src/taskpane/taskpane.js",
commands: "./src/commands/commands.js",
dialog: "./src/settings/dialog.js",
},
2. Locate the plugins array within the config object. In the patterns array of the new
CopyWebpackPlugin object, add new entries for taskpane.css and dialog.css.
JavaScript
{
from: "./src/taskpane/taskpane.css",
to: "taskpane.css",
},
{
from: "./src/settings/dialog.css",
to: "dialog.css",
},
After you've done this, the new CopyWebpackPlugin object will look like this:
JavaScript
new CopyWebpackPlugin({
patterns: [
{
from: "./src/taskpane/taskpane.css",
to: "taskpane.css",
},
{
from: "./src/settings/dialog.css",
to: "dialog.css",
},
{
from: "assets/*",
to: "assets/[name][ext][query]",
},
{
from: "manifest*.xml",
to: "[name]." + buildType + "[ext]",
transform(content) {
if (dev) {
return content;
} else {
return content.toString().replace(new RegExp(urlDev, "g"),
urlProd);
}
},
},
]}),
3. In the same plugins array within the config object, add this new object to the end
of the array.
JavaScript
new HtmlWebpackPlugin({
filename: "dialog.html",
template: "./src/settings/dialog.html",
chunks: ["polyfill", "dialog"]
})
After you've done this, the new plugins array will look like this:
JavaScript
plugins: [
new HtmlWebpackPlugin({
filename: "taskpane.html",
template: "./src/taskpane/taskpane.html",
chunks: ["polyfill", "taskpane"],
}),
new CopyWebpackPlugin({
patterns: [
{
from: "./src/taskpane/taskpane.css",
to: "taskpane.css",
},
{
from: "./src/settings/dialog.css",
to: "dialog.css",
},
{
from: "assets/*",
to: "assets/[name][ext][query]",
},
{
from: "manifest*.xml",
to: "[name]." + buildType + "[ext]",
transform(content) {
if (dev) {
return content;
} else {
return content.toString().replace(new RegExp(urlDev, "g"),
urlProd);
}
},
},
],
}),
new HtmlWebpackPlugin({
filename: "commands.html",
template: "./src/commands/commands.html",
chunks: ["polyfill", "commands"],
}),
new HtmlWebpackPlugin({
filename: "dialog.html",
template: "./src/settings/dialog.html",
chunks: ["polyfill", "dialog"]
})
],
Within the ./src folder, create a new subfolder named helpers. In the ./src/helpers
folder, create a file named gist-api.js, and add the following code to retrieve the user's
gists from GitHub and build the list of gists.
JavaScript
$.ajax({
url: requestUrl,
dataType: 'json'
}).done(function(gists){
callback(gists);
}).fail(function(error){
callback(null, error);
});
}
listItem.on('click', clickFunc);
});
}
function buildFileList(files) {
return fileList;
}
command line
If the add-in has already been configured, the function will load the content of the
gist that the user has selected as the default and insert it into the body of the
message.
If the add-in hasn't yet been configured, then the settings dialog will prompt the
user to provide the required information.
Open the file ./src/commands/commands.html and replace the entire contents with the
following markup.
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<script type="text/javascript"
src="../../node_modules/jquery/dist/jquery.js"></script>
<script type="text/javascript"
src="../../node_modules/showdown/dist/showdown.min.js"></script>
<script type="text/javascript"
src="../../node_modules/urijs/src/URI.min.js"></script>
<script type="text/javascript" src="../helpers/addin-config.js">
</script>
<script type="text/javascript" src="../helpers/gist-api.js"></script>
</head>
<body>
<!-- NOTE: The body is empty on purpose. Since functions in commands.js
are
invoked via a button, there is no UI to render. -->
</body>
</html>
You may have noticed that the HTML file references a JavaScript file, addin-config.js,
that doesn't yet exist. This file will be created in the Create a file to manage
configuration settings section later in this tutorial.
JavaScript
let config;
let btnEvent;
// The initialize function must be run each time a new page is loaded.
Office.initialize = function () {
};
function showError(error) {
Office.context.mailbox.item.notificationMessages.replaceAsync('github-
error', {
type: 'errorMessage',
message: error
}, function(result){
});
}
let settingsDialog;
function insertDefaultGist(event) {
config = getConfig();
} else {
// Save the event object so we can finish up later.
btnEvent = event;
// Not configured yet, display settings dialog with
// warn=1 to display warning.
const url = new URI('dialog.html?
warn=1').absoluteTo(window.location).toString();
const dialogOptions = { width: 20, height: 40, displayInIframe: true };
Office.context.ui.displayDialogAsync(url, dialogOptions,
function(result) {
settingsDialog = result.value;
settingsDialog.addEventHandler(Office.EventType.DialogMessageReceived,
receiveMessage);
settingsDialog.addEventHandler(Office.EventType.DialogEventReceived,
dialogClosed);
});
}
}
function receiveMessage(message) {
config = JSON.parse(message.message);
setConfig(config, function(result) {
settingsDialog.close();
settingsDialog = null;
btnEvent.completed();
btnEvent = null;
});
}
function dialogClosed(message) {
settingsDialog = null;
btnEvent.completed();
btnEvent = null;
}
JavaScript
function getConfig() {
const config = {};
config.gitHubUserName =
Office.context.roamingSettings.get('gitHubUserName');
config.defaultGistId =
Office.context.roamingSettings.get('defaultGistId');
return config;
}
Office.context.roamingSettings.saveAsync(callback);
}
If the gist contains HTML, the add-in will insert the HTML as is into the body of the
message.
If the gist contains Markdown, the add-in will use the Showdown library to
convert the Markdown to HTML, and will then insert the resulting HTML into the
body of the message.
If the gist contains anything other than HTML or Markdown, the add-in will insert it
into the body of the message as a code snippet.
JavaScript
$.ajax({
url: requestUrl,
dataType: 'json'
}).done(function(gist){
callback(gist);
}).fail(function(error){
callback(null, error);
});
}
2. In the compose message window, select the Insert default gist button. You should
see a dialog where you can configure the add-in, starting with the prompt to set
your GitHub username.
3. In the settings dialog, enter your GitHub username and then either Tab or click
elsewhere in the dialog to invoke the change event, which should load your list of
public gists. Select a gist to be the default, and select Done.
4. Select the Insert default gist button again. This time, you should see the contents
of the gist inserted into the body of the email.
7 Note
Outlook on Windows: To pick up the latest settings, you may need to close
and reopen the compose message window.
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Contoso Task Pane Add-in</title>
</html>
css
/* Copyright (c) Microsoft. All rights reserved. Licensed under the MIT
license. See full license in root of repo. */
html, body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: auto; }
body {
position: relative;
font-size: 16px; }
main {
height: 100%;
overflow-y: auto; }
footer {
width: 100%;
position: relative;
bottom: 0;
margin-top: 10px;}
ul {
padding: 0; }
#settings-prompt {
margin: 10px 0;
}
#error-display {
padding: 10px;
}
#insert-button {
margin: 0 10px;
}
.clearfix {
display: block;
clear: both;
height: 0; }
.pointerCursor {
cursor: pointer; }
.invisible {
visibility: hidden; }
.undisplayed {
display: none; }
.ms-Icon.enlarge {
position: relative;
font-size: 20px;
top: 4px; }
.ms-ListItem-secondaryText,
.ms-ListItem-tertiaryText {
padding-left: 15px;
}
.ms-landing-page {
display: -webkit-flex;
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
-webkit-flex-wrap: nowrap;
flex-wrap: nowrap;
height: 100%; }
.ms-landing-page__main {
display: -webkit-flex;
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
-webkit-flex-wrap: nowrap;
flex-wrap: nowrap;
-webkit-flex: 1 1 0;
flex: 1 1 0;
height: 100%; }
.ms-landing-page__content {
display: -webkit-flex;
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
-webkit-flex-wrap: nowrap;
flex-wrap: nowrap;
height: 100%;
-webkit-flex: 1 1 0;
flex: 1 1 0;
padding: 20px; }
.ms-landing-page__content h2 {
margin-bottom: 20px; }
.ms-landing-page__footer {
display: -webkit-inline-flex;
display: inline-flex;
-webkit-justify-content: center;
justify-content: center;
-webkit-align-items: center;
align-items: center; }
.ms-landing-page__footer--left {
transition: background ease 0.1s, color ease 0.1s;
display: -webkit-inline-flex;
display: inline-flex;
-webkit-justify-content: flex-start;
justify-content: flex-start;
-webkit-align-items: center;
align-items: center;
-webkit-flex: 1 0 0px;
flex: 1 0 0px;
padding: 20px; }
.ms-landing-page__footer--left:active {
cursor: default; }
.ms-landing-page__footer--left--disabled {
opacity: 0.6;
pointer-events: none;
cursor: not-allowed; }
.ms-landing-page__footer--left--disabled:active, .ms-landing-page__footer--
left--disabled:hover {
background: transparent; }
.ms-landing-page__footer--left img {
width: 40px;
height: 40px; }
.ms-landing-page__footer--left h1 {
-webkit-flex: 1 0 0px;
flex: 1 0 0px;
margin-left: 15px;
text-align: left;
width: auto;
max-width: auto;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis; }
.ms-landing-page__footer--right {
transition: background ease 0.1s, color ease 0.1s;
padding: 29px 20px; }
.ms-landing-page__footer--right:active, .ms-landing-page__footer--
right:hover {
background: #005ca4;
cursor: pointer; }
.ms-landing-page__footer--right:active {
background: #005ca4; }
.ms-landing-page__footer--right--disabled {
opacity: 0.6;
pointer-events: none;
cursor: not-allowed; }
.ms-landing-page__footer--right--disabled:active, .ms-landing-page__footer--
right--disabled:hover {
background: transparent; }
JavaScript
(function(){
'use strict';
let config;
let settingsDialog;
Office.initialize = function(reason){
jQuery(document).ready(function(){
config = getConfig();
Office.context.mailbox.item.body.setSelectedDataAsync(content,
{coercionType: Office.CoercionType.Html}, function(result)
{
if (result.status === Office.AsyncResultStatus.Failed) {
showError('Could not insert gist: ' +
result.error.message);
}
});
} else {
showError('Could not create insertable content: ' + error);
}
});
} else {
showError('Could not retrieve gist: ' + error);
}
});
});
Office.context.ui.displayDialogAsync(url, dialogOptions,
function(result) {
settingsDialog = result.value;
settingsDialog.addEventHandler(Office.EventType.DialogMessageReceived,
receiveMessage);
settingsDialog.addEventHandler(Office.EventType.DialogEventReceived,
dialogClosed);
});
})
});
};
function loadGists(user) {
$('#error-display').hide();
$('#not-configured').hide();
$('#gist-list-container').show();
} else {
$('#gist-list').empty();
buildGistList($('#gist-list'), gists, onGistSelected);
}
});
}
function onGistSelected() {
$('#insert-button').removeAttr('disabled');
$('.ms-ListItem').removeClass('is-selected').removeAttr('checked');
$(this).children('.ms-ListItem').addClass('is-selected').attr('checked',
'checked');
}
function showError(error) {
$('#not-configured').hide();
$('#gist-list-container').hide();
$('#error-display').text(error);
$('#error-display').show();
}
function receiveMessage(message) {
config = JSON.parse(message.message);
setConfig(config, function(result) {
settingsDialog.close();
settingsDialog = null;
loadGists(config.gitHubUserName);
});
}
function dialogClosed(message) {
settingsDialog = null;
}
})();
2. In the compose message window, select the Insert gist button. You should see a
task pane open to the right of the compose form.
3. In the task pane, select the Hello World Html gist and select Insert to insert that
gist into the body of the message.
Next steps
In this tutorial, you've created an Outlook add-in that can be used in message compose
mode to insert content into the body of a message. To learn more about developing
Outlook add-ins, continue to the following article.
See also
Office add-in manifests
Outlook add-in design guidelines
Debug function commands in Outlook add-ins
Develop Outlook add-ins for the new
Outlook on Windows (preview)
Article • 06/06/2023
The new Outlook on Windows desktop client unifies the Windows and web codebases
to create a more consistent Outlook experience for users and administrators. Its modern
and simplified interface has added capabilities and aims to improve productivity,
organization, and collaboration for users. More importantly, the new Outlook on
Windows supports Outlook web add-ins, so that you can continue to extend Outlook's
functionality.
To help get you started on the migration process, review the following guidance.
The differences in features and scenarios supported by VSTO and COM add-ins
and Outlook web add-ins are being addressed. To determine whether your add-in
scenario is fully supported in an Outlook web add-in, see Supported scenarios in
Outlook web add-ins.
For guidance on how to transition your VSTO add-in to an Outlook web add-in,
see VSTO add-in developer's guide and Tutorial: Share code between both a VSTO
Add-in and an Office Add-in with a shared code library.
If you're new to Outlook web add-ins, try out the Outlook quick start to build your
first add-in.
7 Note
VSTO and COM add-ins are still supported in classic Outlook on Windows.
Supported scenarios in Outlook web add-ins
The development of the Outlook JavaScript API used by Outlook web add-ins is focused
on closing the gap on scenarios that are only supported by VSTO and COM add-in
solutions. This way, users who transition to the Outlook web add-in can continue to
have a seamless experience.
The following table identifies key Outlook scenarios and their support status in a web
add-in. This table will be updated as additional scenarios are supported. Periodically
check this section as you plan to migrate your VSTO or COM add-in.
Spam email Enable users to report unsolicited and Supported. Improvements are
reporting and potentially unsafe messages and learn how in development to further
education to identify these messages. enhance the user experience.
Data loss Prevent users from forwarding mail items Partially supported. Essential
prevention that contain highly sensitive information. features are yet to be
addressed to create a similar
experience to VSTO or COM
add-ins.
Mail item Enable users to identify and classify Partially supported. Essential
classification messages that contain sensitive information. features are yet to be
addressed to create a similar
experience to VSTO or COM
add-ins.
Proofing mail Provide users with real-time proofreading Not currently supported.
items assistance as they compose messages.
There are various possibilities for extending the Outlook functionality through add-ins. If
your VSTO or COM add-in solution doesn't quite fit any of the scenarios in the table,
complete the survey to share your scenario .
Have a Microsoft 365 work or school account connected to Exchange Online. The
new client doesn't currently support on-premises, hybrid, or sovereign Exchange
accounts.
To help you sign up and install the Outlook desktop client, see Getting started with the
new Outlook for Windows .
For guidance on how to sideload your add-in, see Sideload Outlook add-ins for testing.
See also
Blog post: New Outlook for Windows available to all Office Insiders
Podcast: Update on development with new Outlook for Windows
Outlook add-ins overview
Build your first Outlook add-in
VSTO add-in developer's guide
Tutorial: Share code between both a VSTO Add-in and an Office Add-in with a
shared code library
Outlook add-in APIs
Article • 03/21/2023
To use APIs in your Outlook add-in, you must specify the location of the Office.js library,
the requirement set, the schema, and the permissions. You'll primarily use the Office
JavaScript APIs exposed through the Mailbox object.
Office.js library
To interact with the Outlook add-in API, you need to use the JavaScript APIs in Office.js.
The content delivery network (CDN) for the library is
https://appsforoffice.microsoft.com/lib/1/hosted/Office.js . Add-ins submitted to
AppSource must reference Office.js by this CDN; they can't use a local reference.
Reference the CDN in a <script> tag in the <head> tag of the web page (.html, .aspx, or
.php file) that implements the UI of your add-in.
HTML
<script src="https://appsforoffice.microsoft.com/lib/1/hosted/Office.js"
type="text/javascript"></script>
As we add new APIs, the URL to Office.js will stay the same. We will change the version
in the URL only if we break an existing API behavior.
) Important
When developing an add-in for any Office client application, reference the Office
JavaScript API from inside the <head> section of the page. This ensures that the API
is fully initialized prior to any body elements.
Requirement sets
All Outlook APIs belong to the Mailbox requirement set. The Mailbox requirement set
has versions, and each new set of APIs that are released belongs to a higher version of
the set. Not all Outlook clients will support the newest set of APIs when they are
released, but if an Outlook client declares support for a requirement set, it will support
all the APIs in that requirement set.
To control which Outlook clients the add-in appears in, specify a minimum requirement
set version in the manifest. For example, if you specify requirement set version 1.3, the
add-in will not show up in any Outlook client that doesn't support a minimum version of
1.3.
Specifying a requirement set doesn't limit your add-in to the APIs in that version. If the
add-in specifies requirement set v1.1 but is running in an Outlook client that supports
v1.3, the add-in can still use v1.3 APIs. The requirement set only controls which Outlook
clients the add-in appears in.
To check the availability of any APIs from a requirement set greater than the one
specified in the manifest, you can use standard JavaScript:
JavaScript
if (item.somePropertyOrFunction) {
item.somePropertyOrFunction...
}
7 Note
These checks are not needed for any APIs that are in the requirement set version
specified in the manifest.
Specify the minimum requirement set that supports the critical set of APIs for your
scenario, without which features of your add-in won't work. You specify the requirement
set in the manifest. The markup varies depending on the manifest that you are using.
XML manifest: Use the <Requirements> element. Note that the <Methods> child
element of <Requirements> isn't supported in Outlook add-ins, so you can't
declare support for specific methods.
Unified manifest for Microsoft 365 (preview): Use the "extensions.capabilities"
property.
For more information, see Office add-in manifests, and Understanding Outlook API
requirement sets.
Permissions
Your add-in requires the appropriate permissions to use the APIs that it needs. In
general, you should specify the minimum permission needed for your add-in.
There are four levels of permissions; restricted, read item, read/write item, and
read/write mailbox. For more details. For more details, see Understanding Outlook add-
in permissions.
Mailbox object
Outlook add-ins primarily use a subset of the API exposed through the Mailbox object.
To access the objects and members specifically for use in Outlook add-ins, such as the
Item object, use the mailbox property of the Context object to access the Mailbox
object, as shown in the following line of code.
JavaScript
For information about using JavaScript in Outlook add-ins, see Outlook add-ins.
See also
Office add-in manifests
Understanding Outlook API requirement sets
Understanding Outlook add-in permissions
Privacy and security for Office Add-ins
Outlook JavaScript API requirement sets
Article • 07/13/2023
Outlook add-ins declare what API versions they require in their manifest. The markup
varies depending on whether you're using the XML manifest format or the unified
manifest for Microsoft 365 (preview).
XML Manifest
The API version is specified by the Requirements element. Outlook add-ins always
include a Set element with a Name attribute set to Mailbox and a MinVersion
attribute set to the minimum API requirement set that supports the add-in's
scenarios.
For example, the following manifest snippet indicates a minimum requirement set
of 1.1.
XML
<Requirements>
<Sets>
<Set Name="Mailbox" MinVersion="1.1" />
</Sets>
</Requirements>
All Outlook APIs belong to the Mailbox requirement set. The Mailbox requirement set
has versions, and each new set of APIs that we release belongs to a higher version of the
set. Not all Outlook clients support the newest set of APIs, but if an Outlook client
declares support for a requirement set, generally it supports all of the APIs in that
requirement set (check the documentation on a specific API or feature for any
exceptions).
Setting a minimum requirement set version in the manifest controls in which Outlook
client the add-in will appear. If a client doesn't support the minimum requirement set, it
doesn't load the add-in. For example, if requirement set version 1.3 is specified, this
means the add-in will not show up in any Outlook client that doesn't support at least
1.3.
7 Note
Although Outlook on Android and on iOS support up to requirement set 1.5, your
mobile add-in can now implement some APIs from later requirement sets. For more
information on which APIs are supported in Outlook mobile, see Outlook
JavaScript APIs supported in Outlook on mobile devices.
To use a newer API, developers can check if a particular application supports the
requirement set by doing the following:
JavaScript
if (Office.context.requirements.isSetSupported('Mailbox', '1.3')) {
// Perform actions.
}
else {
// Provide alternate flow/logic.
}
Alternatively, developers can check for the existence of a newer API by using standard
JavaScript technique.
JavaScript
No such checks are necessary for any APIs which are present in the requirement set
version specified in the manifest.
) Important
If your target Exchange server and Outlook client support different requirement
sets, then you may be restricted to the lower requirement set range. For example, if
an add-in is running in Outlook 2019 on Windows (highest requirement set: 1.6)
against Exchange 2016 (highest requirement set: 1.5), your add-in may be limited
to requirement set 1.5.
Exchange Online Latest build 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 1.10, 1.11,
1.12, 1.13
IdentityAPI 1.31
2013 1.1
7 Note
1
To require the Identity API set 1.3 in your Outlook add-in code, check if it's
supported by calling isSetSupported('IdentityAPI', '1.3') . Declaring it in the
Outlook add-in's manifest isn't supported. You can also determine if the API is
supported by checking that it's not undefined . For further details, see Using APIs
from later requirement sets.
2
Even if an add-in implements features from requirement sets not supported in an
Exchange on-premises environment, it can still be added to an Outlook client as
long as the requirement set specified in its manifest aligns with those supported by
Exchange on-premises. However, an implemented feature will only work if the
Outlook client in which the add-in is installed supports the minimum requirement
set needed by a feature. To determine the requirement sets supported by varying
Outlook clients, see Outlook client support. We recommend supplementing this
with the documentation on the specific feature for any exceptions.
Windows - Microsoft 365 subscription 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.81, 1.91, 1.101,
- retail perpetual Outlook 2016 1.111, 1.121, 1.131
and later IdentityAPI 1.32
volume-licensed perpetual 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.81, 1.91
Outlook 2021 IdentityAPI 1.32
Mac classic UI 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8
IdentityAPI 1.32
new UI4 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 1.10,
1.11, 1.12
IdentityAPI 1.32
Web modern Outlook UI when 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 1.10,
browser5 8 connected to 1.11, 1.12, 1.13
Exchange Online: subscription, IdentityAPI 1.32
Outlook.com
Exchange on-premises
7 Note
1
Version support for more recent requirement sets in Outlook on Windows with a
Microsoft 365 subscription or a retail perpetual license as follows:
For more details according to your version, see the update history page for Office
2021 or Microsoft 365 and how to find your Office client version and update
channel .
2
To require the Identity API set 1.3 in your Outlook add-in code, check if it's
supported by calling isSetSupported('IdentityAPI', '1.3') . Declaring it in the
Outlook add-in's manifest isn't supported. You can also determine if the API is
supported by checking that it's not undefined . For further details, see Using APIs
from later requirement sets.
3 Support for 1.3 in Outlook 2013 was added as part of the December 8, 2015,
update for Outlook 2013 (KB3114349) . Support for 1.4 in Outlook 2013 was
added as part of the September 13, 2016, update for Outlook 2013 (KB3118280) .
Support for 1.4 in volume-licensed perpetual Outlook 2016 was added as part of
the July 3, 2018, update for Office 2016 (KB4022223) .
4
Support for the new Mac UI is available from Outlook Version 16.38.506. For more
information, see the Add-in support in Outlook on new Mac UI section.
5 Add-ins aren't supported in Outlook on Android, on iOS, and modern mobile web
with on-premises Exchange accounts. Certain iOS devices still support add-ins
when using on-premises Exchange accounts with classic Outlook on the web. For
information about supported devices, see Requirements for running Office Add-
ins.
6
Currently, there are additional considerations when designing and implementing
add-ins for mobile clients. For more details, see code considerations when adding
support for add-in commands in Outlook on mobile devices.
7
Although Outlook on Android and on iOS support up to requirement set 1.5, your
mobile add-in can now implement some APIs from later requirement sets, such as
event-based activation. For more information on which APIs are supported in
Outlook mobile, see Outlook JavaScript APIs supported in Outlook on mobile
devices.
8 Add-ins don't work in modern Outlook on the web on iPhone and Android
smartphones. For information about supported devices, see Requirements for
running Office Add-ins.
Tip
You can distinguish between classic and modern Outlook in a web browser by
checking your mailbox toolbar.
modern
classic
7 Note
Preview APIs are subject to change and aren't intended for use in a production
environment.
For more details about the preview APIs, see Outlook API preview requirement set.
outlook package
Reference
Interfaces
Office.Appointment The subclass of Item dealing with appointments.
Child interfaces:
AppointmentCompose
AppointmentRead
Parent interfaces:
ItemCompose
Appointment
Parent interfaces:
ItemRead
Appointment
Office.AppointmentTime Provides the current dates and times of the appointment that
ChangedEventArgs raised the Office.EventType.AppointmentTimeChanged event.
Office.AttachmentContent Represents the content of an attachment on a message or
appointment item.
Office.Body The body object provides methods for adding and updating the
content of the message or appointment. It is returned in the
body property of the selected item.
Office.InfobarClickedEvent Provides basic details about the notification message that raised
Args the Office.EventType.InfobarClicked event.
Note: This object is intended for you to set and get your custom
headers on a message item. To learn more, see Get and set
internet headers on a message in an Outlook add-in.
To see the full member list, refer to the Object Model page.
AppointmentCompose
AppointmentRead
MessageCompose
MessageRead
Child interfaces:
AppointmentCompose
MessageCompose
Office.ItemRead The read mode of Office.context.mailbox.item.
Child interfaces:
AppointmentRead
MessageRead
Office.LocalClientTime Represents a date and time in the local client's time zone. Read
mode only.
Key properties:
Child interfaces:
MessageCompose
MessageRead
Parent interfaces:
ItemCompose
Message
Parent interfaces:
ItemRead
Message
Office.Recurrence The Recurrence object provides methods to get and set the
recurrence pattern of appointments but only get the recurrence
pattern of meeting requests. It will have a dictionary with the
following keys: seriesTime , recurrenceType ,
recurrenceProperties , and recurrenceTimeZone (optional).
Office.SeriesTime The SeriesTime object provides methods to get and set the
dates and times of appointments in a recurring series and get
the dates and times of meeting requests in a recurring series.
Office.UserProfile Information about the user associated with the mailbox. This
includes their account type, display name, email address, and
time zone.
Enums
Office.MailboxEnums.Action Specifies the type of custom action in a notification message.
Type
Office.MailboxEnums.Rest Specifies the version of the REST API that corresponds to a REST-
Version formatted item ID.
Add-ins are a great way for partners to extend the functionality of Outlook beyond our
core feature set. Add-ins enable users to access external experiences, tasks, and content
without needing to leave their inbox. Once installed, Outlook add-ins are available on
every platform and device.
The following high-level guidelines will help you design and build a compelling add-in,
which brings the best of your app right into Outlook—on Windows, Web, iOS, Mac, and
Android.
Principles
Your add-in will be an extension of our experience and it's important to make sure the
scenarios you enable feel like a natural fit inside Outlook. Think carefully about which of
your common use cases will benefit the most from having hooks to them from within
our email and calendaring experiences.
An add-in shouldn't attempt to do everything your app does. The focus should be on
the most frequently used, and appropriate, actions in the context of Outlook content.
Think about your call to action and make it clear what the user should do when your
task pane opens.
This does mean that your add-in will have to visually be different when it runs in
Outlook on iOS versus on Android.
Make it enjoyable to use and get the details right
People enjoy using products that are both functionally and visually appealing. You can
help ensure the success of your add-in by crafting an experience where you've carefully
considered every interaction and visual detail. The necessary steps to complete a task
must be clear and relevant. Ideally, no action should be further than a click or two away.
Try not to take a user out of context to complete an action. A user should easily be able
to get in and out of your add-in and back to whatever they were doing before. An add-
in isn't meant to be a destination to spend a lot of time in—it's an enhancement to our
core functionality. If done properly, your add-in will help us deliver on the goal of
making people more productive.
Brand wisely
We value great branding, and we know it's important to provide users with your unique
experience. But we feel the best way to ensure your add-in's success is to build an
intuitive experience that subtly incorporates elements of your brand versus displaying
persistent or obtrusive brand elements that only distract a user from moving through
your system in an unencumbered manner.
A good way to incorporate your brand in a meaningful way is through the use of your
brand colors, icons, and voice—assuming these don't conflict with the preferred
platform patterns or accessibility requirements. Strive to keep the focus on content and
task completion, not brand attention.
7 Note
Design patterns
7 Note
While the above principles apply to all endpoints/platforms, the following patterns
and examples are specific to mobile add-ins in Outlook on iOS.
To help you create a well-designed add-in, we have templates that contain iOS mobile
patterns that work within the Outlook mobile environment. Leveraging these specific
patterns will help ensure your add-in feels native to both the iOS platform and Outlook
mobile. These patterns are also detailed later in this article. While not exhaustive, this is
the start of a library that we'll continue to build upon as we uncover additional
paradigms partners wish to include in their add-ins.
Overview
A typical add-in is made up of the following components.
Loading
When a user taps on your add-in, the UX should display as quickly as possible. If there is
any delay, use a progress bar or activity indicator. A progress bar should be used when
the amount of time is determinable and an activity indicator should be used when the
amount of time is indeterminable.
Sign in/Sign up
Make your sign in (and sign up) flow straightforward and simple to use.
An example page to sign in and sign up on iOS
Brand bar
The first screen of your add-in should include your branding element. Designed for
recognition, the brand bar also helps set context for the user. Because the navigation
bar contains the name of your company/brand, it's unnecessary to repeat the brand bar
on subsequent pages.
Margins
Mobile margins should be set to 15px (8% of screen) for each side, to align with Outlook
on iOS and 16px for each side to align with Outlook on Android.
Typography
Typography usage is aligned to Outlook on iOS and is kept simple for scannability.
Typography on iOS
Typography on Android
Color palette
Color usage is subtle in Outlook on iOS. To align, we ask that usage of color is localized
to actions and error states, with only the brand bar using a unique color.
Cells
Since the navigation bar cannot be used to label a page, use section titles to label
pages.
) Important
These examples are meant to highlight the ideal way to approach both the
interaction and visual design of an add-in and may not match the exact feature sets
in the shipped versions of the add-ins.
GIPHY
An example of GIPHY on iOS
An example of GIPHY on Android
Nimble
An example of Nimble on iOS
An example of Nimble on Android
Trello
An example of Trello on iOS
An example of Trello on Android
Dynamics CRM
An example of Dynamics CRM on iOS
Contextual add-ins are Outlook add-ins that activate based on text in a message or
appointment. By using contextual add-ins, a user can initiate tasks related to a message
without leaving the message itself, which results in an easier and richer user experience.
7 Note
Contextual Outlook add-ins aren't supported when the add-in uses a Unified
manifest for Microsoft 365 (preview).
7 Note
Contextual add-ins are not currently available in Outlook on Android and iOS. This
functionality will be made available in the future.
Support for this feature was introduced in requirement set 1.6. See clients and
platforms that support this requirement set.
XML
<ExtensionPoint xsi:type="DetectedEntity">
<Label resid="contextLabel" />
<!--If you opt to include RequestedHeight, it must be between 140px to
450px, inclusive.-->
<!--<RequestedHeight>360</RequestedHeight>-->
<SourceLocation resid="detectedEntityURL" />
<Rule xsi:type="RuleCollection" Mode="And">
<Rule xsi:type="ItemIs" ItemType="Message" />
<Rule xsi:type="ItemHasKnownEntity" EntityType="PhoneNumber"
Highlight="all" />
</Rule>
</ExtensionPoint>
After a contextual add-in is associated with an account, it will automatically start when
the user clicks a highlighted entity or regular expression. For more information about
regular expressions for Outlook add-ins, see Use regular expression activation rules to
show an Outlook add-in.
A contextual add-in can only exist in read add-ins (not compose add-ins).
You cannot specify the color of the highlighted entity.
An entity that is not highlighted will not launch a contextual add-in in a card.
Because an entity or regular expression that is not highlighted will not launch a
contextual add-in, add-ins must include at least one Rule element with the Highlight
attribute set to all .
7 Note
The EmailAddress and Url entity types do not support highlighting, so they cannot
be used to launch a contextual add-in. They can however be combined in a
RuleCollection rule type as an additional activation criteria.
If there are multiple entities, the user has to click a different entity to launch the
add-in for it.
If an entity activates multiple add-ins, each add-in opens a new tab. The user
switches between tabs to change between add-ins. For example, a name and
address might trigger a phone add-in and a map.
If a single string contains multiple entities that activate multiple add-ins, the entire
string is highlighted, and clicking the string shows all add-ins relevant to the string
on separate tabs. For example, a string that describes a proposed meeting at a
restaurant might activate the Suggested Meeting add-in and a restaurant rating
add-in.
Bing Maps
Suggested Meetings
See also
Outlook add-in: Contoso Order Number (sample contextual add-in that activates
based on a regular expression match)
Write your first Outlook add-in
Use regular expression activation rules to show an Outlook add-in
Entities object
Module extension Outlook add-ins
Article • 03/21/2023
Module extension add-ins appear in the Outlook navigation bar, right alongside mail,
tasks, and calendars. A module extension is not limited to using mail and appointment
information. You can create applications that run inside Outlook to make it easy for your
users to access business information and productivity tools without ever leaving
Outlook.
Tip
Module extensions aren't supported in the Unified manifest for Microsoft 365
(preview), but you can create a very similar experience for users by making a
personal tab that opens in Outlook. In the early preview period for the unified
manifest in Outlook Add-ins, it isn't possible to combine an Outlook Add-in and a
personal tab in the same manifest and install them as a unit. We're working on this,
but in the meantime, you must create separate apps for the add-in and the
personal tab. They can both use files on the same domain.
7 Note
If the user is not using compact navigation, the navigation bar has two looks. With one
extension loaded, it shows the name of the add-in.
When more than one add-in is loaded, it shows the word Add-ins. Clicking either will
open the extension's user interface.
When you click on an extension, Outlook replaces the built-in module with your custom
module so that your users can interact with the add-in. You can use some of the features
of the Outlook JavaScript API in your add-in. APIs that logically assume a specific
Outlook item, such as a message or appointment, don't work in module extensions. The
module can also include function commands in the Outlook ribbon that interact with
the add-in's page. To facilitate this, your function commands call the Office.onReady or
Office.initialize method and the Event.completed method. To walk through how a
module extension Outlook add-in is configured, see the Outlook module extensions
billable hours sample .
The following screenshot shows an add-in that is integrated in the Outlook navigation
bar and has ribbon commands that will update the page of the add-in.
Example
The following is a section of a manifest file that defines a module extension.
XML
<Requirements>
<bt:Sets DefaultMinVersion="1.3">
<bt:Set Name="Mailbox" />
</bt:Sets>
</Requirements>
<!-- End override of existing elements -->
<Hosts>
<Host xsi:type="MailHost">
<DesktopFormFactor>
<!-- Set the URL of the file that contains the
JavaScript function that controls the extension -->
<FunctionFile resid="residFunctionFileUrl" />
<CommandSurface>
<CustomTab id="idTab">
<Group id="idGroup">
<Label resid="residGroupLabel" />
</Group>
<Label resid="residCustomTabLabel" />
</CustomTab>
</CommandSurface>
</ExtensionPoint>
</DesktopFormFactor>
</Host>
</Hosts>
<Resources>
<bt:Images>
<bt:Image id="residAddinIcon16"
DefaultValue="https://localhost:8080/Executive-16.png" />
<bt:Image id="residAddinIcon32"
DefaultValue="https://localhost:8080/Executive-32.png" />
<bt:Image id="residAddinIcon80"
DefaultValue="https://localhost:8080/Executive-80.png" />
<bt:Image id="residAssociateIcon16"
DefaultValue="https://localhost:8080/Associate-16.png" />
<bt:Image id="residAssociateIcon32"
DefaultValue="https://localhost:8080/Associate-32.png" />
<bt:Image id="residAssociateIcon80"
DefaultValue="https://localhost:8080/Associate-80.png" />
</bt:Images>
<bt:Urls>
<bt:Url id="residFunctionFileUrl"
DefaultValue="https://localhost:8080/" />
<bt:Url id="residExtensionPointUrl"
DefaultValue="https://localhost:8080/" />
</bt:Urls>
<bt:String id="residChangeToAssociateLabel"
DefaultValue="Associate" />
</bt:ShortStrings>
<bt:LongStrings>
<bt:String id="residVersionOverrideDesc"
DefaultValue="Version override description" />
<bt:String id="residChangeToAssociateDesc"
DefaultValue="Change to the associate billing rate:
$127/hr" />
</bt:LongStrings>
</Resources>
</VersionOverrides>
</VersionOverrides>
See also
Office add-in manifests
Add-in commands
Outlook module extensions Billable hours sample
Activate your Outlook add-in without
the Reading Pane enabled or a message
selected
Article • 05/20/2023
With a simple manifest configuration, you can create Outlook add-ins for the Message
Read surface that activate a task pane without the Reading Pane enabled or a message
first selected from the mailbox. Follow the walkthrough to learn more and unlock
additional capabilities for your add-in. For example, you can enable your users to access
content from different data sources, such as OneDrive or a customer relationship
management (CRM) system, directly from their Outlook client.
7 Note
Support for this feature was introduced in requirement set 1.13. See clients and
platforms that support this requirement set.
7 Note
This feature isn't currently supported in the Unified manifest for Microsoft 365
(preview), but the team is working on making this available.
To activate your add-in with the Reading Pane turned off or without a message selected,
you must add the SupportsNoItemContext child element to the <Action> element and
set its value to true . As this feature can only be implemented with a task pane in
Message Read mode, the following elements must also be configured.
1. In your preferred code editor, open the Outlook quick start project you created.
3. Select the entire <VersionOverrides> node and replace it with the following XML.
XML
<VersionOverrides
xmlns="http://schemas.microsoft.com/office/mailappversionoverrides"
xsi:type="VersionOverridesV1_0">
<VersionOverrides
xmlns="http://schemas.microsoft.com/office/mailappversionoverrides/1.1"
xsi:type="VersionOverridesV1_1">
<Requirements>
<bt:Sets DefaultMinVersion="1.13">
<bt:Set Name="Mailbox"/>
</bt:Sets>
</Requirements>
<Hosts>
<Host xsi:type="MailHost">
<DesktopFormFactor>
<!-- Message Read mode-->
<ExtensionPoint
xsi:type="MessageReadCommandSurface">
<OfficeTab id="TabDefault">
<Group id="msgReadGroup">
<Label resid="GroupLabel"/>
<Control xsi:type="Button"
id="msgReadOpenPaneButton">
<Label
resid="TaskpaneButton.Label"/>
<Supertip>
<Title
resid="TaskpaneButton.Label"/>
<Description
resid="TaskpaneButton.Tooltip"/>
</Supertip>
<Icon>
<bt:Image size="16"
resid="Icon.16x16"/>
<bt:Image size="32"
resid="Icon.32x32"/>
<bt:Image size="80"
resid="Icon.80x80"/>
</Icon>
<Action xsi:type="ShowTaskpane">
<SourceLocation
resid="Taskpane.Url"/>
<!-- Enables your add-in to
activate without the Reading Pane enabled or a message selected. -->
<SupportsNoItemContext>true</SupportsNoItemContext>
</Action>
</Control>
</Group>
</OfficeTab>
</ExtensionPoint>
</DesktopFormFactor>
</Host>
</Hosts>
<Resources>
<bt:Images>
<bt:Image id="Icon.16x16"
DefaultValue="https://localhost:3000/assets/icon-16.png"/>
<bt:Image id="Icon.32x32"
DefaultValue="https://localhost:3000/assets/icon-32.png"/>
<bt:Image id="Icon.80x80"
DefaultValue="https://localhost:3000/assets/icon-80.png"/>
</bt:Images>
<bt:Urls>
<bt:Url id="Taskpane.Url"
DefaultValue="https://localhost:3000/taskpane.html"/>
</bt:Urls>
<bt:ShortStrings>
<bt:String id="GroupLabel" DefaultValue="Test
walkthrough"/>
<bt:String id="TaskpaneButton.Label" DefaultValue="Show
Taskpane"/>
</bt:ShortStrings>
<bt:LongStrings>
<bt:String id="TaskpaneButton.Tooltip"
DefaultValue="Opens a task pane."/>
</bt:LongStrings>
</Resources>
</VersionOverrides>
</VersionOverrides>
HTML
JavaScript
Try it out
1. From a terminal, run the following code in the root directory of your project. This
starts the local web server and sideloads your add-in.
command
npm start
Tip
Turn off your Reading Pane. For guidance, see the "Turn on, turn off, or move
the Reading Pane" section of Use and configure the Reading Pane to preview
messages .
Deselect a message, if applicable. To deselect a message, hold the Ctrl key
and select the message.
See also
Activate your Outlook add-in on multiple messages
Implement a pinnable task pane in Outlook
Activate your Outlook add-in on
multiple messages
Article • 06/19/2023
With the item multi-select feature, your Outlook add-in can now activate and perform
operations on multiple selected messages in one go. Certain operations, such as
uploading messages to your Customer Relationship Management (CRM) system or
categorizing numerous items, can now be easily completed with a single click.
The following sections walk you through how to configure your add-in to retrieve the
subject line of multiple messages in read mode.
7 Note
Support for the item multi-select feature was introduced in requirement set 1.13.
See clients and platforms that support this requirement set.
7 Note
The item multi-select feature isn't currently supported in the Unified manifest for
Microsoft 365 (preview), but the team is working on making this available.
To enable your add-in to activate on multiple selected messages, you must add the
SupportsMultiSelect child element to the <Action> element and set its value to true .
As item multi-select only supports messages at this time, the <ExtensionPoint>
element's xsi:type attribute value must be set to MessageReadCommandSurface or
MessageComposeCommandSurface .
1. In your preferred code editor, open the Outlook quick start project you created.
XML
<Permissions>ReadWriteMailbox</Permissions>
4. Select the entire <VersionOverrides> node and replace it with the following XML.
XML
<VersionOverrides
xmlns="http://schemas.microsoft.com/office/mailappversionoverrides"
xsi:type="VersionOverridesV1_0">
<VersionOverrides
xmlns="http://schemas.microsoft.com/office/mailappversionoverrides/1.1"
xsi:type="VersionOverridesV1_1">
<Requirements>
<bt:Sets DefaultMinVersion="1.13">
<bt:Set Name="Mailbox"/>
</bt:Sets>
</Requirements>
<Hosts>
<Host xsi:type="MailHost">
<DesktopFormFactor>
<!-- Message Read mode-->
<ExtensionPoint
xsi:type="MessageReadCommandSurface">
<OfficeTab id="TabDefault">
<Group id="msgReadGroup">
<Label resid="GroupLabel"/>
<Control xsi:type="Button"
id="msgReadOpenPaneButton">
<Label
resid="TaskpaneButton.Label"/>
<Supertip>
<Title
resid="TaskpaneButton.Label"/>
<Description
resid="TaskpaneButton.Tooltip"/>
</Supertip>
<Icon>
<bt:Image size="16"
resid="Icon.16x16"/>
<bt:Image size="32"
resid="Icon.32x32"/>
<bt:Image size="80"
resid="Icon.80x80"/>
</Icon>
<Action xsi:type="ShowTaskpane">
<SourceLocation
resid="Taskpane.Url"/>
<!-- Enables your add-in to
activate on multiple selected messages. -->
<SupportsMultiSelect>true</SupportsMultiSelect>
</Action>
</Control>
</Group>
</OfficeTab>
</ExtensionPoint>
</DesktopFormFactor>
</Host>
</Hosts>
<Resources>
<bt:Images>
<bt:Image id="Icon.16x16"
DefaultValue="https://localhost:3000/assets/icon-16.png"/>
<bt:Image id="Icon.32x32"
DefaultValue="https://localhost:3000/assets/icon-32.png"/>
<bt:Image id="Icon.80x80"
DefaultValue="https://localhost:3000/assets/icon-80.png"/>
</bt:Images>
<bt:Urls>
<bt:Url id="Taskpane.Url"
DefaultValue="https://localhost:3000/taskpane.html"/>
</bt:Urls>
<bt:ShortStrings>
<bt:String id="GroupLabel" DefaultValue="Item Multi-
select"/>
<bt:String id="TaskpaneButton.Label" DefaultValue="Show
Taskpane"/>
</bt:ShortStrings>
<bt:LongStrings>
<bt:String id="TaskpaneButton.Tooltip"
DefaultValue="Opens a pane which displays an option to retrieve the
subject line of selected messages."/>
</bt:LongStrings>
</Resources>
</VersionOverrides>
</VersionOverrides>
7 Note
2. In the <body> element, replace the entire <main> element with the following
markup.
HTML
2. In the Office.onReady() callback function, replace the existing code with the
following:
JavaScript
Office.context.mailbox.addHandlerAsync(Office.EventType.SelectedItemsCh
anged, run, asyncResult => {
if (asyncResult.status === Office.AsyncResultStatus.Failed) {
console.log(asyncResult.error.message);
return;
}
7 Note
1. In taskpane.js, navigate to the run function and insert the following code.
JavaScript
asyncResult.value.forEach(item => {
const listItem = document.createElement("li");
listItem.textContent = item.subject;
list.appendChild(listItem);
});
});
2. Save your changes.
Try it out
1. From a terminal, run the following code in the root directory of your project. This
starts the local web server and sideloads your add-in.
command
npm start
Tip
2. In Outlook, ensure the Reading Pane is enabled. To enable the Reading Pane, see
Use and configure the Reading Pane to preview messages .
3. Navigate to your inbox and choose multiple messages by holding Ctrl while
selecting messages.
5. In the task pane, select Run to view a list of the selected messages' subject lines.
Item multi-select behavior and limitations
Item multi-select only supports messages within an Exchange mailbox in both read and
compose modes. An Outlook add-in only activates on multiple messages if the following
conditions are met.
The messages must be selected from one Exchange mailbox at a time. Non-
Exchange mailboxes aren't supported.
The messages must be selected from one mailbox folder at a time. An add-in
doesn't activate on multiple messages if they're located in different folders, unless
Conversations view is enabled. For more information, see Multi-select in
conversations.
An add-in must implement a task pane in order to detect the
SelectedItemsChanged event.
The Reading Pane in Outlook must be enabled. An exception to this is if the item
multi-select feature is enabled through the <SupportsNoItemContext> element in
the manifest. To learn more, see Activate your Outlook add-in without the Reading
Pane enabled or a message selected.
A maximum of 100 messages can be selected at a time.
7 Note
Meeting invites and responses are considered messages, not appointments, and
can therefore be included in a selection.
Multi-select in conversations
Item multi-select supports Conversations view whether it's enabled on your mailbox
or on specific folders. The following table describes expected behaviors when
conversations are expanded or collapsed, when the conversation header is selected, and
when conversation messages are located in a different folder from the one currently in
view.
Conversation If the conversation header is the only The newest message (that is, the
header is item selected, an add-in supporting first message in the conversation
selected multi-select doesn't activate. However, if stack) is included in the message
other non-header messages are also selection.
selected, the add-in will only activate on
those and not the selected header. If the newest message in the
conversation is located in another
folder from the one currently in
view, the subsequent message in
the stack located in the current
folder is included in the selection.
Selected All chosen conversation messages are Not applicable. Only the
conversation included in the selection. conversation header is available for
messages are selection in collapsed conversation
located in the view.
same folder as
the one
currently in
view
Selection Expanded conversation view Collapsed conversation view
Selected All chosen conversation messages are Not applicable. Only the
conversation included in the selection. conversation header is available for
messages are selection in collapsed conversation
located in view.
different
folders from
the one
currently in
view
Next steps
Now that you've enabled your add-in to operate on multiple selected messages, you
can extend your add-in's capabilities and further enhance the user experience. Explore
performing more complex operations by using the selected messages' item IDs with
services such as Exchange Web Services (EWS) and Microsoft Graph.
See also
Office add-in manifests
Call web services from an Outlook add-in
Overview of Microsoft Graph
Activate your Outlook add-in without the Reading Pane enabled or a message
selected
Implement a pinnable task pane in
Outlook
Article • 04/27/2023
The task pane UX shape for add-in commands opens a vertical task pane to the right of
an open message or meeting request, allowing the add-in to provide UI for more
detailed interactions (filling in multiple fields, etc.). This task pane can be shown in the
Reading Pane when viewing a list of messages, allowing for quick processing of a
message.
However, by default, if a user has an add-in task pane open for a message in the
Reading Pane, and then selects a new message, the task pane is automatically closed.
For a heavily-used add-in, the user may prefer to keep that pane open, eliminating the
need to reactivate the add-in on each message. With pinnable task panes, your add-in
can give the user that option.
7 Note
Although the pinnable task panes feature was introduced in requirement set 1.5,
it's currently only available to Microsoft 365 subscribers using the following:
Outlook 2016 or later on Windows (Build 7668.2000 or later for users in the
Current or Microsoft 365 Insider Channels, Build 7900.xxxx or later for users in
Deferred channels)
Outlook 2016 or later on Mac (Version 16.13.503 or later)
Modern Outlook on the web
) Important
Appointments/Meetings
Outlook.com
Add the SupportsPinning element to the <Action> element that describes the task
pane button. The following is an example.
XML
7 Note
A pinnable task pane can also be enabled without the <SupportsPinning> element
if the <SupportsNoItemContext> element is included in the manifest. To learn
more, see Activate your Outlook add-in without the Reading Pane enabled or a
message selected.
JavaScript
function itemChanged(eventArgs) {
// Update UI based on the new current item
UpdateTaskPaneUI(Office.context.mailbox.item);
}
) Important
JavaScript
// Example implementation
function UpdateTaskPaneUI(item)
{
// Assuming that item is always a read item (instead of a compose
item).
if (item != null) console.log(item.subject);
}
JavaScript
Deploy to users
If you plan to publish your Outlook add-in to AppSource , and it's configured with a
pinnable task pane, your add-in content must not be static and must clearly display data
related to the message that is open or selected in the mailbox. This ensures that your
add-in will pass AppSource validation.
See also
For an example add-in that implements a pinnable task pane, see command-demo on
GitHub.
Add-ins for Outlook on mobile devices
Article • 07/13/2023
Add-ins now work in Outlook on mobile devices, using the same APIs available for other
Outlook endpoints. If you've built an add-in for Outlook already, it's easy to get it
working on Outlook mobile.
Outlook mobile add-ins are supported on all Microsoft 365 business accounts and
Outlook.com accounts. However, support is not currently available on Gmail accounts.
7 Note
Add-ins using the Unified manifest for Microsoft 365 (preview) aren't currently
supported on mobile devices.
In general, only Message Read mode is supported at this time. That means
MobileMessageReadCommandSurface is the only ExtensionPoint you should declare in
the mobile section of your manifest. However, there are a couple of exceptions.
The makeEwsRequestAsync API isn't supported on mobile since the mobile app
uses REST APIs to communicate with the server. If your app backend needs to
connect to the Exchange server, you can use the callback token to make REST API
calls. For details, see Use the Outlook REST APIs from an Outlook add-in.
When you submit your add-in to the store with MobileFormFactor in the manifest,
you'll need to agree to our developer addendum for add-ins on iOS, and you must
submit your Apple Developer ID for verification.
Finally, your manifest needs to declare MobileFormFactor , and include the correct
types of controls and icon sizes. To learn more, see Add support for add-in
commands in Outlook on mobile devices.
The add-in adds value to the user's email content by saving the information to a
tracking, collaboration, or similar system. For example, an add-in that lets users
turn emails into task items for project tracking, or help tickets for a support team.
An example user interaction to create a Trello card from an email message on iOS
An example user interaction to create a Trello card from an email message on Android
Testing your add-ins on mobile
To test an add-in on Outlook mobile, first sideload an add-in using a Microsoft 365 or
Outlook.com account in Outlook on the web, on Windows, or on Mac. Make sure your
manifest is properly formatted to contain MobileFormFactor or it won't load in Outlook
mobile.
After your add-in is working, make sure to test it on different screen sizes, including
phones and tablets. You should make sure it meets accessibility guidelines for contrast,
font size, and color, as well as being usable with a screen reader such as VoiceOver on
iOS or TalkBack on Android.
Troubleshooting on mobile can be hard since you may not have the tools you're used
to. However, one option for troubleshooting on iOS is to use Fiddler (check out this
tutorial on using it with an iOS device ).
7 Note
Next steps
Learn how to:
Using add-in commands in Outlook on mobile devices allows your users to access the
same functionality (with some limitations) that they already have in Outlook on the web,
on Windows, and on Mac. Adding support for Outlook mobile requires updating the
add-in manifest and possibly changing your code for mobile scenarios.
7 Note
Add-ins using the Unified manifest for Microsoft 365 (preview) aren't currently
supported on mobile devices.
The first step to enabling add-in commands in Outlook mobile is to define them in the
add-in manifest. The VersionOverrides v1.1 schema defines a new form factor for
mobile, MobileFormFactor.
This element contains all of the information for loading the add-in in mobile clients. This
enables you to define completely different UI elements and JavaScript files for the
mobile experience.
The following example shows a single task pane button in a MobileFormFactor element.
XML
<VersionOverrides
xmlns="http://schemas.microsoft.com/office/mailappversionoverrides/1.1"
xsi:type="VersionOverridesV1_1">
...
<MobileFormFactor>
<FunctionFile resid="residUILessFunctionFileUrl" />
<ExtensionPoint xsi:type="MobileMessageReadCommandSurface">
<Group id="mobileMsgRead">
<Label resid="groupLabel" />
<Control xsi:type="MobileButton" id="TaskPaneBtn">
<Label resid="residTaskPaneButtonName" />
<Icon xsi:type="bt:MobileIconList">
<bt:Image size="25" scale="1" resid="tp0icon" />
<bt:Image size="25" scale="2" resid="tp0icon" />
<bt:Image size="25" scale="3" resid="tp0icon" />
<bt:Image size="32" scale="1" resid="tp0icon" />
<bt:Image size="32" scale="2" resid="tp0icon" />
<bt:Image size="32" scale="3" resid="tp0icon" />
This is very similar to the elements that appear in a DesktopFormFactor element, with
some notable differences.
Code considerations
Designing an add-in for mobile introduces some additional considerations.
Pinch zoom
By default users can use the "pinch zoom" gesture to zoom in on task panes. If this
doesn't make sense for your scenario, be sure to disable pinch zoom in your HTML.
Supported APIs
Although Outlook mobile supports up to Mailbox requirement set 1.5, you can now
implement additional APIs from later requirement sets to further extend the capability
of your add-in on Outlook mobile. For guidance on which APIs you can implement in
your mobile add-in, see Outlook JavaScript APIs supported in Outlook on mobile
devices.
See also
Requirement sets supported by Exchange servers and Outlook clients
Outlook JavaScript APIs supported in Outlook on mobile devices
Outlook JavaScript APIs supported in
Outlook on mobile devices
Article • 07/13/2023
Outlook on Android and on iOS support up to Mailbox requirement set 1.5. To further
extend the capabilities of an Outlook mobile add-in, certain APIs from later requirement
sets, previously available only to Outlook desktop and web clients, are now enabled for
mobile support. This article outlines the APIs supported in Outlook mobile and any
implementation exceptions.
Supported APIs
The following table lists a subset of APIs from requirement sets beyond 1.5 that can now
be implemented in Outlook mobile add-ins. Even if the minimum requirement set
specified in the manifest of your add-in is greater than 1.5, as long as the API used from
the later requirement set is supported, the add-in will appear and activate in Outlook on
Android or on iOS. For more information on how to specify the minimum requirement
set in your add-in, see Outlook JavaScript API requirement sets.
Unsupported APIs
Although Outlook mobile supports up to requirement set 1.5, there are some APIs from
these earlier requirement sets that aren't supported. The following table lists these APIs
and also notes features that aren't supported in certain Outlook modes.
- Appointment
Organizer
Office.context.mailbox.item.to.addAsync
Office.context.mailbox.item.to.setAsync
See also
Outlook JavaScript API requirement sets
Add-ins for Outlook on mobile devices
Add support for add-in commands in Outlook on mobile devices
Requirement sets supported by Exchange servers and Outlook clients
Log appointment notes to an external
application in Outlook mobile add-ins
Article • 07/13/2023
In this article, you'll learn how to set up your Outlook mobile add-in to enable users to
log notes and other details about their appointments to your CRM or note-taking
application. Throughout this article, we'll be using a fictional CRM service provider
named "Contoso".
Supported clients
Logging notes to an external application from an Outlook mobile add-in is supported in
Outlook on Android and on iOS with a Microsoft 365 subscription.
Function command
This option will enable a user to log and view their notes and other details about
their appointments when they select a function command from the ribbon.
Add-ins using the Unified manifest for Microsoft 365 (preview) aren't
currently supported on mobile devices.
3. Select the entire <VersionOverrides> node (including open and close tags)
and replace it with the following XML. Make sure to replace all references to
Contoso with your company's information.
XML
<VersionOverrides
xmlns="http://schemas.microsoft.com/office/mailappversionoverrides"
xsi:type="VersionOverridesV1_0">
<VersionOverrides
xmlns="http://schemas.microsoft.com/office/mailappversionoverrides/
1.1" xsi:type="VersionOverridesV1_1">
<Description resid="residDescription"></Description>
<Requirements>
<bt:Sets>
<bt:Set Name="Mailbox" MinVersion="1.3"/>
</bt:Sets>
</Requirements>
<Hosts>
<Host xsi:type="MailHost">
<DesktopFormFactor>
<FunctionFile resid="residFunctionFile"/>
<ExtensionPoint
xsi:type="AppointmentAttendeeCommandSurface">
<OfficeTab id="TabDefault">
<Group id="apptReadGroup">
<Label resid="residDescription"/>
<Control xsi:type="Button"
id="apptReadOpenPaneButton">
<Label resid="residLabel"/>
<Supertip>
<Title resid="residLabel"/>
<Description resid="residTooltip"/>
</Supertip>
<Icon>
<bt:Image size="16" resid="icon-16"/>
<bt:Image size="32" resid="icon-32"/>
<bt:Image size="80" resid="icon-80"/>
</Icon>
<Action xsi:type="ExecuteFunction">
<FunctionName>logCRMEvent</FunctionName>
</Action>
</Control>
</Group>
</OfficeTab>
</ExtensionPoint>
</DesktopFormFactor>
<MobileFormFactor>
<FunctionFile resid="residFunctionFile"/>
<ExtensionPoint
xsi:type="MobileLogEventAppointmentAttendee">
<Control xsi:type="MobileButton"
id="appointmentReadFunctionButton">
<Label resid="residLabel"/>
<Icon>
<bt:Image size="25" scale="1" resid="icon-16"/>
<bt:Image size="25" scale="2" resid="icon-16"/>
<bt:Image size="25" scale="3" resid="icon-16"/>
<bt:Image size="32" scale="1" resid="icon-32"/>
<bt:Image size="32" scale="2" resid="icon-32"/>
<bt:Image size="32" scale="3" resid="icon-32"/>
<bt:Image size="48" scale="1" resid="icon-48"/>
<bt:Image size="48" scale="2" resid="icon-48"/>
<bt:Image size="48" scale="3" resid="icon-48"/>
</Icon>
<Action xsi:type="ExecuteFunction">
<FunctionName>logCRMEvent</FunctionName>
</Action>
</Control>
</ExtensionPoint>
</MobileFormFactor>
</Host>
</Hosts>
<Resources>
<bt:Images>
<bt:Image id="icon-16"
DefaultValue="https://contoso.com/assets/icon-16.png"/>
<bt:Image id="icon-32"
DefaultValue="https://contoso.com/assets/icon-32.png"/>
<bt:Image id="icon-48"
DefaultValue="https://contoso.com/assets/icon-48.png"/>
<bt:Image id="icon-80"
DefaultValue="https://contoso.com/assets/icon-80.png"/>
</bt:Images>
<bt:Urls>
<bt:Url id="residFunctionFile"
DefaultValue="https://contoso.com/commands.html"/>
</bt:Urls>
<bt:ShortStrings>
<bt:String id="residDescription" DefaultValue="Log
appointment notes and other details to Contoso CRM."/>
<bt:String id="residLabel" DefaultValue="Log to Contoso
CRM"/>
</bt:ShortStrings>
<bt:LongStrings>
<bt:String id="residTooltip" DefaultValue="Log notes to
Contoso CRM for this appointment."/>
</bt:LongStrings>
</Resources>
</VersionOverrides>
</VersionOverrides>
Tip
To learn more about manifests for Outlook add-ins, see Office add-in
manifests and Add support for add-in commands in Outlook on mobile
devices.
2. Replace the entire content of the commands.js file with the following
JavaScript.
JavaScript
var event;
function logCRMEvent(appointmentEvent) {
event = appointmentEvent;
console.log(`Subject: ${Office.context.mailbox.item.subject}`);
Office.context.mailbox.item.body.getAsync(
"html",
{ asyncContext: "This is passed to the callback" },
function callback(result) {
if (result.status === Office.AsyncResultStatus.Succeeded) {
event.completed({ allowEvent: true });
} else {
console.error("Failed to get body.");
event.completed({ allowEvent: false });
}
}
);
}
// Register the function.
Office.actions.associate("logCRMEvent", logCRMEvent);
HTML
<script type="text/javascript"
src="https://appsforoffice.microsoft.com/lib/1.1/hosted/office.js">
</script>
<script type="text/javascript" src="commands.js"></script>
Your add-in defines the log viewing experience. For example, you can display the
logged appointment notes in a dialog when the user selects the View button. For
details on using dialogs, refer to Use the Office dialog API in your Office Add-ins.
JavaScript
function updateCustomProperties() {
Office.context.mailbox.item.loadCustomPropertiesAsync(
function callback(customPropertiesResult) {
if (customPropertiesResult.status ===
Office.AsyncResultStatus.Succeeded) {
let customProperties = customPropertiesResult.value;
customProperties.set("EventLogged", true);
customProperties.saveAsync(
function callback(setSaveAsyncResult) {
if (setSaveAsyncResult.status ===
Office.AsyncResultStatus.Succeeded) {
console.log("EventLogged custom property saved
successfully.");
event.completed({ allowEvent: true });
event = undefined;
}
}
);
}
}
);
}
Then, call it after the add-in successfully logs the appointment notes. For example,
you can call it from logCRMEvent as shown in the following function.
JavaScript
function logCRMEvent(appointmentEvent) {
event = appointmentEvent;
console.log(`Subject: ${Office.context.mailbox.item.subject}`);
Office.context.mailbox.item.body.getAsync(
"html",
{ asyncContext: "This is passed to the callback" },
function callback(result) {
if (result.status === Office.AsyncResultStatus.Succeeded) {
// Replace `event.completed({ allowEvent: true });` with the
following statement.
updateCustomProperties();
} else {
console.error("Failed to get body.");
event.completed({ allowEvent: false });
}
}
);
}
1. Use Microsoft Graph to clear the custom properties object when the user
selects the appropriate button on the ribbon.
JavaScript
function clearCustomProperties() {
Office.context.mailbox.item.loadCustomPropertiesAsync(
function callback(customPropertiesResult) {
if (customPropertiesResult.status ===
Office.AsyncResultStatus.Succeeded) {
var customProperties = customPropertiesResult.value;
customProperties.remove("EventLogged");
customProperties.saveAsync(
function callback(removeSaveAsyncResult) {
if (removeSaveAsyncResult.status ===
Office.AsyncResultStatus.Succeeded) {
console.log("Custom properties cleared");
event.completed({ allowEvent: true });
event = undefined;
}
}
);
}
}
);
}
Then, call it when you want to clear the custom property. For example, you can call
it from logCRMEvent if setting the log failed in some way as shown in the following
function.
JavaScript
function logCRMEvent(appointmentEvent) {
event = appointmentEvent;
console.log(`Subject: ${Office.context.mailbox.item.subject}`);
Office.context.mailbox.item.body.getAsync(
"html",
{ asyncContext: "This is passed to the callback" },
function callback(result) {
if (result.status === Office.AsyncResultStatus.Succeeded) {
updateCustomProperties();
} else {
console.error("Failed to get body.");
// Replace `event.completed({ allowEvent: false });` with the
following statement.
clearCustomProperties();
}
}
);
}
Available APIs
The following APIs are available for this feature.
Dialog APIs
Office.AddinCommands.Event
Office.CustomProperties
Office.RoamingSettings
Appointment Read (attendee) APIs except the following:
Office.context.mailbox.item.categories
Office.context.mailbox.item.enhancedLocation
Office.context.mailbox.item.isAllDayEvent
Office.context.mailbox.item.recurrence
Office.context.mailbox.item.sensitivity
Office.context.mailbox.item.seriesId
To learn more about APIs that are supported in Outlook on mobile devices, see Outlook
JavaScript APIs supported in Outlook on mobile devices.
Restrictions
Several restrictions apply.
The Log button name can't be changed. However, there's a way for a different
label to be displayed by setting a custom property on the appointment item. For
more details, refer to the View appointment notes section for function command
or task pane as appropriate.
The EventLogged custom property must be used if you want to toggle the label of
the Log button to View and back.
The add-in icon should be in grayscale using hex code #919191 or its equivalent in
other color formats .
The add-in should extract the meeting details from the appointment form within
the one-minute timeout period. However, any time spent in a dialog box the add-
in opened for authentication, for example, is excluded from the timeout period.
See also
Add-ins for Outlook on mobile devices
Add support for add-in commands in Outlook on mobile devices
Outlook JavaScript APIs supported in Outlook on mobile devices
Implement event-based activation in
Outlook mobile add-ins
Article • 07/13/2023
With the event-based activation feature, develop an add-in to automatically activate and
complete operations when certain events occur in Outlook on Android or on iOS, such
as composing a new message.
The following sections walk you through how to develop an Outlook mobile add-in that
automatically adds a signature to new messages being composed. This highlights a
sample scenario of how you can implement event-based activation in your mobile add-
in. Significantly enhance the mobile user experience by exploring other scenarios in your
add-in today.
To learn how to implement an event-based add-in for Outlook desktop clients, see
Configure your Outlook add-in for event-based activation.
7 Note
Outlook on Android and on iOS only support up to Mailbox requirement set 1.5.
However, to support the event-based activation feature, some APIs from later
requirement sets have been enabled on mobile clients. For more information on
this exception, see Additional supported APIs.
Supported clients
The add-in you develop in this walkthrough is supported in Outlook on Android and on
iOS with a Microsoft 365 subscription.
7 Note
The Unified Microsoft 365 manifest (preview) isn't currently supported on mobile
devices.
To enable an event-based add-in on Outlook mobile, you must configure the following
elements in the VersionOverridesV1_1 node of the manifest.
In the Runtimes element, specify the HTML file that references the event-handling
JavaScript file.
Add the MobileFormFactor element to make your add-in available in Outlook
mobile.
Set the xsi:type of the ExtensionPoint element to LaunchEvent. This enables the
event-based activation feature in your Outlook mobile add-in.
In the LaunchEvent element, set the Type to OnNewMessageCompose and specify the
JavaScript function name of the event handler in the FunctionName attribute.
1. In your code editor, open the quick start project you created.
3. Select the entire <VersionOverrides> node (including the open and close tags)
and replace it with the following XML.
XML
<VersionOverrides
xmlns="http://schemas.microsoft.com/office/mailappversionoverrides"
xsi:type="VersionOverridesV1_0">
<VersionOverrides
xmlns="http://schemas.microsoft.com/office/mailappversionoverrides/1.1"
xsi:type="VersionOverridesV1_1">
<Requirements>
<bt:Sets DefaultMinVersion="1.5">
<bt:Set Name="Mailbox"/>
</bt:Sets>
</Requirements>
<Hosts>
<Host xsi:type="MailHost">
<!-- The HTML file that references or contains the
JavaScript event handlers.
This is used by Outlook on mobile devices. -->
<Runtimes>
<Runtime resid="WebViewRuntime.Url">
</Runtime>
</Runtimes>
<!-- Defines the add-in for Outlook on Windows, on Mac,
and on the web. -->
<DesktopFormFactor>
<FunctionFile resid="Commands.Url"/>
<ExtensionPoint
xsi:type="MessageReadCommandSurface">
<OfficeTab id="TabDefault">
<Group id="msgReadGroup">
<Label resid="GroupLabel"/>
<Control xsi:type="Button"
id="msgReadOpenPaneButton">
<Label
resid="TaskpaneButton.Label"/>
<Supertip>
<Title
resid="TaskpaneButton.Label"/>
<Description
resid="TaskpaneButton.Tooltip"/>
</Supertip>
<Icon>
<bt:Image size="16"
resid="Icon.16x16"/>
<bt:Image size="32"
resid="Icon.32x32"/>
<bt:Image size="80"
resid="Icon.80x80"/>
</Icon>
<Action xsi:type="ShowTaskpane">
<SourceLocation
resid="Taskpane.Url"/>
</Action>
</Control>
<Control xsi:type="Button"
id="ActionButton">
<Label resid="ActionButton.Label"/>
<Supertip>
<Title
resid="ActionButton.Label"/>
<Description
resid="ActionButton.Tooltip"/>
</Supertip>
<Icon>
<bt:Image size="16"
resid="Icon.16x16"/>
<bt:Image size="32"
resid="Icon.32x32"/>
<bt:Image size="80"
resid="Icon.80x80"/>
</Icon>
<Action xsi:type="ExecuteFunction">
<FunctionName>action</FunctionName>
</Action>
</Control>
</Group>
</OfficeTab>
</ExtensionPoint>
</DesktopFormFactor>
<!-- Defines the add-in for Outlook mobile. -->
<MobileFormFactor>
<!-- Configures event-based activation. -->
<ExtensionPoint xsi:type="LaunchEvent">
<LaunchEvents>
<LaunchEvent Type="OnNewMessageCompose"
FunctionName="onNewMessageComposeHandler"/>
</LaunchEvents>
<!-- Identifies the runtime to be used (also
referenced by the Runtime element). -->
<SourceLocation resid="WebViewRuntime.Url"/>
</ExtensionPoint>
</MobileFormFactor>
</Host>
</Hosts>
<!-- This manifest uses a fictitious web server, contoso.com,
to host the add-in's files.
Replace these instances with the information of the web
server that hosts your add-in's files. -->
<Resources>
<bt:Images>
<bt:Image id="Icon.16x16"
DefaultValue="https://contoso.com/assets/icon-16.png"/>
<bt:Image id="Icon.32x32"
DefaultValue="https://contoso.com/assets/icon-32.png"/>
<bt:Image id="Icon.80x80"
DefaultValue="https://contoso.com/assets/icon-80.png"/>
</bt:Images>
<bt:Urls>
<bt:Url id="Commands.Url"
DefaultValue="https://contoso.com/commands.html"/>
<bt:Url id="Taskpane.Url"
DefaultValue="https://contoso.com/taskpane.html"/>
<bt:Url id="WebViewRuntime.Url"
DefaultValue="https://contoso.com/commands.html"/>
</bt:Urls>
<bt:ShortStrings>
<bt:String id="GroupLabel" DefaultValue="Event-based
activation on mobile"/>
<bt:String id="TaskpaneButton.Label" DefaultValue="Show
Taskpane"/>
<bt:String id="ActionButton.Label"
DefaultValue="Perform an action"/>
</bt:ShortStrings>
<bt:LongStrings>
<bt:String id="TaskpaneButton.Tooltip"
DefaultValue="Opens a pane displaying all available properties."/>
<bt:String id="ActionButton.Tooltip"
DefaultValue="Perform an action when clicked."/>
</bt:LongStrings>
</Resources>
</VersionOverrides>
</VersionOverrides>
To learn more about manifests for Outlook add-ins, see Outlook add-in manifests
and Add support for add-in commands in Outlook on mobile devices.
composed, then shows a message to notify that the signature was added.
1. From the same quick start project, navigate to the ./src directory, then create a
new folder named launchevent.
3. Open the launchevent.js file you created and add the following JavaScript code.
JavaScript
/*
* Copyright (c) Microsoft Corporation. All rights reserved. Licensed
under the MIT license.
* See LICENSE in the project root for license information.
*/
function onNewMessageComposeHandler(event) {
const item = Office.context.mailbox.item;
const signatureIcon =
"iVBORw0KGgoAAAANSUhEUgAAACcAAAAnCAMAAAC7faEHAAAAAXNSR0IArs4c6QAAAARnQU
1BAACxjwv8YQUAAAAzUExURQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAKMFRskAAAAQdFJOUwAQIDBAUGBwgI+fr7/P3+8jGoKKAAAACXBI
WXMAAA7DAAAOwwHHb6hkAAABT0lEQVQ4T7XT2ZalIAwF0DAJhMH+/6+tJOQqot6X6joPiou
NBo3w9/Hd6+hrYnUt6vhLcjEAJevVW0zJxABSlcunhERpjY+UKoNN5+ZgDGu2onNz0OngjP
2FM1VdyBW1LtvGeYrBLs7U5I1PTXZt+zifcS3Icw2GcS3vxRY3Vn/iqx31hUyTnV515kdTf
baNhZLI30AceqDiIo4tyKEmJpKdP5M4um+nUwfDWxAXdzqMNKQ14jLdL5ntXzxcRF440mhS
6yu882Kxa30RZcUIjTCJg7lscsR4VsMjfX9Q0Vuv/Wd3YosD1J4LuSRtaL7bzXGN1wx2cyt
UdncDuhA3fu6HPTiCvpQUIjZ3sCcHVbvLtbNTHlysx2w9/s27m9gEb+7CTri6hR1wcTf2gV
f3wBRe3CMbcHYvTODkXhnD0+178K/pZ9+n/C1ru/2HAPwAo7YM1X4+tLMAAAAASUVORK5CY
II=";
item.notificationMessages.addAsync("signature_notification",
notification, (result) => {
if (result.status ===
Office.AsyncResultStatus.Failed) {
console.log(result.error.message);
event.completed({ allowEvent: false });
return;
}
2. Immediately before the closing head tag ( </head> ), add a script entry for the
JavaScript file that contains the event handler.
HTML
3. Open Outlook on Android or on iOS. If you have Outlook already open on your
device, restart it.
4. Create a new message. The event-based add-in adds the signature to the message.
If you have a signature saved on your mobile device, it will briefly appear in the
message you create, but will be immediately replaced by the signature added by
the add-in.
Behavior and limitations
As you develop an event-based add-in for Outlook mobile, be mindful of the following
feature behaviors and limitations.
Office.context.mailbox.item.addFileAttachmentFromBase64Async
Office.context.mailbox.item.disableClientSignatureAsync
Office.context.mailbox.item.from.getAsync
Office.context.mailbox.item.getComposeTypeAsync
Office.context.mailbox.item.body.setSignatureAsync
To learn more about APIs that are supported in Outlook on mobile devices, see Outlook
JavaScript APIs supported in Outlook on mobile devices.
Deploy to users
Event-based add-ins must be deployed by an organization's administrator. For guidance
on how to deploy your add-in via the Microsoft 365 admin center, see the "Deploy to
users" section of Configure your Outlook add-in for event-based activation.
See also
Configure your Outlook add-in for event-based activation
Add-ins for Outlook on mobile devices
Add mobile support to an Outlook add-in
Outlook JavaScript APIs supported in Outlook on mobile devices
Create an Outlook add-in for an online-
meeting provider
Article • 03/21/2023
Setting up an online meeting is a core experience for an Outlook user, and it's easy to
create a Teams meeting with Outlook. However, creating an online meeting in Outlook
with a non-Microsoft service can be cumbersome. By implementing this feature, service
providers can streamline the online meeting creation and joining experience for their
Outlook add-in users.
) Important
This feature is supported in Outlook on the web, Windows, Mac, Android, and iOS
with a Microsoft 365 subscription.
In this article, you'll learn how to set up your Outlook add-in to enable users to organize
and join a meeting using your online-meeting service. Throughout this article, we'll use
a fictional online-meeting service provider, "Contoso".
If your add-in uses an XML manifest, and the add-in will only be supported in Outlook
on the web, Windows, and Mac, select the Windows, Mac, web tab for guidance.
However, if your add-in will also be supported in Outlook on Android and iOS, select the
Mobile tab.
If the add-in uses the unified manifest (preview), select the Unified manifest for
Microsoft 365 (developer preview) tab.
) Important
Online meeting providers aren't yet supported for the unified manifest (preview).
We're working on providing that support soon.
1. In your code editor, open the Outlook quick start project you created.
3. Select the entire <VersionOverrides> node (including open and close tags)
and replace it with the following XML.
XML
<VersionOverrides
xmlns="http://schemas.microsoft.com/office/mailappversionoverrides"
xsi:type="VersionOverridesV1_0">
<VersionOverrides
xmlns="http://schemas.microsoft.com/office/mailappversionoverrides/1.1"
xsi:type="VersionOverridesV1_1">
<Description resid="residDescription"></Description>
<Requirements>
<bt:Sets>
<bt:Set Name="Mailbox" MinVersion="1.3"/>
</bt:Sets>
</Requirements>
<Hosts>
<Host xsi:type="MailHost">
<DesktopFormFactor>
<FunctionFile resid="residFunctionFile"/>
<ExtensionPoint xsi:type="AppointmentOrganizerCommandSurface">
<OfficeTab id="TabDefault">
<Group id="apptComposeGroup">
<Label resid="residDescription"/>
<Control xsi:type="Button" id="insertMeetingButton">
<Label resid="residLabel"/>
<Supertip>
<Title resid="residLabel"/>
<Description resid="residTooltip"/>
</Supertip>
<Icon>
<bt:Image size="16" resid="icon-16"/>
<bt:Image size="32" resid="icon-32"/>
<bt:Image size="64" resid="icon-64"/>
<bt:Image size="80" resid="icon-80"/>
</Icon>
<Action xsi:type="ExecuteFunction">
<FunctionName>insertContosoMeeting</FunctionName>
</Action>
</Control>
</Group>
</OfficeTab>
</ExtensionPoint>
</DesktopFormFactor>
</Host>
</Hosts>
<Resources>
<bt:Images>
<bt:Image id="icon-16"
DefaultValue="https://contoso.com/assets/icon-16.png"/>
<bt:Image id="icon-32"
DefaultValue="https://contoso.com/assets/icon-32.png"/>
<bt:Image id="icon-48"
DefaultValue="https://contoso.com/assets/icon-48.png"/>
<bt:Image id="icon-64"
DefaultValue="https://contoso.com/assets/icon-64.png"/>
<bt:Image id="icon-80"
DefaultValue="https://contoso.com/assets/icon-80.png"/>
</bt:Images>
<bt:Urls>
<bt:Url id="residFunctionFile"
DefaultValue="https://contoso.com/commands.html"/>
</bt:Urls>
<bt:ShortStrings>
<bt:String id="residDescription" DefaultValue="Contoso
meeting"/>
<bt:String id="residLabel" DefaultValue="Add a contoso
meeting"/>
</bt:ShortStrings>
<bt:LongStrings>
<bt:String id="residTooltip" DefaultValue="Add a contoso meeting
to this appointment."/>
</bt:LongStrings>
</Resources>
</VersionOverrides>
</VersionOverrides>
Tip
To learn more about manifests for Outlook add-ins, see Office add-in manifests
and Add support for add-in commands in Outlook on mobile devices.
1. From the same quick start project, open the file ./src/commands/commands.js in
your code editor.
2. Replace the entire content of the commands.js file with the following JavaScript.
JavaScript
let mailboxItem;
// Office is ready.
Office.onReady(function () {
mailboxItem = Office.context.mailbox.item;
}
);
Create meeting UI
As a meeting organizer, you should see screens similar to the following three images
when you create a meeting.
Join meeting UI
As a meeting attendee, you should see a screen similar to the following image when you
view the meeting.
) Important
The Join button is only supported in Outlook on the web, Mac, Android, and iOS. If
you only see a meeting link, but don't see the Join button in a supported client, it
may be that the online-meeting template for your service isn't registered on our
servers. See the Register your online-meeting template section for details.
The Join button is only supported in Outlook on the web, Mac, Android, and iOS.
Available APIs
The following APIs are available for this feature.
Restrictions
Several restrictions apply.
See also
Add-ins for Outlook on mobile devices
Add support for add-in commands in Outlook on mobile devices
On-send feature for Outlook add-ins
Article • 03/21/2023
The on-send feature for Outlook add-ins provides a way to handle a message or
meeting item, or block users from certain actions, and allows an add-in to set certain
properties on send.
7 Note
The on-send feature isn't supported in add-ins that use the Unified manifest for
Microsoft 365 (preview). Achieve similar effects by using event-based activation
and implementing a handler for the OnMessageSend or OnAppointmentSend
events, or both.
Prevent a user from sending sensitive information or leaving the subject line blank.
Add a specific recipient to the CC line in messages, or to the optional recipients
line in meetings.
The on-send feature is triggered by the ItemSend event type and is UI-less.
For information about limitations related to the on-send feature, see Limitations later in
this article.
7 Note
It offers send mode options when you want to provide your users with
optional recommendations instead of mandatory conditions.
It allows your add-in to be published to AppSource if the send mode property
is set to the prompt user or soft block option. To learn more about publishing
an event-based add-in, see AppSource listing options for your event-based
Outlook add-in.
For more information on the differences between Smart Alerts and the on-send
feature, see Differences between Smart Alerts and the on-send feature. We invite
you to try out Smart Alerts by completing the walkthrough.
7 Note
The on-send feature was officially released in requirement set 1.8 (see current
server and client support for details). However, note that the feature's support
matrix is a superset of the requirement set's.
) Important
button (or the Send Update button for existing meetings) and can be used to block the
item from sending if the validation fails. For example, when a user triggers a message
send event, an Outlook add-in that uses the on-send feature can:
Validation is done on the client side in Outlook when the send event is triggered, and
the add-in has up to 5 minutes before it times out. If validation fails, the sending of the
item is blocked, and an error message is displayed in an information bar that prompts
the user to take action.
7 Note
In Outlook on the web, when the on-send feature is triggered in a message being
composed within the Outlook browser tab, the item is popped out to its own
browser window or tab in order to complete validation and other processing.
The following screenshot shows an information bar that notifies the sender to add a
subject.
The following screenshot shows an information bar that notifies the sender that blocked
words were found.
Limitations
The on-send feature currently has the following limitations.
AppSource – You can't publish Outlook add-ins that use the on-send feature to
AppSource as they will fail AppSource validation. Add-ins that use the on-send
feature should be deployed by administrators. If you want the option to publish
your add-in to AppSource, consider using Smart Alerts instead, which is a newer
version of the on-send feature. To learn more about Smart Alerts and how to
deploy these add-ins, see Use Smart Alerts and the OnMessageSend and
OnAppointmentSend events in your Outlook add-in and AppSource listing options
for your event-based Outlook add-in.
) Important
When running npm run validate to validate your add-in's manifest, you'll
receive the error, "Mailbox add-in containing ItemSend event is invalid.
Mailbox add-in manifest contains ItemSend event in VersionOverrides which is
not allowed." This message appears because add-ins that use the ItemSend
event, which is required for this version of the on-send feature, can't be
published to AppSource. You'll still be able to sideload and run your add-in,
provided that no other validation errors are found.
Manifest – Only one ItemSend event is supported per add-in. If you have two or
more ItemSend events in a manifest, the manifest will fail validation.
Performance – Multiple roundtrips to the web server that hosts the add-in can
affect the performance of the add-in. Consider the effects on performance when
you create add-ins that require multiple message- or meeting-based operations.
Send Later (Mac only) – If there are on-send add-ins, the Send Later feature will be
unavailable.
Also, it's not recommended that you call item.close() in the on-send event handler as
closing the item should happen automatically after the event is completed.
In cases where Outlook add-ins don't activate, the on-send add-in won't run and the
message will be sent.
However, if the on-send feature is enabled and available but the mailbox scenario is
unsupported, Outlook won't allow sending.
For example, Add-in1 and Add-in2 both use the on-send feature. Add-in1 is installed
first, and Add-in2 is installed second. Add-in1 verifies that the word Fabrikam appears in
the message as a condition for the add-in to allow send. However, Add-in2 removes any
occurrences of the word Fabrikam. The message will send with all instances of Fabrikam
removed (due to the order of installation of Add-in1 and Add-in2).
Deploy Outlook add-ins that use on-send
We recommend that administrators deploy Outlook add-ins that use the on-send
feature. Administrators have to ensure that the on-send add-in:
Is always present any time a compose item is opened (for email: new, reply, or
forward).
Can't be closed or disabled by the user.
Windows
Add-ins for Outlook on Windows that use the on-send feature should run for any
users who have them installed. However, if users are required to run the add-in to
meet compliance standards, then the group policy Block send when web add-ins
can't load must be set to Enabled on each applicable machine.
7 Note
In older versions of the Administrative Templates tool, the policy name was
Disable send when web extensions can't load. Substitute in this name in later
steps if needed.
For compliance reasons, administrators may need to ensure that users cannot send
message or meeting items until the latest on-send add-in is available to run.
Administrators must enable the group policy Block send when web add-ins can't
load so that all add-ins are updated from Exchange and available to verify each
message or meeting item meets expected rules and regulations on send.
Policy Result
status
Disabled The currently downloaded manifests of the on-send add-ins (not necessarily the
latest versions) run on message or meeting items being sent. This is the default
status/behavior.
Enabled After the latest manifests of the on-send add-ins are downloaded from
Exchange, the add-ins are run on message or meeting items being sent.
Otherwise, send is blocked.
and Initialize your Office Add-in). If your handler code is dynamically defined by certain
circumstances during initialization, you must create a stub function to call the handler
once it's completely defined. The stub function must be referenced in the <Event>
element's FunctionName attribute of your manifest. This workaround ensures that your
handler is defined and ready to be referenced once Office.initialize or
Office.onReady() runs.
If your handler isn't defined once your add-in is initialized, the sender will be notified
that "The callback function is unreachable" through an information bar in the mail item.
User's state
The on-send add-ins will run during send if the user is online. If the user is offline, the
on-send add-ins will not run during send and the message or meeting item will not be
sent.
An on-send add-in will run if its backend is online and reachable. If the backend is
offline, send is disabled.
Exchange's state
The on-send add-ins will run during send if the Exchange server is online and reachable.
If the on-send add-in cannot reach Exchange and the applicable policy or cmdlet is
turned on, send is disabled.
7 Note
On Mac in any offline state, the Send button (or the Send Update button for
existing meetings) is disabled and a notification displayed that their organization
doesn't allow send when the user is offline.
) Important
Modern Outlook on the web: To prevent the user from editing the item while your
add-in is processing on send, you should set the OnSendAddinsEnabled flag to
true as described in the Install Outlook add-ins that use on-send section earlier in
this article.
1. Call displayDialogAsync to open a dialog so that mouse clicks and keystrokes are
disabled.
) Important
To get this behavior in classic Outlook on the web, you should set the
displayInIframe property to true in the options parameter of the
displayDialogAsync call.
3. Close the dialog. Also, handle what happens if the user closes the dialog.
Code examples
The following code examples show you how to create a simple on-send add-in. To
download the code sample that these examples are based on, see Outlook-Add-in-On-
Send .
Tip
If you use a dialog with the on-send event, make sure to close the dialog before
completing the event.
Contoso Message Body Checker.xml – Shows how to check the body of a message
for restricted words or sensitive information on send.
Contoso Subject and CC Checker.xml – Shows how to add a recipient to the CC line
In the Contoso Message Body Checker.xml manifest file, you include the function file and
function name that should be called on the ItemSend event. The operation runs
synchronously.
XML
<Hosts>
<Host xsi:type="MailHost">
<DesktopFormFactor>
<!-- The functionfile and function name to call on message send.
-->
<!-- In this case, the function validateBody will be called
within the JavaScript code referenced in residUILessFunctionFileUrl. -->
<FunctionFile resid="residUILessFunctionFileUrl" />
<ExtensionPoint xsi:type="Events">
<Event Type="ItemSend" FunctionExecution="synchronous"
FunctionName="validateBody" />
</ExtensionPoint>
</DesktopFormFactor>
</Host>
</Hosts>
) Important
If you are using Visual Studio 2019 to develop your on-send add-in, you may get a
validation warning like the following: "This is an invalid xsi:type
'http://schemas.microsoft.com/office/mailappversionoverrides/1.1:Events'." To work
around this, you'll need a newer version of the MailAppVersionOverridesV1_1.xsd
which has been provided as a GitHub gist in a blog about this warning .
For the Contoso Subject and CC Checker.xml manifest file, the following example shows
the function file and function name to call on message send event.
XML
<Hosts>
<Host xsi:type="MailHost">
<DesktopFormFactor>
<!-- The functionfile and function name to call on message send.
-->
<!-- In this case the function validateSubjectAndCC will be
called within the JavaScript code referenced in residUILessFunctionFileUrl.
-->
<FunctionFile resid="residUILessFunctionFileUrl" />
<ExtensionPoint xsi:type="Events">
<Event Type="ItemSend" FunctionExecution="synchronous"
FunctionName="validateSubjectAndCC" />
</ExtensionPoint>
</DesktopFormFactor>
</Host>
</Hosts>
The on-send API requires VersionOverrides v1_1 . The following shows you how to add
the VersionOverrides node in your manifest.
XML
<VersionOverrides
xmlns="http://schemas.microsoft.com/office/mailappversionoverrides"
xsi:type="VersionOverridesV1_0">
<!-- On-send requires VersionOverridesV1_1 -->
<VersionOverrides
xmlns="http://schemas.microsoft.com/office/mailappversionoverrides/1.1"
xsi:type="VersionOverridesV1_1">
...
</VersionOverrides>
</VersionOverrides>
7 Note
To access the currently selected message or meeting item (in this example, the newly
composed message), use the Office.context.mailbox.item namespace. The ItemSend
event is automatically passed by the on-send feature to the function specified in the
manifest—in this example, the validateBody function.
JavaScript
let mailboxItem;
// Entry point for Contoso Message Body Checker add-in before send is
allowed.
// <param name="event">ItemSend event is automatically passed by on-send
code to the function specified in the manifest.</param>
function validateBody(event) {
mailboxItem.body.getAsync("html", { asyncContext: event },
checkBodyOnlyOnSendCallBack);
}
The validateBody function gets the current body in the specified format (HTML) and
passes the ItemSend event object that the code wants to access in the callback function.
In addition to the getAsync method, the Body object also provides a setAsync method
that you can use to replace the body with the specified text.
7 Note
JavaScript
if (checkBody) {
mailboxItem.notificationMessages.addAsync('NoSend', { type:
'errorMessage', message: 'Blocked words have been found in the body of this
email. Please remove them.' });
// Block send.
asyncResult.asyncContext.completed({ allowEvent: false });
}
// Allow send.
asyncResult.asyncContext.completed({ allowEvent: true });
}
message. You can use it to modify this message later. The key can't be longer than
32 characters.
type – One of the properties of the JSON object parameter. Represents the type of
message – One of the properties of the JSON object parameter. In this example,
message is the text of the notification message.
To signal that the add-in has finished processing the ItemSend event triggered by the
send operation, call the event.completed({allowEvent:Boolean}) method. The
allowEvent property is a Boolean. If set to true , send is allowed. If set to false , the
7 Note
JavaScript
// Block send.
asyncResult.asyncContext.completed({ allowEvent: false });
}
else {
// Allow send.
asyncResult.asyncContext.completed({ allowEvent: true });
}
});
}
To learn more about how to add a recipient to the CC line and verify that the email
message includes a subject line on send, and to see the APIs you can use, see the
Outlook-Add-in-On-Send sample . The code is well commented.
Tip
If the error "The callback function is unreachable" appears when your users run
your add-in and your add-in's event handler is dynamically defined, you must
create a stub function as a workaround. See Event handlers are dynamically
defined for more information.
See also
Overview of Outlook add-ins architecture and features
Add-in Command Demo Outlook add-in
Prepend or append content to a
message or appointment body on send
Article • 05/24/2023
Add sensitivity and classification labels to their messages and appointments for
easier item identification and organization.
Insert disclaimers for legal purposes.
Add standardized headers for marketing and communication purposes.
In this walkthrough, you'll develop an add-in that prepends a header and appends a
disclaimer when a message is sent.
7 Note
Support for the append-on-send feature was introduced in requirement set 1.9,
while support for the prepend-on-send feature was introduced in requirement set
1.13. See clients and platforms that support these requirement sets.
XML Manifest
To enable the prepend-on-send and append-on-send features in your add-in, you
must include the AppendOnSend permission in the collection of ExtendedPermissions.
Additionally, you'll configure function commands to prepend and append content
to the message body.
1. In your code editor, open the quick start project you created.
3. Select the entire <VersionOverrides> node (including open and close tags)
and replace it with the following XML.
XML
<VersionOverrides
xmlns="http://schemas.microsoft.com/office/mailappversionoverrides"
xsi:type="VersionOverridesV1_0">
<VersionOverrides
xmlns="http://schemas.microsoft.com/office/mailappversionoverrides/
1.1" xsi:type="VersionOverridesV1_1">
<Requirements>
<bt:Sets DefaultMinVersion="1.13">
<bt:Set Name="Mailbox" />
</bt:Sets>
</Requirements>
<Hosts>
<Host xsi:type="MailHost">
<DesktopFormFactor>
<FunctionFile resid="Commands.Url" />
<ExtensionPoint xsi:type="MessageComposeCommandSurface">
<OfficeTab id="TabDefault">
<Group id="msgComposeGroup">
<Label resid="GroupLabel" />
<Control xsi:type="Button"
id="msgComposeOpenPaneButton">
<Label resid="TaskpaneButton.Label" />
<Supertip>
<Title resid="TaskpaneButton.Label" />
<Description resid="TaskpaneButton.Tooltip" />
</Supertip>
<Icon>
<bt:Image size="16" resid="Icon.16x16" />
<bt:Image size="32" resid="Icon.32x32" />
<bt:Image size="80" resid="Icon.80x80" />
</Icon>
<Action xsi:type="ShowTaskpane">
<SourceLocation resid="Taskpane.Url" />
</Action>
</Control>
<!-- Configure the prepend-on-send function
command. -->
<Control xsi:type="Button" id="PrependButton">
<Label resid="PrependButton.Label"/>
<Supertip>
<Title resid="PrependButton.Label"/>
<Description resid="PrependButton.Tooltip"/>
</Supertip>
<Icon>
<bt:Image size="16" resid="Icon.16x16"/>
<bt:Image size="32" resid="Icon.32x32"/>
<bt:Image size="80" resid="Icon.80x80"/>
</Icon>
<Action xsi:type="ExecuteFunction">
<FunctionName>prependHeaderOnSend</FunctionName>
</Action>
</Control>
<!-- Configure the append-on-send function command.
-->
<Control xsi:type="Button" id="AppendButton">
<Label resid="AppendButton.Label"/>
<Supertip>
<Title resid="AppendButton.Label"/>
<Description resid="AppendButton.Tooltip"/>
</Supertip>
<Icon>
<bt:Image size="16" resid="Icon.16x16"/>
<bt:Image size="32" resid="Icon.32x32"/>
<bt:Image size="80" resid="Icon.80x80"/>
</Icon>
<Action xsi:type="ExecuteFunction">
<FunctionName>appendDisclaimerOnSend</FunctionName>
</Action>
</Control>
</Group>
</OfficeTab>
</ExtensionPoint>
</DesktopFormFactor>
</Host>
</Hosts>
<Resources>
<bt:Images>
<bt:Image id="Icon.16x16"
DefaultValue="https://localhost:3000/assets/icon-16.png"/>
<bt:Image id="Icon.32x32"
DefaultValue="https://localhost:3000/assets/icon-32.png"/>
<bt:Image id="Icon.80x80"
DefaultValue="https://localhost:3000/assets/icon-80.png"/>
</bt:Images>
<bt:Urls>
<bt:Url id="Commands.Url"
DefaultValue="https://localhost:3000/commands.html" />
<bt:Url id="Taskpane.Url"
DefaultValue="https://localhost:3000/taskpane.html" />
</bt:Urls>
<bt:ShortStrings>
<bt:String id="GroupLabel" DefaultValue="Contoso Add-in"/>
<bt:String id="TaskpaneButton.Label" DefaultValue="Show
Taskpane"/>
<bt:String id="PrependButton.Label" DefaultValue="Prepend
header on send"/>
<bt:String id="AppendButton.Label" DefaultValue="Append
disclaimer on send"/>
</bt:ShortStrings>
<bt:LongStrings>
<bt:String id="TaskpaneButton.Tooltip" DefaultValue="Opens
a pane displaying all available properties."/>
<bt:String id="PrependButton.Tooltip" DefaultValue="Prepend
the Contoso header on send."/>
<bt:String id="AppendButton.Tooltip" DefaultValue="Append
the Contoso disclaimer on send."/>
</bt:LongStrings>
</Resources>
<!-- Configures the prepend-on-send and append-on-send
features. The same value, AppendOnSend, is used for both features.
-->
<ExtendedPermissions>
<ExtendedPermission>AppendOnSend</ExtendedPermission>
</ExtendedPermissions>
</VersionOverrides>
</VersionOverrides>
Tip
Tip
To learn more about manifests for Outlook add-ins, see Office add-in manifests.
Implement the prepend-on-send handler
In this section, you'll implement the JavaScript code to prepend a sample company
header to a mail item when it's sent.
1. Navigate to the ./src/commands folder of your project and open the commands.js
file.
JavaScript
function prependHeaderOnSend(event) {
// It's recommended to call the getTypeAsync method and pass its
returned value to the options.coercionType parameter of the
prependOnSendAsync call.
Office.context.mailbox.item.body.getTypeAsync(
{
asyncContext: event
},
(asyncResult) => {
if (asyncResult.status === Office.AsyncResultStatus.Failed) {
console.log(asyncResult.error.message);
return;
}
Office.context.mailbox.item.body.prependOnSendAsync(
header,
{
asyncContext: asyncResult.asyncContext,
coercionType: bodyFormat
},
(asyncResult) => {
if (asyncResult.status === Office.AsyncResultStatus.Failed) {
console.log(asyncResult.error.message);
return;
}
1. In the same commands.js file, insert the following function after the
prependHeaderOnSend function.
JavaScript
function appendDisclaimerOnSend(event) {
// Calls the getTypeAsync method and passes its returned value to the
options.coercionType parameter of the appendOnSendAsync call.
Office.context.mailbox.item.body.getTypeAsync(
{
asyncContext: event
},
(asyncResult) => {
if (asyncResult.status === Office.AsyncResultStatus.Failed) {
console.log(asyncResult.error.message);
return;
}
Office.context.mailbox.item.body.appendOnSendAsync(
disclaimer,
{
asyncContext: asyncResult.asyncContext,
coercionType: bodyFormat
},
(asyncResult) => {
if (asyncResult.status === Office.AsyncResultStatus.Failed) {
console.log(asyncResult.error.message);
return;
}
JavaScript
Office.actions.associate("prependHeaderOnSend", prependHeaderOnSend);
Office.actions.associate("appendDisclaimerOnSend",
appendDisclaimerOnSend);
Try it out
1. Run the following command in the root directory of your project. When you run
this command, the local web server will start if it's not already running and your
add-in will be sideloaded.
command line
npm start
7 Note
6. Send the message, then open it from your Inbox or Sent Items folder to view the
inserted content.
Tip
Any formatting applied to prepended or appended content doesn't affect the style
of the rest of the mail item's body.
When implementing Smart Alerts in the same add-in, the prepend-on-send and
append-on-send operations occur before the OnMessageSend and
OnAppointmentSend event handler operations.
Delegate and shared mailbox scenarios are supported as long as the add-in that
implements prepend-on-send or append-on-send is enabled on the shared
mailbox or owner's account.
DataExceedsMaximumSize The content to be Shorten the string you pass to the data
appended or prepended is parameter of your prependOnSendAsync or
longer than 5,000 appendOnSendAsync call.
characters.
Error Description Resolution
InvalidFormatError The message or Only plain text can be inserted into a plain text
appointment body is in body of a message or appointment. To verify the
plain text format, but the format of the mail item being composed, call
coercionType passed to Office.context.mailbox.item.body.getTypeAsync ,
the prependOnSendAsync or then pass its returned value to your
appendOnSendAsync prependOnSendAsync or appendOnSendAsync call.
method is set to
Office.CoercionType.Html .
See also
Office add-in manifests
Office.Body
Use Smart Alerts and the OnMessageSend and OnAppointmentSend events in
your Outlook add-in
Implement an integrated spam-
reporting add-in (preview)
Article • 07/21/2023
With the number of unsolicited emails on the rise, security is at the forefront of add-in
usage. Currently, partner spam-reporting add-ins are added to the Outlook ribbon, but
they usually appear towards the end of the ribbon or in the overflow menu. This makes
it harder for users to locate the add-in to report unsolicited emails. In addition to
configuring how messages are processed when they're reported, developers also need
to complete additional tasks to show processing dialogs or supplemental information to
the user.
The integrated spam reporting feature eases the task of developing individual add-in
components from scratch. More importantly, it displays your add-in in a prominent spot
on the Outlook ribbon, making it easier for users to locate it and report spam messages.
Implement this feature in your add-in to:
) Important
The preprocessing dialog is shown to a user when they report a message. In the
dialog, you can share guidance on the reporting process and include options for
the user to provide more information about the message being reported. To
customize the title, description, and options of the preprocessing dialog, you
must include the PreProcessingDialog element in your manifest.
The following is an example of a <VersionOverrides> node configured for spam
reporting.
1. In your preferred code editor, open the add-in project you created.
3. Select the entire <VersionOverrides> node (including the open and close tags)
and replace it with the following code.
XML
<VersionOverrides
xmlns="http://schemas.microsoft.com/office/mailappversionoverrides"
xsi:type="VersionOverridesV1_0">
<VersionOverrides
xmlns="http://schemas.microsoft.com/office/mailappversionoverrides/1.1"
xsi:type="VersionOverridesV1_1">
<Requirements>
<bt:Sets DefaultMinVersion="1.13">
<bt:Set Name="Mailbox"/>
</bt:Sets>
</Requirements>
<Hosts>
<Host xsi:type="MailHost">
<Runtimes>
<Runtime resid="WebViewRuntime.Url">
<!-- References the JavaScript file that contains the spam-
reporting event handler. This is used by Outlook on Windows. -->
<Override type="javascript" resid="JSRuntime.Url"/>
</Runtime>
</Runtimes>
<DesktopFormFactor>
<FunctionFile resid="WebViewRuntime.Url"/>
<!-- Implements the integrated spam reporting feature in the
add-in. -->
<ExtensionPoint xsi:type="ReportPhishingCommandSurface">
<ReportPhishingCustomization>
<!-- Configures the ribbon button. -->
<Control xsi:type="Button" id="spamReportingButton">
<Label resid="spamButton.Label"/>
<Supertip>
<Title resid="spamButton.Label"/>
<Description resid="spamSuperTip.Text"/>
</Supertip>
<Icon>
<bt:Image size="16" resid="Icon.16x16"/>
<bt:Image size="32" resid="Icon.32x32"/>
<bt:Image size="80" resid="Icon.80x80"/>
</Icon>
<Action xsi:type="ExecuteFunction">
<FunctionName>onSpamReport</FunctionName>
</Action>
</Control>
<!-- Configures the preprocessing dialog. -->
<PreProcessingDialog>
<Title resid="PreProcessingDialog.Label"/>
<Description resid="PreProcessingDialog.Text"/>
<ReportingOptions>
<Title resid="OptionsTitle.Label"/>
<Option resid="Option1.Label"/>
<Option resid="Option2.Label"/>
<Option resid="Option3.Label"/>
</ReportingOptions>
<FreeTextLabel resid="FreeText.Label"/>
<MoreInfo>
<MoreInfoText resid="MoreInfo.Label"/>
<MoreInfoUrl resid="MoreInfo.Url"/>
</MoreInfo>
</PreProcessingDialog>
<!-- Identifies the runtime to be used. This is also
referenced by the Runtime element. -->
<SourceLocation resid="WebViewRuntime.Url"/>
</ReportPhishingCustomization>
</ExtensionPoint>
</DesktopFormFactor>
</Host>
</Hosts>
<Resources>
<bt:Images>
<bt:Image id="Icon.16x16"
DefaultValue="https://localhost:3000/assets/icon-16.png"/>
<bt:Image id="Icon.32x32"
DefaultValue="https://localhost:3000/assets/icon-32.png"/>
<bt:Image id="Icon.80x80"
DefaultValue="https://localhost:3000/assets/icon-80.png"/>
</bt:Images>
<bt:Urls>
<bt:Url id="WebViewRuntime.Url"
DefaultValue="https://localhost:3000/commands.html"/>
<bt:Url id="JSRuntime.Url"
DefaultValue="https://localhost:3000/commands.js"/>
<bt:Url id="MoreInfo.Url"
DefaultValue="https://www.contoso.com/spamreporting"/>
</bt:Urls>
<bt:ShortStrings>
<bt:String id="spamButton.Label" DefaultValue="Report Spam
Message"/>
<bt:String id="PreProcessingDialog.Label" DefaultValue="Report
Spam Message"/>
<bt:String id="OptionsTitle.Label" DefaultValue="Why are you
reporting this email?"/>
<bt:String id="FreeText.Label" DefaultValue="Provide additional
information, if any:"/>
<bt:String id="MoreInfo.Label" DefaultValue="To learn more
about reporting unsolicited messages, see "/>
<bt:String id="Option1.Label" DefaultValue="Received spam
email."/>
<bt:String id="Option2.Label" DefaultValue="Received a phishing
email."/>
<bt:String id="Option3.Label" DefaultValue="I'm not sure this
is a legitimate email."/>
</bt:ShortStrings>
<bt:LongStrings>
<bt:String id="spamSuperTip.Text" DefaultValue="Report an
unsolicited message."/>
<bt:String id="PreProcessingDialog.Text" DefaultValue="Thank
you for reporting this message."/>
</bt:LongStrings>
</Resources>
</VersionOverrides>
</VersionOverrides>
Your event handler is responsible for processing the reported message, such as
forwarding a copy of the message to an internal system for further investigation. To
efficiently send a copy of the reported message, call the getAsFileAsync method in your
event handler. This gets the Base64-encoded EML format of a message, which you can
then forward to your internal system.
) Important
Outlook on Windows includes a local copy of the production and beta versions of
Office.js instead of loading from the content delivery network (CDN). By default, the
local production copy of the API is referenced. To reference the local beta copy of
the API, you must configure your computer's registry as follows:
Once the event handler has completed processing the message, it must call the
event.completed method. In addition to signaling to the add-in that the spam-reporting
event has been processed, event.completed can also be used to customize a post-
processing dialog to show to the user or perform additional operations on the message,
such as deleting it from the inbox. For a list of properties you can include in a JSON
object to pass as a parameter to the event.completed method, see
Office.AddinCommands.EventCompletedOptions.
7 Note
3. Open the newly created spamreporting.js file and add the following JavaScript
code.
JavaScript
/**
* Signals that the spam-reporting event has completed processing.
* It then moves the reported message to the Junk Email folder of
the mailbox, then
* shows a post-processing dialog to the user. If an error occurs
while the message
* is being processed, the `onErrorDeleteItem` property determines
whether the message
* will be deleted.
*/
const event = asyncResult.asyncContext;
event.completed({
onErrorDeleteItem: true,
postProcessingAction: "moveToSpamFolder",
showPostProcessingDialog: {
title: "Contoso Spam Reporting",
description: "Thank you for reporting this message.",
},
});
});
}
The following is a sample post-processing dialog shown to the user once the add-in
completes processing a reported message.
Tip
As you develop a spam-reporting add-in that will run in Outlook on Windows, keep
the following in mind.
Imports aren't currently supported in the JavaScript file that contains the code
to handle the spam-reporting event.
Code included in the Office.onReady() and Office.initialize functions
won't run. You must add any add-in startup logic, such as checking the user's
Outlook version, to your event handlers instead.
2. Immediately before the closing head tag ( </head> ), replace the existing script
entry with the following code.
HTML
<script type="text/javascript"
src="https://appsforoffice.microsoft.com/lib/beta/hosted/office.js">
</script>
<script type="text/javascript" src="../spamreporting/spamreporting.js">
</script>
2. Locate the plugins array within the config object and add this new object to the
beginning of the array.
JavaScript
new CopyWebpackPlugin({
patterns: [
{
from: "./src/spamreporting/spamreporting.js",
to: "spamreporting.js",
},
],
}),
A spam-reporting add-in can run for a maximum of five minutes once it's
activated. Any processing that occurs beyond five minutes will cause the add-in to
time out. If the add-in times out, a dialog will be shown to the user to notify them
of this.
A spam-reporting add-in can be used to report a message even if the Reading
Pane of the Outlook client is turned off.
Only one message can be reported at a time. If a user attempts to report another
message while the previous one is still being processed, a dialog will be shown to
them to notify them of this.
The add-in can still process the reported message even if the user navigates away
from the selected message.
The buttons that appear in the preprocessing and post-processing dialogs aren't
customizable. Additionally, the text and buttons in the timeout and ongoing report
dialogs can't be modified.
The integrated spam reporting and event-based activation features must use the
same runtime. Multiple runtimes aren't currently supported in Outlook. To learn
more about runtimes, see Runtimes in Office Add-ins.
See also
Office Add-ins manifest
Runtimes in Office Add-ins
Configure your Outlook add-in for event-based
activation
Article • 07/06/2023
Without the event-based activation feature, a user has to explicitly launch an add-in to complete their
tasks. This feature enables your add-in to run tasks based on certain events, particularly for operations that
apply to every item. You can also integrate with the task pane and function commands.
By the end of this walkthrough, you'll have an add-in that runs whenever a new item is created and sets
the subject.
7 Note
Support for this feature was introduced in requirement set 1.10, with additional events now available
in subsequent requirement sets. For details about an event's minimum requirement set and the
clients and platforms that support it, see Supported events and Requirement sets supported by
Exchange servers and Outlook clients.
The add-in from the following walkthrough only runs in Outlook on Windows, on Mac, and on the
web. To learn how to implement an event-based add-in that runs in Outlook on mobile devices, see
Implement event-based activation in Outlook mobile add-ins.
Supported events
The following table lists events that are currently available and the supported clients for each event. When
an event is raised, the handler receives an event object which may include details specific to the type of
event. The Description column includes a link to the related object where applicable.
- New Mac
UI
- New Mac
UI
Event canonical name Unified manifest for Microsoft Description Minimum
and XML manifest name 365 name requirement
set and
supported
clients
- New Mac
UI
7 Note
1 Event-based add-ins in Outlook on Windows require a minimum of Windows 10 Version 1903 (Build
18362) or Windows Server 2019 Version 1903 to run.
2 Outlook on mobile supports APIs up to Mailbox requirement set 1.5. However, support is now
enabled for additional APIs and features introduced in later requirement sets, such as the
OnNewMessageCompose event. To learn more, see Implement event-based activation in Outlook mobile
add-ins.
XML Manifest
To enable event-based activation of your add-in, you must configure the Runtimes element and
LaunchEvent extension point in the VersionOverridesV1_1 node of the manifest.
3. Select the entire <VersionOverrides> node (including open and close tags) and replace it with
the following XML, then save your changes.
XML
<VersionOverrides xmlns="http://schemas.microsoft.com/office/mailappversionoverrides"
xsi:type="VersionOverridesV1_0">
<VersionOverrides
xmlns="http://schemas.microsoft.com/office/mailappversionoverrides/1.1"
xsi:type="VersionOverridesV1_1">
<Requirements>
<bt:Sets DefaultMinVersion="1.10">
<bt:Set Name="Mailbox" />
</bt:Sets>
</Requirements>
<Hosts>
<Host xsi:type="MailHost">
<!-- Event-based activation happens in a lightweight runtime.-->
<Runtimes>
<!-- HTML file including reference to or inline JavaScript event handlers.
This is used by Outlook on the web and Outlook on the new Mac UI. -->
<Runtime resid="WebViewRuntime.Url">
<!-- JavaScript file containing event handlers. This is used by Outlook on
Windows. -->
<Override type="javascript" resid="JSRuntime.Url"/>
</Runtime>
</Runtimes>
<DesktopFormFactor>
<FunctionFile resid="Commands.Url" />
<ExtensionPoint xsi:type="MessageReadCommandSurface">
<OfficeTab id="TabDefault">
<Group id="msgReadGroup">
<Label resid="GroupLabel" />
<Control xsi:type="Button" id="msgReadOpenPaneButton">
<Label resid="TaskpaneButton.Label" />
<Supertip>
<Title resid="TaskpaneButton.Label" />
<Description resid="TaskpaneButton.Tooltip" />
</Supertip>
<Icon>
<bt:Image size="16" resid="Icon.16x16" />
<bt:Image size="32" resid="Icon.32x32" />
<bt:Image size="80" resid="Icon.80x80" />
</Icon>
<Action xsi:type="ShowTaskpane">
<SourceLocation resid="Taskpane.Url" />
</Action>
</Control>
<Control xsi:type="Button" id="ActionButton">
<Label resid="ActionButton.Label"/>
<Supertip>
<Title resid="ActionButton.Label"/>
<Description resid="ActionButton.Tooltip"/>
</Supertip>
<Icon>
<bt:Image size="16" resid="Icon.16x16"/>
<bt:Image size="32" resid="Icon.32x32"/>
<bt:Image size="80" resid="Icon.80x80"/>
</Icon>
<Action xsi:type="ExecuteFunction">
<FunctionName>action</FunctionName>
</Action>
</Control>
</Group>
</OfficeTab>
</ExtensionPoint>
<!-- Can configure other command surface extension points for add-in command
support. -->
Outlook on Windows uses a JavaScript file, while Outlook on the web and on the new Mac UI use an
HTML file that can reference the same JavaScript file. You must provide references to both these files
in the Resources node of the manifest as the Outlook platform ultimately determines whether to use
HTML or JavaScript based on the Outlook client. As such, to configure event handling, provide the
location of the HTML in the <Runtime> element, then in its Override child element provide the
location of the JavaScript file inlined or referenced by the HTML.
Tip
1. From the same quick start project, create a new folder named launchevent under the ./src directory.
3. Open the file ./src/launchevent/launchevent.js in your code editor and add the following JavaScript
code.
JavaScript
/*
* Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT
license.
* See LICENSE in the project root for license information.
*/
function onNewMessageComposeHandler(event) {
setSubject(event);
}
function onNewAppointmentComposeHandler(event) {
setSubject(event);
}
function setSubject(event) {
Office.context.mailbox.item.subject.setAsync(
"Set by an event-based add-in!",
{
"asyncContext": event
},
function (asyncResult) {
// Handle success or error.
if (asyncResult.status !== Office.AsyncResultStatus.Succeeded) {
console.error("Failed to set subject: " + JSON.stringify(asyncResult.error));
}
) Important
Windows: At present, imports aren't supported in the JavaScript file where you implement the
handling for event-based activation.
Tip
Event-based add-ins running in Outlook on Windows don't run code included in the
Office.onReady() and Office.initialize functions. We recommend adding your add-in startup logic,
such as checking the user's Outlook version, to your event handlers instead.
2. Immediately before the closing head tag ( </head> ), add a script entry to include the event-handling
JavaScript code.
HTML
2. Locate the plugins array within the config object and add this new object at the beginning of the
array.
JavaScript
new CopyWebpackPlugin({
patterns: [
{
from: "./src/launchevent/launchevent.js",
to: "launchevent.js",
},
],
}),
Try it out
1. Run the following commands in the root directory of your project. When you run npm start , the local
web server will start (if it's not already running) and your add-in will be sideloaded.
command line
command line
npm start
7 Note
If your add-in wasn't automatically sideloaded, then follow the instructions in Sideload Outlook
add-ins for testing to manually sideload the add-in in Outlook.
Verify that your event-handling JavaScript file referenced by the Outlook client on Windows calls
Office.actions.associate . This ensures that the event handler name specified in the manifest is
Tip
If your event-based add-in has only one JavaScript file referenced by Outlook on the web,
Windows, and Mac, it's recommended to check on which platform the add-in is running to
determine when to call Office.actions.associate , as shown in the following code.
JavaScript
The JavaScript code of event-based add-ins that run in Outlook on Windows only supports
ECMAScript 2016 and earlier specifications. Some examples of programming syntax to avoid are as
follows.
Avoid using async and await statements in your code. Including these in your JavaScript code will
cause the add-in to time out.
Avoid using the conditional (ternary) operator as it will prevent your add-in from loading.
If your add-in has only one JavaScript file referenced by Outlook on the web, Windows, and Mac, you
must limit your code to ECMAScript 2016 to ensure that your add-in runs in Outlook on Windows.
However, if you have a separate JavaScript file referenced by Outlook on the web and Mac, you can
implement a later ECMAScript specification in that file.
text
Tip
If the bundle.js file doesn't appear in the Wef folder, try the following:
If your add-in is installed or sideloaded, restart Outlook.
Remove your add-in from Outlook, then sideload it again.
As you test your add-in in Outlook on Windows or Mac, enable runtime logging to identify possible
manifest and add-in installation issues. For guidance on how to use runtime logging, see Debug your
add-in with runtime logging.
Set breakpoints in your code to debug your add-in. For platform-specific instructions, see Debug
your event-based Outlook add-in.
Deploy to users
Event-based add-ins are restricted to admin-managed deployments only, even if they're acquired from
AppSource. If users acquire the add-in from AppSource or the in-app Office Store, they won't be able to
activate the event-based function of the add-in. To learn more about listing your event-based add-in in
AppSource, see AppSource listing options for your event-based Outlook add-in.
Admin deployments are done by uploading the manifest to the Microsoft 365 admin center. In the admin
portal, expand the Settings section in the navigation pane then select Integrated apps. On the Integrated
apps page, choose the Upload custom apps action.
) Important
Add-ins that use the Smart Alerts feature can only be published to AppSource if the manifest's send
mode property is set to the prompt user or soft block option. If an add-in's send mode property is
set to block, it can only be deployed by an organization's admin as it will fail AppSource validation.
If the user has multiple add-ins that subscribed to the same event, the Outlook platform launches the add-
ins in no particular order. Currently, only five event-based add-ins can be actively running.
In all supported Outlook clients, the user must remain on the current mail item where the add-in was
activated for it to complete running. Navigating away from the current item (for example, switching to
another compose window or tab) terminates the add-in operation. The add-in also ceases operation when
the user sends the message or appointment they're composing.
When developing an event-based add-in to run in the Outlook on Windows client, be mindful of the
following:
Imports aren't supported in the JavaScript file where you implement the handling for event-based
activation.
Add-ins don't run code included in Office.onReady() and Office.initialize . We recommend
adding any startup logic, such as checking the user's Outlook version, to your event handlers instead.
Some Office.js APIs that change or alter the UI aren't allowed from event-based add-ins. The following are
the blocked APIs.
Under Office.context.auth :
getAccessToken
getAccessTokenAsync
7 Note
Under Office.context.mailbox :
displayAppointmentForm
displayMessageForm
displayNewAppointmentForm
displayNewMessageForm
Under Office.context.mailbox.item :
close
Under Office.context.ui :
displayDialogAsync
messageParent
Be aware that you must use additional security measures when using XMLHttpRequest objects, requiring
Same Origin Policy and simple CORS (Cross-Origin Resource Sharing) .
To enable your event-based add-in to make CORS request, you must add the add-in and its JavaScript file
to a well-known URI. For guidance on how to configure this resource, see Enable single sign-on (SSO) or
cross-origin resource sharing (CORS) in your event-based Outlook add-in.
7 Note
Full CORS support is available in Outlook on the web, Mac, and Windows (starting in Version 2201,
Build 16.0.14813.10000).
See also
Office add-in manifests
How to debug event-based add-ins
AppSource listing options for your event-based Outlook add-in
Smart Alerts and OnMessageSend walkthrough
Automatically update your signature when switching between mail accounts
Office Add-ins code samples:
Use Outlook event-based activation to encrypt attachments, process meeting request attendees
and react to appointment date/time changes
Use Outlook event-based activation to set the signature
Use Outlook event-based activation to tag external recipients
Use Outlook Smart Alerts
Verify the sensitivity label of a message
Use Smart Alerts and the
OnMessageSend and
OnAppointmentSend events in your
Outlook add-in
Article • 07/05/2023
The OnMessageSend and OnAppointmentSend events take advantage of Smart Alerts, which
allows you to run logic after a user selects Send in their Outlook message or
appointment. Your event handler allows you to give your users the opportunity to
improve their emails and meeting invites before they're sent.
The following walkthrough uses the OnMessageSend event. By the end of this
walkthrough, you'll have an add-in that runs whenever a message is being sent and
checks if the user forgot to add a document or picture they mentioned in their email.
7 Note
Prerequisites
The OnMessageSend event is available through the event-based activation feature. To
understand how to configure your add-in to use this feature, use other available events,
debug your add-in, and more, see Configure your Outlook add-in for event-based
activation.
XML Manifest
3. Select the entire <VersionOverrides> node (including open and close tags)
and replace it with the following XML, then save your changes.
XML
<VersionOverrides
xmlns="http://schemas.microsoft.com/office/mailappversionoverrides"
xsi:type="VersionOverridesV1_0">
<VersionOverrides
xmlns="http://schemas.microsoft.com/office/mailappversionoverrides/1.1"
xsi:type="VersionOverridesV1_1">
<Requirements>
<bt:Sets DefaultMinVersion="1.12">
<bt:Set Name="Mailbox" />
</bt:Sets>
</Requirements>
<Hosts>
<Host xsi:type="MailHost">
<!-- Event-based activation happens in a lightweight runtime.-->
<Runtimes>
<!-- HTML file including reference to or inline JavaScript
event handlers.
This is used by Outlook on the web and on the new Mac UI.
-->
<Runtime resid="WebViewRuntime.Url">
<!-- JavaScript file containing event handlers. This is used
by Outlook on Windows. -->
<Override type="javascript" resid="JSRuntime.Url"/>
</Runtime>
</Runtimes>
<DesktopFormFactor>
<FunctionFile resid="Commands.Url" />
<ExtensionPoint xsi:type="MessageReadCommandSurface">
<OfficeTab id="TabDefault">
<Group id="msgReadGroup">
<Label resid="GroupLabel" />
<Control xsi:type="Button" id="msgReadOpenPaneButton">
<Label resid="TaskpaneButton.Label" />
<Supertip>
<Title resid="TaskpaneButton.Label" />
<Description resid="TaskpaneButton.Tooltip" />
</Supertip>
<Icon>
<bt:Image size="16" resid="Icon.16x16" />
<bt:Image size="32" resid="Icon.32x32" />
<bt:Image size="80" resid="Icon.80x80" />
</Icon>
<Action xsi:type="ShowTaskpane">
<SourceLocation resid="Taskpane.Url" />
</Action>
</Control>
<Control xsi:type="Button" id="ActionButton">
<Label resid="ActionButton.Label"/>
<Supertip>
<Title resid="ActionButton.Label"/>
<Description resid="ActionButton.Tooltip"/>
</Supertip>
<Icon>
<bt:Image size="16" resid="Icon.16x16"/>
<bt:Image size="32" resid="Icon.32x32"/>
<bt:Image size="80" resid="Icon.80x80"/>
</Icon>
<Action xsi:type="ExecuteFunction">
<FunctionName>action</FunctionName>
</Action>
</Control>
</Group>
</OfficeTab>
</ExtensionPoint>
Tip
For a list of send mode options available with the OnMessageSend and
OnAppointmentSend events, see Available send mode options.
To learn more about manifests for Outlook add-ins, see Office add-in
manifests.
In this scenario, you'll add handling for sending a message. Your add-in will check for
certain keywords in the message. If any of those keywords are found, it will then check if
there are any attachments. If there are no attachments, your add-in will recommend to
the user to add the possibly missing attachment.
1. From the same quick start project, create a new folder named launchevent under
the ./src directory.
3. Open the file ./src/launchevent/launchevent.js in your code editor and add the
following JavaScript code.
JavaScript
/*
* Copyright (c) Microsoft Corporation. All rights reserved. Licensed
under the MIT license.
* See LICENSE in the project root for license information.
*/
function onMessageSendHandler(event) {
Office.context.mailbox.item.body.getAsync(
"text",
{ asyncContext: event },
getBodyCallback
);
}
function getBodyCallback(asyncResult){
let event = asyncResult.asyncContext;
let body = "";
if (asyncResult.status !== Office.AsyncResultStatus.Failed &&
asyncResult.value !== undefined) {
body = asyncResult.value;
} else {
let message = "Failed to get body text";
console.error(message);
event.completed({ allowEvent: false, errorMessage: message });
return;
}
function hasMatches(body) {
if (body == null || body == "") {
return false;
}
return false;
}
function getAttachmentsCallback(asyncResult) {
let event = asyncResult.asyncContext;
if (asyncResult.value.length > 0) {
for (let i = 0; i < asyncResult.value.length; i++) {
if (asyncResult.value[i].isInline == false) {
event.completed({ allowEvent: true });
return;
}
}
) Important
When developing your Smart Alerts add-in to run in Outlook on Windows, keep the
following in mind.
Imports aren't currently supported in the JavaScript file where you implement
the handling for event-based activation.
To ensure your add-in runs as expected when an OnMessageSend or
OnAppointmentSend event occurs in Outlook on Windows, call
implemented. This maps the event handler name specified in the manifest to
its JavaScript counterpart. If this call isn't included in your JavaScript file and
the send mode property of your manifest is set to soft block or isn't specified,
your users will be blocked from sending messages or meetings.
2. Immediately before the closing head tag ( </head> ), add a script entry for the
event-handling JavaScript code.
JavaScript
2. Locate the plugins array within the config object and add this new object to the
beginning of the array.
JavaScript
new CopyWebpackPlugin({
patterns: [
{
from: "./src/launchevent/launchevent.js",
to: "launchevent.js",
},
],
}),
Try it out
1. Run the following commands in the root directory of your project. When you run
npm start , the local web server will start (if it's not already running) and your add-
in will be sideloaded.
command line
command line
npm start
7 Note
3. Send the message. A dialog should pop up with a recommendation for you to add
an attachment.
4. Add an attachment then send the message again. There should be no alert this
time.
Deploy to users
Similar to other event-based add-ins, add-ins that use the Smart Alerts feature must be
deployed by an organization's administrator. For guidance on how to deploy your add-
in via the Microsoft 365 admin center, see the "Deploy to users" section in Configure
your Outlook add-in for event-based activation.
) Important
Add-ins that use the Smart Alerts feature can only be published to AppSource if the
manifest's send mode property is set to the soft block or prompt user option. If an
add-in's send mode property is set to block, it can only be deployed by an
organization's admin as it will fail AppSource validation. To learn more about
publishing your event-based add-in to AppSource, see AppSource listing options
for your event-based Outlook add-in.
If the conditions implemented by your add-in aren't met or your add-in is unavailable
when the event occurs, a dialog is shown to the user to alert them that additional
actions may be needed before the mail item can be sent. The send mode property
determines the options available to the user in the dialog.
Send mode option canonical XML manifest Unified manifest for Microsoft 365
name name name
prompt user
If the item doesn't meet the add-in's conditions, the user can choose Send Anyway in
the alert, or address the issue then try to send the item again. If the add-in is taking a
long time to process the item, the user will be prompted with the option to stop running
the add-in and choose Send Anyway. In the event the add-in is unavailable (for
example, there's an error loading the add-in), the item will be sent.
Use the prompt user option in your add-in if one of the following applies.
The condition checked by the add-in isn't mandatory, but is nice to have in the
message or appointment being sent.
You'd like to recommend an action and allow the user to decide whether they want
to apply it to the message or appointment being sent.
Some scenarios where the prompt user option is applied include suggesting to tag the
message or appointment as low or high importance and recommending to apply a color
category to the item.
soft block
Default option if the send mode property of your manifest isn't configured. The user is
alerted that the item they're sending doesn't meet the add-in's conditions and they
must address the issue before trying to send the item again. However, if the add-in is
unavailable (for example, there's an error loading the add-in), the item will be sent.
Use the soft block option in your add-in when you want a condition to be met before a
message or appointment can be sent, but you don't want the user to be blocked from
sending the item if the add-in is unavailable. Sample scenarios where the soft block
option is used include prompting the user to set a message or appointment's
importance level and checking that the appropriate signature is applied before the item
is sent.
block
The item isn't sent if any of the following situations occur.
Use the block option if the add-in's conditions are mandatory, even if the add-in is
unavailable. For example, the block option is ideal when users are required to apply a
sensitivity label to a message or appointment before it can be sent.
Add-in is unavailable
If the add-in is unavailable when a message or appointment is being sent (for example,
an error occurs that prevents the add-in from loading), the user is alerted. The options
available to the user differ depending on the send mode option applied to the add-in.
If the prompt user or soft block option is used, the user can choose Send Anyway to
send the item without the add-in checking it, or Try Later to let the item be checked by
the add-in when it becomes available again.
If the block option is used, the user can't send the item until the add-in becomes
available.
Long-running add-in operations
If the add-in runs for more than five seconds, but less than five minutes, the user is
alerted that the add-in is taking longer than expected to process the message or
appointment.
If the prompt user option is used, the user can choose Send Anyway to send the item
without the add-in completing its check. Alternatively, the user can select Don't Send to
stop the add-in from processing.
However, if the soft block or block option is used, the user will not be able to send the
item until the add-in completes processing it.
Limitations
Because the OnMessageSend and OnAppointmentSend events are supported through the
event-based activation feature, the same feature limitations apply to add-ins that
activate as a result of these events. For a description of these limitations, see Event-
based activation behavior and limitations.
In addition to these constraints, only one instance each of the OnMessageSend and
OnAppointmentSend event can be declared in the manifest. If you require multiple
add-in.
While a Smart Alerts dialog message can be changed to suit your add-in scenario using
the errorMessage property of the event.completed method, the following can't be
customized.
The dialog's title bar. Your add-in's name is always displayed there.
The message's format. For example, you can't change the text's font size and color
or insert a bulleted list.
The dialog options. For example, the Send Anyway and Don't Send options are
fixed and depend on the send mode option you select.
Event-based activation processing and progress information dialogs. For example,
the text and options that appear in the timeout and long-running operation
dialogs can't be changed.
Differences between Smart Alerts and the on-
send feature
While Smart Alerts and the on-send feature provide your users the opportunity to
improve their messages and meeting invites before they're sent, Smart Alerts is a newer
feature that offers you more flexibility with how you prompt your users for further
action. Key differences between the two features are outlined in the following table.
See also
Office add-in manifests
Configure your Outlook add-in for event-based activation
Event-based activation troubleshooting guide
How to debug event-based add-ins
AppSource listing options for your event-based Outlook add-in
Office Add-ins code sample: Use Outlook Smart Alerts
Office Add-ins code sample: Verify the sensitivity label of a message
Automatically update your signature
when switching between Exchange
accounts
Article • 05/20/2023
Applying the correct signature to messages when using multiple Exchange accounts is
now made easier with the addition of the OnMessageFromChanged and
OnAppointmentFromChanged events to the event-based activation feature. The
OnMessageFromChanged event occurs when the account in the From field of a message
being composed is changed, while the OnAppointmentFromChanged event occurs when the
organizer of a meeting being composed is changed. These events further extend the
capabilities of signature add-ins and allow them to:
Provide users with the convenience to apply custom signatures for each of their
accounts.
Enable mailbox delegates to more accurately and efficiently manage outgoing
messages and meeting requests from multiple mailboxes.
Ensure that users' messages and appointments meet their organization's
communication and marketing policies.
The following sections walk you through how to develop an event-based add-in that
handles the OnMessageFromChanged event to automatically update a message's signature
when the mail account in the From field is changed.
7 Note
OnMessageFromChanged event
Client Exchange Exchange 2019 on- Exchange 2016 on-
Online premises (Cumulative premises (Cumulative
Update 12 or later) Update 22 or later)
Prerequisites
To test the walkthrough, you must have at least two Exchange accounts.
7 Note
3. Select the entire <VersionOverrides> node (including open and close tags),
replace it with the following XML, then save your changes.
XML
<VersionOverrides
xmlns="http://schemas.microsoft.com/office/mailappversionoverrides"
xsi:type="VersionOverridesV1_0">
<VersionOverrides
xmlns="http://schemas.microsoft.com/office/mailappversionoverrides/1.1"
xsi:type="VersionOverridesV1_1">
<Requirements>
<bt:Sets DefaultMinVersion="1.13">
<bt:Set Name="Mailbox"/>
</bt:Sets>
</Requirements>
<Hosts>
<Host xsi:type="MailHost">
<Runtimes>
<!-- HTML file that references or contains inline JavaScript
event handlers.
This is used by event-based activation add-ins in
Outlook on the web and Outlook on the new Mac UI. -->
<Runtime resid="WebViewRuntime.Url">
<!-- JavaScript file that contains the event handlers.
This is used by event-based activation add-ins in
Outlook on Windows. -->
<Override type="javascript" resid="JSRuntime.Url"/>
</Runtime>
</Runtimes>
<DesktopFormFactor>
<FunctionFile resid="Commands.Url"/>
<ExtensionPoint xsi:type="MessageComposeCommandSurface">
<OfficeTab id="TabDefault">
<Group id="msgComposeGroup">
<Label resid="GroupLabel"/>
<Control xsi:type="Button"
id="msgComposeOpenPaneButton">
<Label resid="TaskpaneButton.Label"/>
<Supertip>
<Title resid="TaskpaneButton.Label"/>
<Description resid="TaskpaneButton.Tooltip"/>
</Supertip>
<Icon>
<bt:Image size="16" resid="Icon.16x16"/>
<bt:Image size="32" resid="Icon.32x32"/>
<bt:Image size="80" resid="Icon.80x80"/>
</Icon>
<Action xsi:type="ShowTaskpane">
<SourceLocation resid="Taskpane.Url"/>
</Action>
</Control>
<Control xsi:type="Button" id="ActionButton">
<Label resid="ActionButton.Label"/>
<Supertip>
<Title resid="ActionButton.Label"/>
<Description resid="ActionButton.Tooltip"/>
</Supertip>
<Icon>
<bt:Image size="16" resid="Icon.16x16"/>
<bt:Image size="32" resid="Icon.32x32"/>
<bt:Image size="80" resid="Icon.80x80"/>
</Icon>
<Action xsi:type="ExecuteFunction">
<FunctionName>action</FunctionName>
</Action>
</Control>
</Group>
</OfficeTab>
</ExtensionPoint>
<!-- Configures event-based activation. -->
<ExtensionPoint xsi:type="LaunchEvent">
<LaunchEvents>
<LaunchEvent Type="OnNewMessageCompose"
FunctionName="onNewMessageComposeHandler"/>
<LaunchEvent Type="OnMessageFromChanged"
FunctionName="onMessageFromChangedHandler"/>
</LaunchEvents>
<!-- Identifies the runtime to be used (also referenced by
the <Runtime> element). -->
<SourceLocation resid="WebViewRuntime.Url"/>
</ExtensionPoint>
</DesktopFormFactor>
</Host>
</Hosts>
<Resources>
<bt:Images>
<bt:Image id="Icon.16x16"
DefaultValue="https://localhost:3000/assets/icon-16.png"/>
<bt:Image id="Icon.32x32"
DefaultValue="https://localhost:3000/assets/icon-32.png"/>
<bt:Image id="Icon.80x80"
DefaultValue="https://localhost:3000/assets/icon-80.png"/>
</bt:Images>
<bt:Urls>
<bt:Url id="Commands.Url"
DefaultValue="https://localhost:3000/commands.html"/>
<bt:Url id="Taskpane.Url"
DefaultValue="https://localhost:3000/taskpane.html"/>
<bt:Url id="JSRuntime.Url"
DefaultValue="https://localhost:3000/launchevent.js"/>
<bt:Url id="WebViewRuntime.Url"
DefaultValue="https://localhost:3000/commands.html"/>
</bt:Urls>
<bt:ShortStrings>
<bt:String id="GroupLabel" DefaultValue="Contoso Add-in"/>
<bt:String id="TaskpaneButton.Label" DefaultValue="Show
Taskpane"/>
<bt:String id="ActionButton.Label" DefaultValue="Perform an
action"/>
</bt:ShortStrings>
<bt:LongStrings>
<bt:String id="TaskpaneButton.Tooltip" DefaultValue="Opens a
pane displaying all available properties."/>
<bt:String id="ActionButton.Tooltip" DefaultValue="Perform an
action when clicked."/>
</bt:LongStrings>
</Resources>
</VersionOverrides>
</VersionOverrides>
Tip
selected account.
1. From the same quick start project, navigate to the ./src directory, then create a
new folder named launchevent.
JavaScript
/*
* Copyright (c) Microsoft Corporation. All rights reserved. Licensed
under the MIT license.
* See LICENSE in the project root for license information.
*/
"iVBORw0KGgoAAAANSUhEUgAAACcAAAAnCAMAAAC7faEHAAAAAXNSR0IArs4c6QAAAARnQU
1BAACxjwv8YQUAAAAzUExURQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAKMFRskAAAAQdFJOUwAQIDBAUGBwgI+fr7/P3+8jGoKKAAAACXBI
WXMAAA7DAAAOwwHHb6hkAAABT0lEQVQ4T7XT2ZalIAwF0DAJhMH+/6+tJOQqot6X6joPiou
NBo3w9/Hd6+hrYnUt6vhLcjEAJevVW0zJxABSlcunhERpjY+UKoNN5+ZgDGu2onNz0OngjP
2FM1VdyBW1LtvGeYrBLs7U5I1PTXZt+zifcS3Icw2GcS3vxRY3Vn/iqx31hUyTnV515kdTf
baNhZLI30AceqDiIo4tyKEmJpKdP5M4um+nUwfDWxAXdzqMNKQ14jLdL5ntXzxcRF440mhS
6yu882Kxa30RZcUIjTCJg7lscsR4VsMjfX9Q0Vuv/Wd3YosD1J4LuSRtaL7bzXGN1wx2cyt
UdncDuhA3fu6HPTiCvpQUIjZ3sCcHVbvLtbNTHlysx2w9/s27m9gEb+7CTri6hR1wcTf2gV
f3wBRe3CMbcHYvTODkXhnD0+178K/pZ9+n/C1ru/2HAPwAo7YM1X4+tLMAAAAASUVORK5CY
II=";
// Get the currently selected From account.
item.from.getAsync({ asyncContext: event }, (result) => {
if (result.status === Office.AsyncResultStatus.Failed) {
console.log(result.error.message);
return;
}
Windows: At present, imports aren't supported in the JavaScript file where you
implement the handling for event-based activation.
Tip
2. To run the add-in in Outlook on Mac, replace the existing script tag with the
following code. Otherwise, skip to the next step.
HTML
<script type="text/javascript"
src="https://appsforoffice.microsoft.com/lib/beta/hosted/office.js">
</script>
HTML
JavaScript
new CopyWebpackPlugin({
patterns: [
{
from: "./src/launchevent/launchevent.js",
to: "launchevent.js",
},
],
}),
Try it out
1. Run the following commands in the root directory of your project. When you run
npm start , the local web server will start (if it isn't already running) and your add-
in will be sideloaded.
command line
command line
npm start
7 Note
2. In your preferred Outlook client, create a new message. If you don't have a default
Outlook signature configured, the add-in adds one to the newly created message.
3. Enable the From field, if applicable. For guidance on how to enable it, see the
"Why is the From button missing?" section of Change the account used to send
email messages .
For guidance on how to deploy your add-in via the Microsoft 365 admin center, see the
"Deploy to users" section of Configure your Outlook add-in for event-based activation.
In addition to these characteristics, the following aspects also apply when an add-in
activates on these events.
Email account aliases are supported. When an alias for the current account is
selected in the From or organizer field, the OnMessageFromChanged or
OnAppointmentFromChanged event occurs without reloading the account's add-ins.
When the From or organizer field dropdown list is opened by mistake or the same
account that appears in the From or organizer field is reselected, the
OnMessageFromChanged or OnAppointmentFromChanged event occurs, but the
See also
Configure your Outlook add-in for event-based activation
AppSource listing options for your event-based Outlook add-in
Debug your event-based Outlook add-in
Article • 06/29/2023
This article discusses the key debugging stages to enable and set breakpoints in your
code as you implement event-based activation in your add-in. The event-based
activation feature was introduced in requirement set 1.10, with additional events now
available in subsequent requirement sets. For more information, see Supported events.
Before you proceed, review the event-based troubleshooting guide for additional
guidance.
Windows
If you used the Yeoman generator for Office Add-ins to create your add-in project
(for example, by doing the event-based activation walkthrough), follow the Created
with Yeoman generator option throughout this article. Otherwise, follow the Other
steps. Visual Studio Code should be at least version 1.56.1.
manifest.
XML manifest: Use the value of the <Id> element child of the root
<OfficeApp> element.
Unified manifest for Microsoft 365 (preview): Use the value of the "id"
property of the root anonymous { ... } object.
7 Note
command line
npm start
In addition to building the code and starting the local server, this command
sets the UseDirectDebugger registry key for this add-in to 1 .
ID]\ . Replace [Add-in ID] with your add-in's ID from the manifest. Set the
registry key to 1 .
4. Perform the action to initiate the event you're developing for, such as creating
a new message to initiate the OnNewMessageCompose event. The Debug Event-
based handler dialog should appear. Do not interact with the dialog yet.
Configure Visual Studio Code
command line
code .
2. In Visual Studio Code, open the ./.vscode/launch.json file and add the
following excerpt to your list of configurations. Save your changes.
JSON
{
"name": "Direct Debugging",
"type": "node",
"request": "attach",
"port": 9223,
"timeout": 600000,
"trace": true
}
Other
1. Create a new folder called Debugging (perhaps in your Desktop folder).
3. Go to File > Open Folder, navigate to the folder you just created, then choose
Select Folder.
7. Add the following excerpt to your list of configurations. Save your changes.
JSON
{
"name": "Direct Debugging",
"type": "node",
"request": "attach",
"port": 9223,
"timeout": 600000,
"trace": true
}
text
Tip
If the bundle.js file doesn't appear in the Wef folder, try the following:
4. In the DEBUG dropdown, select Direct Debugging, then select the Start
Debugging icon.
2. You can now hit your breakpoints in Visual Studio Code, enabling you to
debug your event-based activation code.
Stop the debugger
To stop debugging the rest of the current Outlook on Windows session, in the
Debug Event-based handler dialog, choose Cancel. To re-enable debugging, restart
Outlook.
To prevent the Debug Event-based handler dialog from popping up and stop
debugging for subsequent Outlook sessions, delete the associated registry key,
HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\16.0\Wef\Developer\[Add-in
See also
Configure your Outlook add-in for event-based activation
Event-based activation troubleshooting guide
Debug your add-in with runtime logging
AppSource listing options for your
event-based Outlook add-in
Article • 02/14/2023
An end-user or admin can acquire add-ins through AppSource or the in-app Office
Store. If your add-in's primary scenario or workflow requires event-based activation, you
may want to restrict your add-in to admin deployment only. To enable that restriction,
we can provide flight code URLs for add-ins in AppSource. Thanks to the flight codes,
only end-users with these special URLs can access the listing. The following is an
example URL.
https://appsource.microsoft.com/product/office/WA200002862?
flightCodes=EventBasedTest1
Users and admins can't explicitly search for an add-in by its name in AppSource or the
in-app Office Store when a flight code is enabled for it. As the add-in creator, you can
privately share these flight codes with organization admins for add-in deployment.
7 Note
While end-users can install the add-in using a flight code, the add-in won't include
event-based activation.
) Important
Add-ins that use the Smart Alerts feature can only be published to AppSource if
the manifest's SendMode property is set to the SoftBlock or PromptUser option. If
an add-in's SendMode property is set to Block , it can only be deployed by an
organization's admin as it will fail AppSource validation.
To deploy the add-in, the admin can use the following steps.
) Important
After the updated add-in is approved, organization admins who have previously
deployed the add-in will receive an update message in the Integrated apps section of
the admin center. The message advises the admin about the event-based activation
changes. After the admin accepts the changes, the update will be deployed to end-
users. To learn more about the admin consent process, see Admin consent for installing
event-based add-ins.
For end-users who installed the add-in on their own, the event-based activation feature
won't work even after the add-in has been updated.
Each time you add any new event-based activation function to your add-in, admins will
see the update flow in the admin portal and need to provide consent for additional
events. To learn more about the update and consent process, see Manage apps in the
Integrated apps portal.
See also
Configure your Outlook add-in for event-based activation
Enable shared folders and shared
mailbox scenarios in an Outlook add-in
Article • 05/30/2023
This article describes how to enable shared folders (also known as delegate access) and
shared mailbox scenarios in your Outlook add-in, including which permissions the Office
JavaScript API supports.
7 Note
Shared folder support was introduced in requirement set 1.8, while shared mailbox
support was introduced in requirement set 1.13. For information about client
support for these features, see Supported clients and platforms.
Web browser (classic Outlook Not Not applicable Not applicable Not
UI) applicable applicable
7 Note
Supported setups
The following sections describe supported configurations for shared mailboxes and
shared folders. The feature APIs may not work as expected in other configurations.
Select the platform you'd like to learn how to configure.
Windows
Shared folders
The mailbox owner must first provide access to a delegate using one of the
following options.
Set up delegate access from the Microsoft 365 admin center. This option can
only be completed by administrators. To learn more, see Give mailbox
permissions to another Microsoft 365 user.
Set up delegate access from the Exchange admin center. This option can only
be completed by administrators. To learn more, see Manage permissions for
recipients.
Once access is provided, the delegate must then follow the instructions outlined in
the "Add another person's mailbox to your profile" section of the article Manage
another person's mail and calendar items .
Shared mailboxes
Exchange server admins can create and manage shared mailboxes for sets of users
to access. Exchange Online and on-premises Exchange environments are supported.
2 Warning
Do NOT sign into the shared mailbox with a password. The feature APIs won't
work in that case.
To learn more about where add-ins do and don't activate in general, refer to the
Mailbox items available to add-ins section of the Outlook add-ins overview page.
Supported permissions
The following table describes the permissions that the Office JavaScript API supports for
delegates and shared mailbox users.
Currently the API supports getting existing permissions, but not setting
permissions.
However, if REST or Exchange Web Services (EWS) operations were used to set an
extended property on an item, such changes could take a few hours to sync. We
recommend you instead use the CustomProperties object and related APIs to avoid such
a delay. To learn more, see the custom properties section of the "Get and set metadata
in an Outlook add-in" article.
) Important
In a delegate scenario, you can't use EWS with the tokens currently provided by
office.js API.
First, to support REST calls from a delegate, the add-in must request the read/write
mailbox permission. The markup varies depending on the type of manifest.
XML Manifest
Set the SupportsSharedFolders element to true in the manifest under the parent
element DesktopFormFactor . At present, other form factors aren't supported.
XML
...
<VersionOverrides
xmlns="http://schemas.microsoft.com/office/mailappversionoverrides"
xsi:type="VersionOverridesV1_0">
<VersionOverrides
xmlns="http://schemas.microsoft.com/office/mailappversionoverrides/1.1"
xsi:type="VersionOverridesV1_1">
...
<Hosts>
<Host xsi:type="MailHost">
<DesktopFormFactor>
<SupportsSharedFolders>true</SupportsSharedFolders>
<FunctionFile resid="residDesktopFuncUrl" />
<ExtensionPoint xsi:type="MessageReadCommandSurface">
<!-- configure selected extension point -->
</ExtensionPoint>
</DesktopFormFactor>
</Host>
</Hosts>
...
</VersionOverrides>
</VersionOverrides>
...
JavaScript
function performOperation() {
Office.context.mailbox.getCallbackTokenAsync({
isRest: true
},
function (asyncResult) {
if (asyncResult.status === Office.AsyncResultStatus.Succeeded &&
asyncResult.value !== "") {
Office.context.mailbox.item.getSharedPropertiesAsync({
// Pass auth token along.
asyncContext: asyncResult.value
},
function (asyncResult1) {
let sharedProperties = asyncResult1.value;
let delegatePermissions = sharedProperties.delegatePermissions;
$.ajax({
url: rest_url,
dataType: 'json',
headers:
{
"Authorization": "Bearer " + asyncResult1.asyncContext
}
}
).done(
function (response) {
console.log("success");
}
).fail(
function (error) {
console.log("error message");
}
);
}
}
);
}
}
);
}
Tip
As a delegate, you can use REST to get the content of an Outlook message
attached to an Outlook item or group post.
JavaScript
if (item.getSharedPropertiesAsync) {
// In Windows, Mac, and the web client, this indicates a shared item so
use SharedProperties properties to construct the REST URL.
// Add-ins don't activate on shared items in mobile so no need to handle.
Limitations
Depending on your add-in's scenarios, there are a few limitations for you to consider
when handling shared folder or shared mailbox situations.
1. The mailbox owner starts a message. This can be a new message, a reply, or a
forward.
2. They save the message then move it from their own Drafts folder to a folder
shared with the delegate.
3. The delegate opens the draft from the shared folder then continues composing.
1. A shared mailbox user starts a message. This can be a new message, a reply, or a
forward.
2. They save the message then move it from their own Drafts folder to a folder in the
shared mailbox.
3. Another shared mailbox user opens the draft from the shared mailbox then
continues composing.
The message is now in a shared context and add-ins that support these shared scenarios
can get the item's shared properties. After the message has been sent, it's usually found
in the sender's Sent Items folder.
An Outlook add-in consists of two components: the add-in manifest and a web app
supported by the JavaScript library for Office Add-ins (office.js). The manifest describes
how the add-in integrates across Outlook clients.
You can learn about manifests at Office Add-in manifests. This article focuses on aspects
of the manifest that are primarily relevant to Outlook.
Permissions
Outlook add-ins have a special set of permissions that don't apply to add-ins for other
Office host applications. These permissions must be configured in the manifest. For
details about these permissions and their effects, see Understanding Outlook add-in
permissions.
XML Manifest
The <Permissions> element contains the required permissions for the add-in. In
general, you should specify the minimum necessary permission that your add-in
needs, depending on the exact methods that you plan to use. For example, a mail
add-in that activates in compose forms and only reads but doesn't write to item
properties like item.requiredAttendees, and doesn't call
mailbox.makeEwsRequestAsync to access any Exchange Web Services operations
should specify ReadItem permission. The following is an example of setting an
Outlook permission.
XML
<OfficeApp>
...
<Permissions>ReadWriteItem</Permissions>
...
</OfficeApp>
Activation rules
7 Note
Activation rules aren't supported in Outlook add-ins that use the unified manifest
for Microsoft 365.
Activation rules are specified in the <Rule> element. The <Rule> element can appear as
a child of the <OfficeApp> element in 1.1 manifests.
Activation rules can be used to activate an add-in based on one or more of the
following conditions on the currently selected item.
7 Note
Activation rules only apply to clients that don't support the <VersionOverrides>
element.
For details and samples of activation rules, see Activation rules for Outlook add-ins.
Form settings
7 Note
Form settings aren't supported in Outlook add-ins that use the unified manifest for
Microsoft 365.
The <FormSettings> element is used by older Outlook clients, which only support
schema 1.1 and not <VersionOverrides>. Using this element, developers define how the
add-in will appear in such clients. There are two parts—ItemRead and ItemEdit.
ItemRead is used to specify how the add-in appears when the user reads messages and
appointments. ItemEdit describes how the add-in appears while the user is composing a
reply, new message, new appointment or editing an appointment as an organizer.
These settings are directly related to the activation rules in the <Rule> element. For
example, if an add-in specifies that it should appear on a message in compose mode, an
ItemEdit form must be specified.
See also
Localization for Office Add-ins
Privacy, permissions, and security for Outlook add-ins
Outlook add-in APIs
Office Add-ins manifest
Understanding Outlook add-in permissions
Use regular expression activation rules to show an Outlook add-in
Match strings in an Outlook item as well-known entities
Activation rules for contextual Outlook
add-ins
Article • 03/21/2023
Outlook activates some types of add-ins if the message or appointment that the user is
reading or composing satisfies the activation rules of the add-in. This is true for all add-
ins that use the 1.1 manifest schema. The user can then choose the add-in from the
Outlook UI to start it for the current item.
7 Note
Outlook Add-in features that depend on activation rules aren't supported when the
add-in uses a Unified manifest for Microsoft 365 (preview).
The following figure shows Outlook add-ins activated in the add-in bar for the message
in the Reading Pane.
The Rule element that you use to specify an individual rule is of the abstract Rule
complex type. Each of the following types of rules extends this abstract Rule
complex type. So when you specify an individual rule in a manifest, you must use
the xsi:type attribute to further define one of the following types of rules.
For example, the following rule defines an ItemIs rule. <Rule xsi:type="ItemIs"
ItemType="Message" />
The FormType attribute applies to activation rules in the manifest v1.1 but is not
defined in VersionOverrides v1.0. So it can't be used when ItemIs is used in the
VersionOverrides node.
The following table lists the types of rules that are available. You can find more
information following the table and in the specified articles under Create Outlook add-
ins for read forms.
Specify one of the following item types in the ItemType attribute of an ItemIs rule. You
can specify more than one ItemIs rule in a manifest. The ItemType simpleType defines
the types of Outlook items that support Outlook add-ins.
Value Description
Appointment Specifies an item in an Outlook calendar. This includes a meeting item that has
been responded to and has an organizer and attendees, or an appointment that
does not have an organizer or attendee and is simply an item on the calendar.
This corresponds to the IPM.Appointment message class in Outlook.
Message Specifies one of the following items received in typically the Inbox.
An email message. This corresponds to the IPM.Note message class in
Outlook.
A meeting request, response, or cancellation. This corresponds to the
following message classes in Outlook.
IPM.Schedule.Meeting.Request
IPM.Schedule.Meeting.Neg
IPM.Schedule.Meeting.Pos
IPM.Schedule.Meeting.Tent
IPM.Schedule.Meeting.Canceled
The FormType attribute is used to specify the mode (read or compose) in which the add-
in should activate.
7 Note
The ItemIs FormType attribute is defined in schema v1.1 and later but not in
VersionOverrides v1.0. Do not include the FormType attribute when defining add-in
commands.
After an add-in is activated, you can use the mailbox.item property to obtain the
currently selected item in Outlook, and the item.itemType property to obtain the type of
the current item.
You can optionally use the ItemClass attribute to specify the message class of the item,
and the IncludeSubClasses attribute to specify whether the rule should be true when
the item is a subclass of the specified class.
For more information about message classes, see Item Types and Message Classes.
The following example is an ItemIs rule that lets users see the add-in in the Outlook
add-in bar when the user is reading a message.
XML
The following example is an ItemIs rule that lets users see the add-in in the Outlook
add-in bar when the user is reading a message or appointment.
XML
ItemHasAttachment rule
The ItemHasAttachment complex type defines a rule that checks if the selected item
contains an attachment.
XML
ItemHasKnownEntity rule
Before an item is made available to an add-in, the server examines it to determine
whether the subject and body contain any text that is likely to be one of the known
entities. If any of these entities are found, it is placed in a collection of known entities
that you access by using the getEntities or getEntitiesByType method of that item.
You can specify a rule by using ItemHasKnownEntity that shows your add-in when an
entity of the specified type is present in the item. You can specify the following known
entities in the EntityType attribute of an ItemHasKnownEntity rule.
Address
Contact
EmailAddress
MeetingSuggestion
PhoneNumber
TaskSuggestion
URL
The following example shows a collection of Rule elements that show the add-in when
one of the specified well-known entities is present in the message.
XML
XML
For more information about entities in activation rules, see Match strings in an Outlook
item as well-known entities.
ItemHasRegularExpressionMatch rule
The ItemHasRegularExpressionMatch complex type defines a rule that uses a regular
expression to match the contents of the specified property of an item. If text that
matches the regular expression is found in the specified property of the item, Outlook
activates the add-in bar and displays the add-in. You can use the getRegExMatches or
getRegExMatchesByName method of the object that represents the currently selected item
to obtain matches for the specified regular expression.
XML
For more information about using the ItemHasRegularExpressionMatch rule, see Use
regular expression activation rules to show an Outlook add-in.
RuleCollection rule
The RuleCollection complex type combines multiple rules into a single rule. You can
specify whether the rules in the collection should be combined with a logical OR or a
logical AND by using the Mode attribute.
When a logical AND is specified, an item must match all the specified rules in the
collection to show the add-in. When a logical OR is specified, an item that matches any
of the specified rules in the collection will show the add-in.
You can combine RuleCollection rules to form complex rules. The following example
activates the add-in when the user is viewing an appointment or message item and the
subject or body of the item contains an address.
XML
The following example activates the add-in when the user is composing a message, or
when the user is viewing an appointment and the subject or body of the appointment
contains an address.
XML
ItemHasKnownEntity An Outlook rich client will apply the rule against the first 1 MB of the body,
and not to the rest of the body.
Add-in element Guidelines
See also
Create Outlook add-ins for compose forms
Limits for activation and JavaScript API for Outlook add-ins
Use regular expression activation rules to show an Outlook add-in
Match strings in an Outlook item as well-known entities
Add support for add-in commands in
Outlook on mobile devices
Article • 07/13/2023
Using add-in commands in Outlook on mobile devices allows your users to access the
same functionality (with some limitations) that they already have in Outlook on the web,
on Windows, and on Mac. Adding support for Outlook mobile requires updating the
add-in manifest and possibly changing your code for mobile scenarios.
7 Note
Add-ins using the Unified manifest for Microsoft 365 (preview) aren't currently
supported on mobile devices.
The first step to enabling add-in commands in Outlook mobile is to define them in the
add-in manifest. The VersionOverrides v1.1 schema defines a new form factor for
mobile, MobileFormFactor.
This element contains all of the information for loading the add-in in mobile clients. This
enables you to define completely different UI elements and JavaScript files for the
mobile experience.
The following example shows a single task pane button in a MobileFormFactor element.
XML
<VersionOverrides
xmlns="http://schemas.microsoft.com/office/mailappversionoverrides/1.1"
xsi:type="VersionOverridesV1_1">
...
<MobileFormFactor>
<FunctionFile resid="residUILessFunctionFileUrl" />
<ExtensionPoint xsi:type="MobileMessageReadCommandSurface">
<Group id="mobileMsgRead">
<Label resid="groupLabel" />
<Control xsi:type="MobileButton" id="TaskPaneBtn">
<Label resid="residTaskPaneButtonName" />
<Icon xsi:type="bt:MobileIconList">
<bt:Image size="25" scale="1" resid="tp0icon" />
<bt:Image size="25" scale="2" resid="tp0icon" />
<bt:Image size="25" scale="3" resid="tp0icon" />
<bt:Image size="32" scale="1" resid="tp0icon" />
<bt:Image size="32" scale="2" resid="tp0icon" />
<bt:Image size="32" scale="3" resid="tp0icon" />
This is very similar to the elements that appear in a DesktopFormFactor element, with
some notable differences.
Code considerations
Designing an add-in for mobile introduces some additional considerations.
Pinch zoom
By default users can use the "pinch zoom" gesture to zoom in on task panes. If this
doesn't make sense for your scenario, be sure to disable pinch zoom in your HTML.
Supported APIs
Although Outlook mobile supports up to Mailbox requirement set 1.5, you can now
implement additional APIs from later requirement sets to further extend the capability
of your add-in on Outlook mobile. For guidance on which APIs you can implement in
your mobile add-in, see Outlook JavaScript APIs supported in Outlook on mobile
devices.
See also
Requirement sets supported by Exchange servers and Outlook clients
Outlook JavaScript APIs supported in Outlook on mobile devices
Outlook add-in requirements
Article • 03/28/2022
For Outlook add-ins to load and function properly, there are a number of requirements
for both the servers and the clients.
Client requirements
The client must be one of the supported applications for Outlook add-ins. The
following clients support add-ins.
Outlook 2013 or later on Windows
Outlook 2016 or later on Mac
Outlook on iOS
Outlook on Android
Outlook on the web for Exchange 2016 or later
Outlook on the web for Exchange 2013
Outlook.com
See also
Requirements for running Office Add-ins
Office client application and platform availability for Office Add-ins (Outlook
section)
Outlook JavaScript API requirement set support
Use the Outlook REST APIs from an
Outlook add-in
Article • 03/28/2023
) Important
It was previously announced that the Outlook REST endpoints will be fully
decommissioned on November 30, 2022 (see the November 2020 announcement).
However, the decommission date has been postponed. The new date in 2023 will
be announced six months before the decommission is enforced through the
Microsoft 365 Developer Blog . For more information on this recent update, see
the November 2022 announcement . Although the decommission date has been
postponed, we highly encourage you to migrate your add-ins to use Microsoft
Graph. For guidance, see Compare Microsoft Graph and Outlook REST API
endpoints.
To assist you with the migration, active add-ins are able to keep using the REST
service until extended support ends for Outlook 2019 on October 14, 2025. Add-in
traffic that uses the service will be automatically identified for exemption based on
the add-in's manifest ID. This exemption applies to privately released and
AppSource-hosted add-ins. It also includes new add-ins developed after the
decommission date.
If your add-in will require write access to the current item or other items in the user's
mailbox, your add-in must specify the read/write mailbox permission. level in its
manifest. In this case, the token returned will contain read/write access to the user's
messages, events, and contacts.
Example
JavaScript
Office.context.mailbox.getCallbackTokenAsync({isRest: true},
function(result){
if (result.status === "succeeded") {
const accessToken = result.value;
Your add-in can determine which Outlook client it is loaded in by checking the
Office.context.mailbox.diagnostics.hostName property.
Example
JavaScript
function getItemRestId() {
if (Office.context.mailbox.diagnostics.hostName === 'OutlookIOS') {
// itemId is already REST-formatted.
return Office.context.mailbox.item.itemId;
} else {
// Convert to an item ID for API v2.0.
return Office.context.mailbox.convertToRestId(
Office.context.mailbox.item.itemId,
Office.MailboxEnums.RestVersion.v2_0
);
}
}
Example
JavaScript
// Example: https://outlook.office.com
const restHost = Office.context.mailbox.restUrl;
) Important
JavaScript
function getCurrentItem(accessToken) {
// Get the item's REST ID.
const itemId = getItemRestId();
$.ajax({
url: getMessageUrl,
dataType: 'json',
headers: { 'Authorization': 'Bearer ' + accessToken }
}).done(function(item){
// Message is passed in `item`.
const subject = item.Subject;
...
}).fail(function(error){
// Handle error.
});
}
See also
For an example that calls the REST APIs from an Outlook add-in, see command-
demo on GitHub.
Outlook REST APIs are also available through the Microsoft Graph endpoint but
there are some key differences, including how your add-in gets an access token.
For more information, see Outlook REST API via Microsoft Graph.
Call web services from an Outlook add-
in
Article • 05/20/2023
Your add-in can use Exchange Web Services (EWS) from a computer that is running
Exchange Server, a web service that is available on the server that provides the source
location for the add-in's UI, or a web service that is available on the Internet. This article
provides an example that shows how an Outlook add-in can request information from
EWS.
) Important
EWS calls and operations aren't supported in add-ins running in Outlook on iOS
and Android.
The way you call a web service varies based on where the web service is located. The
following tables list the different ways you can call a web service based on location.
The Exchange Use the mailbox.makeEwsRequestAsync method to call EWS operations that
server that add-ins support. The Exchange server that hosts the mailbox also exposes EWS.
hosts the client
mailbox
The web server Call the web service by using standard JavaScript techniques. The JavaScript
that provides code in the UI frame runs in the context of the web server that provides the UI.
the source Therefore, it can call web services on that server without causing a cross-site
location for the scripting error.
add-in UI
All other Create a proxy for the web service on the web server that provides the source
locations location for the UI. If you do not provide a proxy, cross-site scripting errors will
prevent your add-in from running. One way to provide a proxy is by using
JSON/P. For more information, see Privacy and security for Office Add-ins.
The XML for the SOAP request for that EWS operation, as an argument to the data
parameter
Any optional input data for that callback function (as the userContext argument)
When the EWS SOAP request is complete, Outlook calls the callback function with one
argument, which is an AsyncResult object. The callback function can access two
properties of the AsyncResult object: the value property, which contains the XML SOAP
response of the EWS operation, and optionally, the asyncContext property, which
contains any data passed as the userContext parameter. Typically, the callback function
then parses the XML in the SOAP response to get any relevant information, and
processes that information accordingly.
Specify the prefix for a tag name when using the DOM method
getElementsByTagName , to include support for Internet Explorer and the Trident
webview.
XML
<t:ExtendedProperty><t:ExtendedFieldURI PropertySetId="00000000-0000-
0000-0000-000000000000"
PropertyName="MyProperty"
PropertyType="String"/>
<t:Value>{
...
}</t:Value></t:ExtendedProperty>
Code, as in the following, would work on a browser like Chrome to get the XML
enclosed by the ExtendedProperty tags.
JavaScript
For the Trident (Internet Explorer) webview, you must include the t: prefix of the
tag name, as follows.
JavaScript
Use the DOM property textContent to get the contents of a tag in an EWS
response, as follows.
JavaScript
content = $.parseJSON(value.textContent);
Other properties such as innerHTML may not work on the Trident (Internet Explorer)
webview for some tags in an EWS response.
Example
The following example calls makeEwsRequestAsync to use the GetItem operation to get
the subject of an item. This example includes the following three functions.
getSubjectRequest – Takes an item ID as input, and returns the XML for the SOAP
sendRequest – Calls getSubjectRequest to get the SOAP request for the selected
item, then passes the SOAP request and the callback function, callback , to
makeEwsRequestAsync to get the subject of the specified item.
callback – Processes the SOAP response which includes any subject and other
JavaScript
function getSubjectRequest(id) {
// Return a GetItem operation request for the subject of the specified
item.
const result =
'<?xml version="1.0" encoding="utf-8"?>' +
'<soap:Envelope xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"'
+
' xmlns:xsd="https://www.w3.org/2001/XMLSchema"' +
' xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"'
+
'
xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">' +
' <soap:Header>' +
' <RequestServerVersion Version="Exchange2013"
xmlns="http://schemas.microsoft.com/exchange/services/2006/types"
soap:mustUnderstand="0" />' +
' </soap:Header>' +
' <soap:Body>' +
' <GetItem
xmlns="http://schemas.microsoft.com/exchange/services/2006/messages">' +
' <ItemShape>' +
' <t:BaseShape>IdOnly</t:BaseShape>' +
' <t:AdditionalProperties>' +
' <t:FieldURI FieldURI="item:Subject"/>' +
' </t:AdditionalProperties>' +
' </ItemShape>' +
' <ItemIds><t:ItemId Id="' + id + '"/></ItemIds>' +
' </GetItem>' +
' </soap:Body>' +
'</soap:Envelope>';
return result;
}
function sendRequest() {
// Create a local variable that contains the mailbox.
const mailbox = Office.context.mailbox;
mailbox.makeEwsRequestAsync(getSubjectRequest(mailbox.item.itemId),
callback);
}
function callback(asyncResult) {
const result = asyncResult.value;
const context = asyncResult.context;
The following describes how you can use the makeEwsRequestAsync method.
1. In the XML, substitute any item IDs and relevant EWS operation attributes with
appropriate values.
4. In the callback function, verify the results of the operation in the SOAP response.
The following table lists the EWS operations that add-ins support. To see examples of
SOAP requests and responses, choose the link for each operation. For more information
about EWS operations, see EWS operations in Exchange.
CopyItem operation Copies the specified items and puts the new items in a designated folder
in the Exchange store.
FindFolder operation Finds subfolders of an identified folder and returns a set of properties
that describe the set of subfolders.
FindItem operation Identifies items that are located in a specified folder in the Exchange
store.
GetConversationItems Gets one or more sets of items that are organized in nodes in a
operation conversation.
GetFolder operation Gets the specified properties and contents of folders from the Exchange
store.
GetItem operation Gets the specified properties and contents of items from the Exchange
store.
MarkAsJunk Moves email messages to the Junk Email folder, and adds or removes
operation senders of the messages from the blocked senders list accordingly.
MoveItem operation Moves items to a single destination folder in the Exchange store.
SendItem operation Sends email messages that are located in the Exchange store.
UpdateItem operation Modifies the properties of existing items in the Exchange store.
7 Note
FAI (Folder Associated Information) items cannot be updated (or created) from an
add-in. These hidden messages are stored in a folder and are used to store a
variety of settings and auxiliary data. Attempting to use the UpdateItem operation
will throw an ErrorAccessDenied error: "Office extension is not allowed to update
this type of item". As an alternative, you may use the EWS Managed API to update
these items from a Windows client or a server application. Caution is recommended
as internal, service-type data structures are subject to change and could break your
solution.
7 Note
To use the makeEwsRequestAsync method, your add-in must request the read/write
mailbox permission in the manifest. The markup varies depending on the type of
manifest.
For information about using the read/write mailbox permission, see read/write mailbox
permission.
See also
Privacy and security for Office Add-ins
Addressing same-origin policy limitations in Office Add-ins
EWS reference for Exchange
Mail apps for Outlook and EWS in Exchange
See the following for creating backend services for add-ins using ASP.NET Web API.
Create a web service for an Office Add-in using the ASP.NET Web API
The basics of building an HTTP service using ASP.NET Web API
Get and set Outlook item data in read or
compose forms
Article • 10/04/2022
Starting in version 1.1 of the Office Add-ins manifests schema, Outlook can activate
add-ins when the user is viewing or composing an item. Depending on whether an add-
in is activated in a read or compose form, the properties that are available to the add-in
on the item differ as well.
For example, the dateTimeCreated and dateTimeModified properties are defined only
for an item that has already been sent (item is subsequently viewed in a read form) but
not when the item is being created (in a compose form). Another example is the bcc
property, which is only meaningful when a message is being authored (in a compose
form), and is not accessible to the user in a read form.
For the remaining item-level properties available in compose forms, because the add-in
and user can possibly be reading or writing the same property at the same time, the
methods to get or set them in compose mode are asynchronous, and hence the type of
the objects returned by these properties may also be different in compose forms than in
read forms. For more information about using asynchronous methods to get or set
item-level properties in compose mode, see Get and set item data in a compose form in
Outlook.
By specifying the read item permission in the add-in manifest, you can use the
mailbox.getCallbackTokenAsync method to get an Exchange callback token, the
mailbox.ewsUrl property to get the URL of the EWS endpoint for the user's mailbox, and
item.itemId to get the EWS ID for the selected item. You can then pass the callback
token, EWS endpoint URL, and the EWS item ID to server-side code to access the
GetItem operation, to get more properties of the item.
See also
Get and set item data in a compose form in Outlook
Call web services from an Outlook add-in
Get and set categories
Article • 03/21/2023
7 Note
Support for this feature was introduced in requirement set 1.8. See clients and
platforms that support this requirement set.
) Important
For the add-in to manage the categories master list, it must request the read/write
mailbox permission in the manifest. The markup varies depending on the type of
manifest.
JavaScript
const masterCategoriesToAdd = [
{
"displayName": "Urgent!",
"color": Office.MailboxEnums.CategoryColor.Preset0
}
];
Office.context.mailbox.masterCategories.addAsync(masterCategoriesToAdd,
function (asyncResult) {
if (asyncResult.status === Office.AsyncResultStatus.Succeeded) {
console.log("Successfully added categories to master list");
} else {
console.log("masterCategories.addAsync call failed with error: " +
asyncResult.error.message);
}
});
JavaScript
Office.context.mailbox.masterCategories.getAsync(function (asyncResult) {
if (asyncResult.status === Office.AsyncResultStatus.Failed) {
console.log("Action failed with error: " +
asyncResult.error.message);
} else {
const masterCategories = asyncResult.value;
console.log("Master categories:");
masterCategories.forEach(function (item) {
console.log("-- " + JSON.stringify(item));
});
}
});
JavaScript
Office.context.mailbox.masterCategories.removeAsync(masterCategoriesToRemove
, function (asyncResult) {
if (asyncResult.status === Office.AsyncResultStatus.Succeeded) {
console.log("Successfully removed categories from master list");
} else {
console.log("masterCategories.removeAsync call failed with error: "
+ asyncResult.error.message);
}
});
) Important
Only categories in the master list on your mailbox are available for you to apply to
a message or appointment. See the earlier section Manage categories in the
master list for more information.
In Outlook on the web, you can't use the API to manage categories on a message
in Compose mode.
JavaScript
Office.context.mailbox.item.categories.addAsync(categoriesToAdd, function
(asyncResult) {
if (asyncResult.status === Office.AsyncResultStatus.Succeeded) {
console.log("Successfully added categories");
} else {
console.log("categories.addAsync call failed with error: " +
asyncResult.error.message);
}
});
JavaScript
Office.context.mailbox.item.categories.getAsync(function (asyncResult) {
if (asyncResult.status === Office.AsyncResultStatus.Failed) {
console.log("Action failed with error: " +
asyncResult.error.message);
} else {
const categories = asyncResult.value;
console.log("Categories:");
categories.forEach(function (item) {
console.log("-- " + JSON.stringify(item));
});
}
});
JavaScript
Office.context.mailbox.item.categories.removeAsync(categoriesToRemove,
function (asyncResult) {
if (asyncResult.status === Office.AsyncResultStatus.Succeeded) {
console.log("Successfully removed categories");
} else {
console.log("categories.removeAsync call failed with error: " +
asyncResult.error.message);
}
});
See also
Outlook permissions
Get and set internet headers on a
message in an Outlook add-in
Article • 03/28/2023
Background
A common requirement in Outlook add-ins development is to store custom properties
associated with an add-in at different levels. At present, custom properties are stored at
the item or mailbox level.
Item level - For properties that apply to a specific item, use the CustomProperties
object. For example, store a customer code associated with the person who sent
the email.
Mailbox level - For properties that apply to all the mail items in the user's mailbox,
use the RoamingSettings object. For example, store a user's preference to show the
temperature in a particular scale.
Both types of properties aren't preserved after the item leaves the Exchange server, so
the email recipients can't get any properties set on the item. Therefore, developers can't
access those settings or other Multipurpose Internet Mail Extensions (MIME) properties
to enable better read scenarios.
While there's a way for you to set the internet headers through Exchange Web Services
(EWS) requests, in some scenarios, making an EWS request won't work. For example, in
Compose mode on Outlook desktop, the item ID isn't synced on saveAsync in cached
mode.
Tip
To learn more about using these options, see Get and set add-in metadata for an
Outlook add-in.
Stamp information on an email that persists after it leaves Exchange across all
clients.
Read information on an email that persisted after the email left Exchange across all
clients in mail read scenarios.
Access the entire MIME header of the email.
JavaScript
function setCallback(asyncResult) {
if (asyncResult.status === Office.AsyncResultStatus.Succeeded) {
console.log("Successfully set headers");
} else {
console.log("Error setting headers: " +
JSON.stringify(asyncResult.error));
}
}
function getCallback(asyncResult) {
if (asyncResult.status === Office.AsyncResultStatus.Succeeded) {
console.log("Selected headers: " + JSON.stringify(asyncResult.value));
} else {
console.log("Error getting selected headers: " +
JSON.stringify(asyncResult.error));
}
}
function removeCallback(asyncResult) {
if (asyncResult.status === Office.AsyncResultStatus.Succeeded) {
console.log("Successfully removed selected headers");
} else {
console.log("Error removing selected headers: " +
JSON.stringify(asyncResult.error));
}
}
setCustomHeaders();
getSelectedCustomHeaders();
removeSelectedCustomHeaders();
getSelectedCustomHeaders();
/* Sample output:
Successfully set headers
Selected headers: {"best-vegetable":"spinach","preferred-
fruit":"orange","preferred-vegetable":"broccoli"}
Successfully removed selected headers
Selected headers: {"preferred-fruit":"orange","preferred-
vegetable":"broccoli"}
*/
JavaScript
Office.context.mailbox.item.getAllInternetHeadersAsync(getCallback);
function getCallback(asyncResult) {
if (asyncResult.status === Office.AsyncResultStatus.Succeeded) {
console.log("Sender's preferred fruit: " +
asyncResult.value.match(/preferred-fruit:.*/gim)[0].slice(17));
console.log("Sender's preferred vegetable: " +
asyncResult.value.match(/preferred-vegetable:.*/gim)[0].slice(21));
} else {
console.log("Error getting preferences from header: " +
JSON.stringify(asyncResult.error));
}
}
/* Sample output:
Sender's preferred fruit: orange
Sender's preferred vegetable: broccoli
*/
) Important
This sample works for simple cases. For more complex information retrieval (for
example, multi-instance headers or folded values as described in RFC 2822 ), try
using an appropriate MIME-parsing library.
Recommended practices
Currently, internet headers are a finite resource on a user's mailbox. When the quota is
exhausted, you can't create any more internet headers on that mailbox, which can result
in unexpected behavior from clients that rely on this to function.
Apply the following guidelines when you create internet headers in your add-in.
Create the minimum number of headers required. The header quota is based on
the total size of headers applied to a message. In Exchange Online, the header limit
is capped at 256 KB, while in an Exchange on-premises environment, the limit is
determined by your organization's administrator. For further information on
header limits, see Exchange Online message limits and Exchange Server message
limits.
Name headers so that you can reuse and update their values later. As such, avoid
naming headers in a variable manner (for example, based on user input,
timestamp, etc.).
See also
Get and set add-in metadata for an Outlook add-in
Get and set recurrence
Article • 03/28/2023
Sometimes you need to create and update a recurring appointment, such as a weekly
status meeting for a team project or a yearly birthday reminder. You can use the Office
JavaScript API to manage the recurrence patterns of an appointment series in your add-
in.
7 Note
Support for this feature was introduced in requirement set 1.7. See clients and
platforms that support this requirement set.
7 Note
You can also use the firstDayOfWeek property with the weekly recurrence type.
The specified day will start the list of days displayed in the recurrence dialog.
Access recurrence
How you access the recurrence pattern and what you can do with it depends on if you're
the appointment organizer or an attendee.
The appointment organizer can specify the recurrence pattern for an appointment series
in compose mode only. In the following example, the appointment series is set to occur
from 10:30 AM to 11:00 AM PST every Tuesday and Thursday during the period
November 2, 2019 to December 2, 2019.
JavaScript
const pattern = {
"seriesTime": seriesTimeObject,
"recurrenceType": "weekly",
"recurrenceProperties": {"interval": 1, "days": ["tue", "thu"]},
"recurrenceTimeZone": {"name": "Pacific Standard Time"}};
Office.context.mailbox.item.recurrence.setAsync(pattern, callback);
function callback(asyncResult)
{
console.log(JSON.stringify(asyncResult));
}
JavaScript
Office.context.mailbox.item.recurrence.getAsync(callback);
function callback(asyncResult) {
const recurrencePattern = asyncResult.value;
recurrencePattern.seriesTime.setDuration(60);
Office.context.mailbox.item.recurrence.setAsync(recurrencePattern,
(asyncResult) => {
if (asyncResult.status !== Office.AsyncResultStatus.Succeeded) {
console.log("failed");
return;
}
console.log("success");
});
}
Get recurrence
JavaScript
Office.context.mailbox.item.recurrence.getAsync(callback);
function callback(asyncResult){
const context = asyncResult.context;
const recurrence = asyncResult.value;
if (recurrence == null) {
console.log("Non-recurring meeting");
} else {
console.log(JSON.stringify(recurrence));
}
}
The following example shows the results of the getAsync call that retrieves the
recurrence for a series.
7 Note
JSON
{
"recurrenceType": "weekly",
"recurrenceProperties": {
"interval": 1,
"days": ["tue","thu"],
"firstDayOfWeek": "sun"},
"seriesTime": {seriesTimeObject},
"recurrenceTimeZone": {
"name": "Pacific Standard Time",
"offset": -480}}
JavaScript
outputRecurrence(Office.context.mailbox.item);
function outputRecurrence(item) {
const recurrence = item.recurrence;
const seriesId = item.seriesId;
if (recurrence == null) {
console.log("Non-recurring item");
} else {
console.log(JSON.stringify(recurrence));
}
}
The following example shows the value of the item.recurrence property for an
appointment series.
7 Note
JSON
{
"recurrenceType": "weekly",
"recurrenceProperties": {
"interval": 1,
"days": ["tue","thu"],
"firstDayOfWeek": "sun"},
"seriesTime": {seriesTimeObject},
"recurrenceTimeZone": {
"name": "Pacific Standard Time",
"offset": -480}}
Get the recurrence details
After you've retrieved the recurrence object (either from the getAsync callback or from
item.recurrence ), you can get specific properties of the recurrence. For example, you
can get the start and end dates and times of the series by using methods on the
recurrence.seriesTime property.
JavaScript
See also
RecurrenceChanged event
Recurrence object
SeriesTime object
Get and set add-in metadata for an
Outlook add-in
Article • 03/28/2023
You can manage custom data in your Outlook add-in by using either of the following:
Both of these give access to custom data that's only accessible by your Outlook add-in,
but each method stores the data separately from the other. That is, the data stored
through roaming settings isn't accessible by custom properties, and vice versa. Roaming
settings are stored on the user's mailbox while custom properties are stored on a
message or appointment. Stored data is accessible in subsequent Outlook sessions on
all the form factors that the add-in supports.
Changes to this data are stored on an in-memory copy of those settings for the current
Outlook session. You should explicitly save all the roaming settings after updating them
so that they'll be available the next time the user opens your add-in, on the same or any
other supported device.
The following is an example of the structure, assuming there are three defined roaming
settings named add-in_setting_name_0 , add-in_setting_name_1 , and add-
in_setting_name_2 .
JSON
{
"add-in_setting_name_0": "add-in_setting_value_0",
"add-in_setting_name_1": "add-in_setting_value_1",
"add-in_setting_name_2": "add-in_setting_value_2"
}
JavaScript
let _mailbox;
let _settings;
let _customerName;
let _customerBalance;
The set method creates the setting if the setting doesn't already exist, and assigns the
setting to the specified value. The saveAsync method saves roaming settings
asynchronously. This code sample passes a callback function,
saveMyAddInSettingsCallback , to saveAsync . When the asynchronous call finishes,
JavaScript
// Set a roaming setting.
function setAddInSetting() {
_settings.set("cookie", Date());
// Save roaming settings to the mailbox, so that they'll be available in
the next session.
_settings.saveAsync(saveMyAddInSettingsCallback);
}
the cookie setting and save all the roaming settings to the mailbox.
JavaScript
7 Note
Custom properties are only available to the add-in that created them and only
through the mail item in which they were saved. Because of this, properties set
while in compose mode aren't transmitted to recipients of the mail item. When a
message or appointment with custom properties is sent, its properties can be
accessed from the item in the Sent Items folder. To allow recipients to receive the
custom data your add-in sets, consider using InternetHeaders instead.
7 Note
Outlook on Mac doesn't cache custom properties. If the user's network goes
down, add-ins in Outlook on Mac wouldn't be able to access their custom
properties.
In Outlook on Windows, custom properties saved while in compose mode
only persist after the item being composed is closed or after
Office.context.mailbox.item.saveAsync is called.
Office.initialize -- Initializes the add-in and loads the custom property bag from the
Exchange server.
customPropsCallback -- Gets the custom property bag that's returned from the
server and saves it locally for later use.
updateProperty -- Sets or updates a specific property, and then saves the change
to the local property bag.
removeProperty -- Removes a specific property from the property bag, and then
saves these changes.
JavaScript
let _mailbox;
let _customProps;
Custom Properties.) You can then use EWS or REST to get this MAPI-based property.
Your mail add-in can get the CustomProperties MAPI-based extended property by using
the EWS GetItem operation. Access GetItem on the server side by using a callback
token, or on the client side by using the mailbox.makeEwsRequestAsync method. In the
GetItem request, specify the CustomProperties MAPI-based property in its property set
using the details provided in the preceding section How custom properties are stored
on an item.
The following example shows how to get an item and its custom properties.
) Important
In the following example, replace <app-guid> with your add-in's ID.
TypeScript
let request_str =
'<?xml version="1.0" encoding="utf-8"?>' +
'<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' +
'xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"' +
'xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"' +
'xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">'
+
'<soap:Header xmlns:wsse="http://docs.oasis-
open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"' +
'xmlns:wsa="http://www.w3.org/2005/08/addressing">' +
'<t:RequestServerVersion Version="Exchange2010_SP1"/>' +
'</soap:Header>' +
'<soap:Body>' +
'<m:GetItem>' +
'<m:ItemShape>' +
'<t:BaseShape>AllProperties</t:BaseShape>' +
'<t:IncludeMimeContent>true</t:IncludeMimeContent>' +
'<t:AdditionalProperties>' +
'<t:ExtendedFieldURI ' +
'DistinguishedPropertySetId="PublicStrings" ' +
'PropertyName="cecp-<app-guid>"' +
'PropertyType="String" ' +
'/>' +
'</t:AdditionalProperties>' +
'</m:ItemShape>' +
'<m:ItemIds>' +
'<t:ItemId Id="' +
Office.context.mailbox.item.itemId +
'"/>' +
'</m:ItemIds>' +
'</m:GetItem>' +
'</soap:Body>' +
'</soap:Envelope>';
Office.context.mailbox.makeEwsRequestAsync(
request_str,
function(asyncResult) {
if (asyncResult.status === Office.AsyncResultStatus.Succeeded) {
console.log(asyncResult.value);
}
else {
console.log(JSON.stringify(asyncResult));
}
}
);
You can also get more custom properties if you specify them in the request string as
other ExtendedFieldURI elements.
In your add-in, you can construct your REST query against messages and events to get
the ones that already have custom properties. In your query, you should include the
CustomProperties MAPI-based property and its property set using the details provided
in the section How custom properties are stored on an item.
The following example shows how to get all events that have any custom properties set
by your add-in and ensure that the response includes the value of the property so you
can apply further filtering logic.
) Important
HTTP
GET https://outlook.office.com/api/v2.0/Me/Events?
$filter=SingleValueExtendedProperties/Any
(ep: ep/PropertyId eq 'String {00020329-0000-0000-C000-000000000046}
Name cecp-<app-guid>' and ep/Value ne null)
&$expand=SingleValueExtendedProperties($filter=PropertyId eq 'String
{00020329-0000-0000-C000-000000000046} Name cecp-<app-guid>')
For other examples that use REST to get single-value MAPI-based extended properties,
see Get singleValueExtendedProperty.
The following example shows how to get an item and its custom properties. In the
callback function for the done method, item.SingleValueExtendedProperties contains a
list of the requested custom properties.
) Important
TypeScript
Office.context.mailbox.getCallbackTokenAsync(
{
isRest: true
},
function (asyncResult) {
if (asyncResult.status === Office.AsyncResultStatus.Succeeded
&& asyncResult.value !== "") {
let item_rest_id = Office.context.mailbox.convertToRestId(
Office.context.mailbox.item.itemId,
Office.MailboxEnums.RestVersion.v2_0);
let rest_url = Office.context.mailbox.restUrl +
"/v2.0/me/messages('" +
item_rest_id +
"')";
rest_url += "?
$expand=SingleValueExtendedProperties($filter=PropertyId eq 'String
{00020329-0000-0000-C000-000000000046} Name cecp-<app-guid>')";
1. Check for existing properties on initializing your add-in, and keep them or clear
them as needed.
2. When setting custom properties, include an additional property to indicate
whether the custom properties were added in read mode. This will help you
differentiate if the property was created in compose mode or inherited from the
parent.
3. To check if the user is forwarding or replying to a message, you can use
item.getComposeTypeAsync (available from requirement set 1.10).
See also
MAPI Property Overview
Outlook Properties Overview
Call Outlook REST APIs from an Outlook add-in
Call web services from an Outlook add-in
Properties and extended properties in EWS in Exchange
Property sets and response shapes in EWS in Exchange
Get and set internet headers on a message in an Outlook add-in
Create Outlook add-ins for read forms
Article • 04/11/2023
Read add-ins are Outlook add-ins that are activated in the Reading Pane or read
inspector in Outlook. Unlike compose add-ins (Outlook add-ins that are activated when
a user is creating a message or appointment), read add-ins are available when users:
7 Note
Outlook doesn't activate add-ins in read form for certain types of messages,
including items that are attachments to another message, items in the
Outlook Drafts folder, or items that are encrypted or protected in other ways.
In each of these read scenarios, Outlook activates add-ins when their activation
conditions are fulfilled, and users can choose and open activated add-ins in the add-in
bar in the Reading Pane or read inspector. The following figure shows the Bing Maps
add-in activated and opened as the user is reading a message that contains a
geographic address.
The add-in pane showing the Bing Maps add-in in action for the selected Outlook
message that contains an address
Types of add-ins available in read mode
Read add-ins can be any combination of the following types.
Add-in commands
Contextual Outlook add-ins
See also
Write your first Outlook add-in
Use regular expression activation rules
to show an Outlook add-in
Article • 05/20/2023
You can specify regular expression rules to have a contextual add-in activated when a
match is found in specific fields of the message. Contextual add-ins activate only in read
mode. Outlook doesn't activate contextual add-ins when the user is composing an item.
There are also other scenarios where Outlook doesn't activate add-ins, for example,
digitally signed items. For more information, see Activation rules for Outlook add-ins.
7 Note
Contextual Outlook add-ins aren't supported when the add-in uses a Unified
manifest for Microsoft 365 (preview).
Outlook evaluates regular expressions based on the rules for the JavaScript interpreter
used by the browser or webview control on the client computer. For brevity hereafter,
this article uses "browser" to refer to "browser or webview control". Outlook supports
the same list of special characters that all XML processors also support. The following
table lists these special characters. You can use these characters in a regular expression
by specifying the escape sequence of the corresponding character, as described in the
following table.
ItemHasRegularExpressionMatch rule
An ItemHasRegularExpressionMatch rule is useful in controlling activation of an add-in
based on specific values of a supported property. The ItemHasRegularExpressionMatch
rule has the following attributes.
Attribute Description
name
RegExName Specifies the name of the regular expression so that you can refer to the
expression in the code for your add-in.
RegExValue Specifies the regular expression that will be evaluated to determine whether the
add-in should be shown.
PropertyName Specifies the name of the property that the regular expression will be evaluated
against. The allowed values are BodyAsHTML , BodyAsPlaintext , SenderSMTPAddress ,
and Subject .
If you specify BodyAsHTML , Outlook only applies the regular expression if the item
body is HTML. Otherwise, Outlook returns no matches for that regular expression.
Important: If you need to specify the Highlight attribute for the <Rule> element,
you must set the PropertyName attribute to BodyAsPlaintext .
IgnoreCase Specifies whether to ignore case when matching the regular expression specified
by RegExName .
Highlight Specifies how the client should highlight matching text. This element can only be
applied to Rule elements within ExtensionPoint elements. Can be one of the
following: all or none . If not specified, the default value is all .
Important: To specify the Highlight attribute in the <Rule> element, you must
set the PropertyName attribute to BodyAsPlaintext .
The plain text body returned on one browser can be different in subtle ways on
another. If you use an ItemHasRegularExpressionMatch rule with BodyAsPlaintext
as the PropertyName attribute, test your regular expression on all the browsers that
your add-in supports.
Because different browsers use different ways to obtain the text body of a selected
item, you should make sure that your regular expression supports the subtle
differences that can be returned as part of the body text. For example, some
browsers such as Internet Explorer 9 uses the innerText property of the DOM, and
others such as Firefox uses the .textContent() method to obtain the text body of
an item. Also, different browsers may return line breaks differently: a line break is
\r\n on Internet Explorer, and \n on Firefox and Chrome. For more information,
se W3C DOM Compatibility - HTML .
The HTML body of an item is slightly different between an Outlook rich client, and
Outlook on the web or Outlook on mobile devices. Define your regular expressions
carefully.
Examples
The following ItemHasRegularExpressionMatch rule activates the add-in whenever the
sender's SMTP email address matches @contoso , regardless of uppercase or lowercase
characters.
XML
<Rule xsi:type="ItemHasRegularExpressionMatch"
RegExName="addressMatches"
RegExValue="@[cC][oO][nN][tT][oO][sS][oO]"
PropertyName="SenderSMTPAddress"
/>
The following is another way to specify the same regular expression using the
IgnoreCase attribute.
XML
<Rule xsi:type="ItemHasRegularExpressionMatch"
RegExName="addressMatches"
RegExValue="@contoso"
PropertyName="SenderSMTPAddress"
IgnoreCase="true"
/>
XML
<Rule xsi:type="ItemHasRegularExpressionMatch"
PropertyName="BodyAsPlaintext"
RegExName="TickerSymbols"
RegExValue="\b(NYSE|NASDAQ|AMEX):\s*[A-Za-z]+\b"/>
ItemHasKnownEntity rule
An ItemHasKnownEntity rule activates an add-in based on the existence of an entity in
the subject or body of the selected item. The EntityType type defines the supported
entities. Applying a regular expression on an ItemHasKnownEntity rule provides the
convenience where activation is based on a subset of values for an entity (for example, a
specific set of URLs, or telephone numbers with a certain area code).
7 Note
Outlook can only extract entity strings in English regardless of the default locale
specified in the manifest. Only messages support the MeetingSuggestion entity
type; appointments don't support this. You can't extract entities from items in the
Sent Items folder, nor can you use an ItemHasKnownEntity rule to activate an add-
in for items in the Sent Items folder.
The ItemHasKnownEntity rule supports the attributes in the following table. Note that
while specifying a regular expression is optional in an ItemHasKnownEntity rule, if you
choose to use a regular expression as an entity filter, you must specify both the
RegExFilter and FilterName attributes.
Attribute Description
name
EntityType Specifies the type of entity that must be found for the rule to evaluate to true . Use
multiple rules to specify multiple types of entities.
Attribute Description
name
RegExFilter Specifies a regular expression that further filters instances of the entity specified by
EntityType .
FilterName Specifies the name of the regular expression specified by RegExFilter , so that it is
subsequently possible to refer to it by code.
IgnoreCase Specifies whether to ignore case when matching the regular expression specified
by RegExFilter .
Examples
The following ItemHasKnownEntity rule activates the add-in whenever there is a URL in
the subject or body of the current item, and the URL contains the string youtube ,
regardless of the case of the string.
XML
<Rule xsi:type="ItemHasKnownEntity"
EntityType="Url"
RegExFilter="youtube"
FilterName="youtube"
IgnoreCase="true"/>
getRegExMatches returns matches in the current item for all regular expressions
specified in ItemHasRegularExpressionMatch and ItemHasKnownEntity rules of the
add-in.
7 Note
Outlook doesn't return matches in any particular order in the array. Also, you
shouldn't assume that matches are returned in the same order in this array even
when you run the same add-in on each of these clients on the same item in the
same mailbox.
Examples
The following is an example of a rule collection that contains an
ItemHasRegularExpressionMatch rule with a regular expression named videoURL .
XML
The following example uses getRegExMatches of the current item to set a variable
videos to the results of the preceding ItemHasRegularExpressionMatch rule.
JavaScript
Multiple matches are stored as array elements in that object. The following code
example shows how to iterate over the matches for a regular expression named reg1 to
build a string to display as HTML.
JavaScript
function initDialer()
{
let myEntities;
let myString;
let myCell;
myEntities = Office.context.mailbox.item.getRegExMatches();
myString = "";
myCell = document.getElementById('dialerholder');
// Loop over the myEntities collection.
for (let i in myEntities.reg1) {
myString += "<p><a href='callto:tel:" + myEntities.reg1[i] + "'>" +
myEntities.reg1[i] + "</a></p>";
}
myCell.innerHTML = myString;
}
activates the add-in if it detects that the currently selected item contains a meeting
suggestion, and the subject or body contains the term WonderCamp .
XML
<Rule xsi:type="ItemHasKnownEntity"
EntityType="MeetingSuggestion"
RegExFilter="WonderCamp"
FilterName="CampSuggestion"
IgnoreCase="false"/>
The following code example uses getFilteredEntitiesByName on the current item to set
a variable suggestions to an array of detected meeting suggestions for the preceding
ItemHasKnownEntity rule.
JavaScript
const suggestions =
Office.context.mailbox.item.getFilteredEntitiesByName("CampSuggestion");
See also
Outlook add-in: Contoso Order Number - A sample contextual add-in that
activates based on a regular expression match.
Create Outlook add-ins for read forms
Activation rules for Outlook add-ins
Limits for activation and JavaScript API for Outlook add-ins
Match strings in an Outlook item as well-known entities
Best practices for regular expressions in the .NET framework
Match strings in an Outlook item as
well-known entities
Article • 03/21/2023
Before sending a message or meeting request item, Exchange Server parses the
contents of the item, identifies and stamps certain strings in the subject and body that
resemble entities well-known to Exchange, for example, email addresses, phone
numbers, and URLs. Messages and meeting requests are delivered by Exchange Server
in an Outlook Inbox with well-known entities stamped.
Using the Office JavaScript API, you can get these strings that match specific well-known
entities for further processing. You can also specify a well-known entity in a rule in the
add-in manifest so that Outlook can activate your add-in when the user is viewing an
item that contains matches for that entity. You can then extract and take action on
matches for the entity.
7 Note
Outlook Add-in features that depend on activation rules aren't supported when the
add-in uses a Unified manifest for Microsoft 365 (preview).
Being able to identify or extract such instances from a selected message or appointment
is convenient. For example, you can build a reverse phone look-up service as an Outlook
add-in. The add-in can extract strings in the item subject or body that resemble a phone
number, do a reverse lookup, and display the registered owner of each phone number.
This topic introduces these well-known entities, shows examples of activation rules
based on well-known entities, and how to extract entity matches independently of
having used entities in activation rules.
The following table lists the entities that Exchange Server and Outlook support and
recognize (hence the name "well-known entities"), and the object type of an instance of
each entity. The natural language recognition of a string as one of these entities is
based on a learning model that has been trained on a large amount of data. Therefore,
the recognition is non-deterministic. See Tips for using well-known entities for more
information about conditions for recognition.
Address United States street addresses; for example: 1234 JavaScript String
Main Street, Redmond, WA 07722. Generally, for an object
address to be recognized, it should follow the
structure of a United States postal address, with
most of the elements of a street number, street
name, city, state, and zip code present. The address
can be specified in one or multiple lines.
Url A web address that explicitly specifies the network JavaScript String
location and identifier for a web resource. Exchange object
Server does not require the access protocol in the
web address, and does not recognize URLs that are
embedded in link text as instances of the Url entity.
Exchange Server can match the following examples:
www.youtube.com/user/officevideos
https://www.youtube.com/user/officevideos
The following figure describes how Exchange Server and Outlook support well-known
entities for add-ins, and what add-ins can do with well-known entities. See Retrieving
entities in your add-in and Activating an add-in based on the existence of an entity for
more details on how to use these entities.
Specifying the default restricted permission allows your add-in to extract the Address ,
MeetingSuggestion , or TaskSuggestion entity. To extract any of the other entities, specify
The following example requests the read item permission in the manifest.
XML
<Permissions>ReadItem</Permissions>
To learn more about Outlook add-in permissions, see Understanding Outlook add-in
permissions.
The getEntities method returns an array of Entities objects that contains all the well-
known entities in the item.
After calling getEntities , you can then use the corresponding property of the Entities
object to obtain an array of instances of a type of entity. Depending on the type of
entity, the instances in the array can be just strings, or can map to specific objects.
As an example seen in the earlier figure, to get addresses in the item, access the array
returned by getEntities().addresses[] . The Entities.addresses property returns an
array of strings that Outlook recognizes as postal addresses. Similarly, the
Entities.contacts property returns an array of Contact objects that Outlook recognizes
as contact information. Tables 1 lists the object type of an instance of each supported
entity.
The following example shows how to retrieve any addresses found in a message.
JavaScript
Similar to other activation rules, you can specify multiple rules to form a rule collection
for your add-in. The following example applies an "AND" operation on 2 rules: an
ItemIs rule and an ItemHasKnownEntity rule. This rule collection activates the add-in
whenever the current item is a message and Outlook recognizes an address in the
subject or body of that item.
XML
The following example uses getEntitiesByType of the current item to set a variable
addresses to the results of the preceding rule collection.
JavaScript
const addresses =
Office.context.mailbox.item.getEntitiesByType(Office.MailboxEnums.EntityType
.Address);
The following ItemHasKnownEntity rule example activates the add-in whenever there is a
URL in the subject or body of the current item, and the URL contains the string
"youtube", regardless of the case of the string.
XML
<Rule xsi:type="ItemHasKnownEntity"
EntityType="Url"
RegExFilter="youtube"
FilterName="youtube"
IgnoreCase="true"/>
JavaScript
const videos =
Office.context.mailbox.item.getFilteredEntitiesByName(youtube);
You can extract strings that are well-known entities only if the strings are in
English.
You can extract well-known entities from the first 2,000 characters in the item
body, but not beyond that limit. This size limit helps balance the need for
functionality and performance, so that Exchange Server and Outlook are not
bogged down by parsing and identifying instances of well-known entities in large
messages and appointments. Note that this limit is independent of whether the
add-in specifies an ItemHasKnownEntity rule. If the add-in does use such a rule,
note also the rule processing limit in item 2 below for the Outlook rich clients.
You can extract entities from appointments that are meetings organized by
someone other than the mailbox owner. You cannot extract entities from calendar
items that are not meetings, or meetings organized by the mailbox owner.
You can extract entities of the MeetingSuggestion type from only messages but not
appointments.
You can extract URLs that exist explicitly in the item body, but not URLs that are
embedded in hyperlinked text in HTML item body. Consider using an
ItemHasRegularExpressionMatch rule instead to get both explicit and embedded
You cannot extract entities from items in the Sent Items folder.
In addition, the following applies if you use an ItemHasKnownEntity rule, and may affect
the scenarios where you'd otherwise expect your add-in to be activated.
When using the ItemHasKnownEntity rule, expect Outlook to match entity strings in
only English regardless of the default locale specified in the manifest.
When your add-in is running on an Outlook rich client, expect Outlook to apply
the ItemHasKnownEntity rule to the first megabyte of the item body and not to the
rest of the body over that limit.
You cannot use an ItemHasKnownEntity rule to activate an add-in for items in the
Sent Items folder.
See also
Create Outlook add-ins for read forms
Extract entity strings from an Outlook item
Activation rules for Outlook add-ins
Use regular expression activation rules to show an Outlook add-in
Understanding Outlook add-in permissions
Extract entity strings from an Outlook
item
Article • 03/21/2023
This article describes how to create a Display entities Outlook add-in that extracts string
instances of supported well-known entities in the subject and body of the selected
Outlook item. This item can be an appointment, email message, or meeting request,
response, or cancellation.
7 Note
The Outlook Add-in feature described in this article uses activation rules, which
aren't supported in add-ins that use a Unified manifest for Microsoft 365
(preview).
Address: A United States postal address, that has at least a subset of the elements
of a street number, street name, city, state, and zip code.
URL
Most of these entities rely on natural language recognition, which is based on machine
learning of large amounts of data. This recognition is nondeterministic and sometimes
depends on the context in the Outlook item.
Outlook activates the entities add-in whenever the user selects an appointment, email
message, or meeting request, response, or cancellation for viewing. During initialization,
the sample entities add-in reads all instances of the supported entities from the current
item.
The add-in provides buttons for the user to choose a type of entity. When the user
selects an entity, the add-in displays instances of the selected entity in the add-in pane.
The following sections list the XML manifest, and HTML and JavaScript files of the
entities add-in, and highlight the code that supports the respective entity extraction.
XML manifest
The entities add-in has two activation rules joined by a logical OR operation.
XML
These rules specify that Outlook should activate this add-in when the currently selected
item in the Reading Pane or read inspector is an appointment or message (including an
email message, or meeting request, response, or cancellation).
The following is the manifest of the entities add-in. It uses version 1.1 of the schema for
Office Add-ins manifests.
XML
HTML implementation
The HTML file of the entities add-in specifies buttons for the user to select each type of
entity, and another button to clear displayed instances of an entity. It includes a
JavaScript file, default_entities.js, which is described in the next section under JavaScript
implementation. The JavaScript file includes the event handlers for each of the buttons.
Note that all Outlook add-ins must include office.js. The HTML file that follows includes
version 1.1 of office.js on the content delivery network (CDN).
HTML
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge" >
<title>standard_item_properties</title>
<link rel="stylesheet" type="text/css" media="all"
href="default_entities.css" />
<script type="text/javascript" src="MicrosoftAjax.js"></script>
<!-- Use the CDN reference to Office.js. -->
<script src="https://appsforoffice.microsoft.com/lib/1/hosted/Office.js"
type="text/javascript"></script>
<script type="text/javascript" src="default_entities.js"></script>
</head>
<body>
<div id="container">
<div id="button">
<input type="button" value="clear"
onclick="myClearEntitiesBox();">
<input type="button" value="Get Addresses"
onclick="myGetAddresses();">
<input type="button" value="Get Contact Information"
onclick="myGetContacts();">
<input type="button" value="Get Email Addresses"
onclick="myGetEmailAddresses();">
<input type="button" value="Get Meeting Suggestions"
onclick="myGetMeetingSuggestions();">
<input type="button" value="Get Phone Numbers"
onclick="myGetPhoneNumbers();">
<input type="button" value="Get Task Suggestions"
onclick="myGetTaskSuggestions();">
<input type="button" value="Get URLs"
onclick="myGetUrls();">
</div>
<div id="entities_box"></div>
</div>
</body>
</html>
Style sheet
The entities add-in uses an optional CSS file, default_entities.css, to specify the layout of
the output. The following is a listing of the CSS file.
CSS
{
color: #FFFFFF;
margin: 0px;
padding: 0px;
font-family: Arial, Sans-serif;
}
html
{
scrollbar-base-color: #FFFFFF;
scrollbar-arrow-color: #ABABAB;
scrollbar-lightshadow-color: #ABABAB;
scrollbar-highlight-color: #ABABAB;
scrollbar-darkshadow-color: #FFFFFF;
scrollbar-track-color: #FFFFFF;
}
body
{
background: #4E9258;
}
input
{
color: #000000;
padding: 5px;
}
span
{
color: #FFFF00;
}
div#container
{
height: 100%;
padding: 2px;
overflow: auto;
}
div#container td
{
border-bottom: 1px solid #CCCCCC;
}
td.property-name
{
padding: 0px 5px 0px 0px;
border-right: 1px solid #CCCCCC;
}
div#meeting_suggestions
{
border-top: 1px solid #CCCCCC;
}
JavaScript implementation
The remaining sections describe how this sample (default_entities.js file) extracts well-
known entities from the subject and body of the message or appointment that the user
is viewing.
JavaScript
// Global variables
let _Item;
let _MyEntities;
// Checks for the DOM to load using the jQuery ready method.
$(document).ready(function () {
// After the DOM is loaded, app-specific code can run.
});
}
Extracting addresses
When the user clicks the Get Addresses button, the myGetAddresses event handler
obtains an array of addresses from the addresses property of the _MyEntities object, if
any address was extracted. Each extracted address is stored as a string in the array.
myGetAddresses forms a local HTML string in htmlText to display the list of extracted
JavaScript
document.getElementById("entities_box").innerHTML = htmlText;
}
The string representing the company name associated with the contact from the
Contact.businessName property.
The array of telephone numbers associated with the contact from the
Contact.phoneNumbers property. Each telephone number is represented by a
PhoneNumber object.
For each PhoneNumber member in the telephone numbers array, the string
representing the telephone number from the PhoneNumber.phoneString property.
The array of URLs associated with the contact from the Contact.urls property. Each
URL is represented as a string in an array member.
The array of email addresses associated with the contact from the
Contact.emailAddresses property. Each email address is represented as a string in
an array member.
The array of postal addresses associated with the contact from the
Contact.addresses property. Each postal address is represented as a string in an
array member.
myGetContacts forms a local HTML string in htmlText to display the data for each
JavaScript
htmlText += "<hr/>";
}
document.getElementById("entities_box").innerHTML = htmlText;
}
JavaScript
// Gets instances of the EmailAddress entity on the item.
function myGetEmailAddresses() {
let htmlText = "";
document.getElementById("entities_box").innerHTML = htmlText;
}
7 Note
Only messages but not appointments support the MeetingSuggestion entity type.
For each attendee, the SMTP address from the EmailUser.emailAddress property.
The string representing the location of the meeting suggestion from the
MeetingSuggestion.location property.
The string representing the subject of the meeting suggestion from the
MeetingSuggestion.subject property.
The string representing the start time of the meeting suggestion from the
MeetingSuggestion.start property.
The string representing the end time of the meeting suggestion from the
MeetingSuggestion.end property.
myGetMeetingSuggestions forms a local HTML string in htmlText to display the data for
each of the meeting suggestions. The following is the related JavaScript code.
JavaScript
htmlText += "<hr/>";
}
document.getElementById("entities_box").innerHTML = htmlText;
}
PhoneNumber object in the array. myGetPhoneNumbers obtains further data about each
phone number:
The string representing the kind of phone number, for example, home phone
number, from the PhoneNumber.type property.
The string that was originally identified as the phone number from the
PhoneNumber.originalPhoneString property.
myGetPhoneNumbers forms a local HTML string in htmlText to display the data for each of
the phone numbers. The following is the related JavaScript code.
JavaScript
document.getElementById("entities_box").innerHTML = htmlText;
}
The string that was originally identified a task suggestion from the
TaskSuggestion.taskString property.
For each assignee, the SMTP address from the EmailUser.emailAddress property.
myGetTaskSuggestions forms a local HTML string in htmlText to display the data for
each task suggestion. The following is the related JavaScript code.
JavaScript
htmlText += "<hr/>";
}
document.getElementById("entities_box").innerHTML = htmlText;
}
Extracting URLs
When the user clicks the Get URLs button, the myGetUrls event handler obtains an array
of URLs from the urls property of the _MyEntities object, if any was extracted. Each
extracted URL is stored as a string in the array. myGetUrls forms a local HTML string in
htmlText to display the list of extracted URLs.
JavaScript
document.getElementById("entities_box").innerHTML = htmlText;
}
JavaScript
JavaScript listing
The following is the complete listing of the JavaScript implementation.
JavaScript
// Global variables
let _Item;
let _MyEntities;
// Checks for the DOM to load using the jQuery ready method.
$(document).ready(function () {
// After the DOM is loaded, app-specific code can run.
});
}
document.getElementById("entities_box").innerHTML = htmlText;
}
document.getElementById("entities_box").innerHTML = htmlText;
}
htmlText += "<hr/>";
}
document.getElementById("entities_box").innerHTML = htmlText;
}
document.getElementById("entities_box").innerHTML = htmlText;
}
htmlText += "<hr/>";
}
document.getElementById("entities_box").innerHTML = htmlText;
}
document.getElementById("entities_box").innerHTML = htmlText;
}
See also
Create Outlook add-ins for read forms
Match strings in an Outlook item as well-known entities
item.getEntities method
Get attachments of an Outlook item
from the server
Article • 08/07/2023
You can get the attachments of an Outlook item in a couple of ways, but which option
you use depends on your scenario.
Your add-in can use the attachments API to send information about the
attachments to the remote service. The service can then contact the Exchange
server directly to retrieve the attachments.
This API may be handy if Microsoft Graph or EWS is unavailable (for example, due
to the admin configuration of your Exchange server), or your add-in wants to use
the base64 content directly in HTML or JavaScript. Also, the
getAttachmentContentAsync API is available in compose scenarios where the
attachment may not have synced to Exchange yet; see Manage an item's
attachments in a compose form in Outlook to learn more.
This article elaborates on the first option. To send attachment information to the remote
service, use the following properties and method.
1. Show the add-in when the user is viewing a message or appointment that contains
an attachment.
3. Send the callback token and attachment information to the remote service.
Each of these steps is covered in detail in the following sections using code from the
Outlook-Add-in-JavaScript-GetAttachments sample.
7 Note
The code in these examples has been shortened to emphasize the attachment
information. The sample contains additional code for authenticating the add-in
with the remote server and managing the state of the request.
JavaScript
function getAttachmentToken() {
if (serviceRequest.attachmentToken == "") {
Office.context.mailbox.getCallbackTokenAsync(attachmentTokenCallback);
}
}
function attachmentTokenCallback(asyncResult) {
if (asyncResult.status === Office.AsyncResultStatus.Succeeded) {
// Cache the result from the server.
serviceRequest.attachmentToken = asyncResult.value;
serviceRequest.state = 3;
testAttachments();
} else {
showToast("Error", "Couldn't get callback token: " +
asyncResult.error.message);
}
}
JavaScript
JavaScript
function makeServiceRequest() {
// Format the attachment details for sending.
for (let i = 0; i < mailbox.item.attachments.length; i++) {
serviceRequest.attachments[i] =
JSON.parse(JSON.stringify(mailbox.item.attachments[i]));
}
$.ajax({
url: '../../api/Default',
type: 'POST',
data: JSON.stringify(serviceRequest),
contentType: 'application/json;charset=utf-8'
}).done(function (response) {
if (!response.isError) {
const names = "<h2>Attachments processed using " +
serviceRequest.service +
": " +
response.attachmentsProcessed +
"</h2>";
for (let i = 0; i < response.attachmentNames.length; i++) {
names += response.attachmentNames[i] + "<br />";
}
document.getElementById("names").innerHTML = names;
} else {
app.showNotification("Runtime error", response.message);
}
}).fail(function (status) {
}).always(function () {
$('.disable-while-sending').prop('disabled', false);
})
}
C#
namespace AttachmentsSample
{
public class AttachmentSampleServiceRequest
{
public string attachmentToken { get; set; }
public string ewsUrl { get; set; }
public string service { get; set; }
public AttachmentDetails [] attachments { get; set; }
}
C#
private AttachmentSampleServiceResponse
GetAtttachmentsFromExchangeServerUsingEWSManagedApi(AttachmentSampleServiceR
equest request)
{
var attachmentsProcessedCount = 0;
var attachmentNames = new List<string>();
// Create an ExchangeService object, set the credentials and the EWS URL.
ExchangeService service = new ExchangeService();
service.Credentials = new OAuthCredentials(request.attachmentToken);
service.Url = new Uri(request.ewsUrl);
if (getAttachmentsResponse.OverallResult == ServiceResult.Success)
{
foreach (var attachmentResponse in getAttachmentsResponse)
{
attachmentNames.Add(attachmentResponse.Attachment.Name);
if (attachmentResponse.Attachment is ItemAttachment)
{
ItemAttachment itemAttachment = attachmentResponse.Attachment as
ItemAttachment;
Stream s = new
MemoryStream(itemAttachment.Item.MimeContent.Content);
// Process the contents of the attachment here.
}
attachmentsProcessedCount++;
}
}
return response;
}
C#
Finally, the following method does the work of using an EWS GetAttachment request to
get the attachments from the Exchange server. This implementation makes an individual
request for each attachment, and returns the count of attachments processed. Each
response is processed in a separate ProcessXmlResponse method, defined next.
C#
private AttachmentSampleServiceResponse
GetAttachmentsFromExchangeServerUsingEWS(AttachmentSampleServiceRequest
request)
{
var attachmentsProcessedCount = 0;
var attachmentNames = new List<string>();
// Make the request to the Exchange server and get the response.
HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
}
// If the response is not OK, return an error message for the
// attachment.
else
{
var errorString = string.Format("Attachment \"{0}\" could not be
processed. " +
"Error message: {1}.", attachment.name,
webResponse.StatusDescription);
attachmentNames.Add(errorString);
}
attachmentsProcessedCount++;
}
return response;
}
C#
// This method processes the response from the Exchange server.
// In your application the bulk of the processing occurs here.
private string ProcessXmlResponse(XElement responseEnvelope)
{
// First, check the response for web service errors.
var errorCodes = from errorCode in responseEnvelope.Descendants
("
{http://schemas.microsoft.com/exchange/services/2006/messages}ResponseCode")
select errorCode;
// Return the first error code found.
foreach (var errorCode in errorCodes)
{
if (errorCode.Value != "NoError")
{
return string.Format("Could not process result. Error: {0}",
errorCode.Value);
}
}
return string.Empty;
}
See also
Create Outlook add-ins for read forms
Explore the EWS Managed API, EWS, and web services in Exchange
Get started with EWS Managed API client applications
Outlook Add-in SSO
Create Outlook add-ins for compose
forms
Article • 05/20/2023
You can create compose add-ins, which are Outlook add-ins activated in compose
forms. In contrast with read add-ins (Outlook add-ins that are activated in read mode
when a user is viewing a message or appointment), compose add-ins are available in the
following user scenarios.
In each of these scenarios, any add-in command buttons defined by the add-in are
shown in compose form.
Add-ins developed for servers or clients that don't support add-in commands use
activation rules in a Rule element contained in the OfficeApp element. Unless the
add-in is being specifically developed for older clients and servers, new add-ins
should use add-in commands.
Add-ins that use activation rules aren't supported in an add-in that uses a Unified
manifest for Microsoft 365 (preview).
See also
Get Started with Outlook add-ins for Office
Manage an item's attachments in a
compose form in Outlook
Article • 03/28/2023
The Office JavaScript API provides several APIs you can use to manage an item's
attachments when the user is composing.
These are asynchronous methods, which means execution can go on without waiting for
the action to complete. Depending on the original location and size of the attachment
being added, the asynchronous call may take a while to complete.
If there are tasks that depend on the action to complete, you should carry out those
tasks in a callback function. This callback function is optional and is invoked when the
attachment upload has completed. The callback function takes an AsyncResult object as
an output parameter that provides any status, error, and returned value from adding the
attachment. If the callback requires any extra parameters, you can specify them in the
optional options.asyncContext parameter. options.asyncContext can be of any type
that your callback function expects.
For example, you can define options.asyncContext as a JSON object that contains one
or more key-value pairs. You can find more examples about passing optional parameters
to asynchronous methods in the Office Add-ins platform in Asynchronous programming
in Office Add-ins. The following example shows how to use the asyncContext parameter
to pass two arguments to a callback function.
JavaScript
Office.context.mailbox.item.addFileAttachmentAsync('https://contoso.com/rtm/
icon.png', 'icon.png', options, callback);
You can check for success or error of an asynchronous method call in the callback
function using the status and error properties of the AsyncResult object. If the
attaching completes successfully, you can use the AsyncResult.value property to get
the attachment ID. The attachment ID is an integer which you can subsequently use to
remove the attachment.
7 Note
The attachment ID is valid only within the same session and isn't guaranteed to
map to the same attachment across sessions. Examples of when a session is over
include when the user closes the add-in, or if the user starts composing in an inline
form and subsequently pops out the inline form to continue in a separate window.
Tip
There are limits to the files or Outlook items you can attach to a mail item, such as
the number of attachments and their size. For further guidance, see Limits for
JavaScript API.
Attach a file
You can attach a file to a message or appointment in a compose form by using the
addFileAttachmentAsync method and specifying the URI of the file. You can also use the
addFileAttachmentFromBase64Async method, specifying the Base64-encoded string as
input. If the file is protected, you can include an appropriate identity or authentication
token as a URI query string parameter. Exchange will make a call to the URI to get the
attachment, and the web service which protects the file will need to use the token as a
means of authentication.
The following JavaScript example is a compose add-in that attaches a file, picture.png,
from a web server to the message or appointment being composed. The callback
function takes asyncResult as a parameter, checks for the result status, and gets the
attachment ID if the method succeeds.
JavaScript
Office.initialize = function () {
// Checks for the DOM to load using the jQuery ready method.
$(document).ready(function () {
// After the DOM is loaded, app-specific code can run.
// Add the specified file attachment to the item
// being composed.
// When the attachment finishes uploading, the
// callback function is invoked and gets the attachment ID.
// You can optionally pass any object that you would
// access in the callback function as an argument to
// the asyncContext parameter.
Office.context.mailbox.item.addFileAttachmentAsync(
`https://webserver/picture.png`,
'picture.png',
{ asyncContext: null },
function (asyncResult) {
if (asyncResult.status === Office.AsyncResultStatus.Failed){
write(asyncResult.error.message);
} else {
// Get the ID of the attached file.
const attachmentID = asyncResult.value;
write('ID of added attachment: ' + attachmentID);
}
});
});
}
JavaScript
"iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAMAAADVRocKAAAAAXNSR0IArs4c6QAAAARnQU1BAAC
xjwv8YQUAAAAnUExURQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAN0S+bU
AAAAMdFJOUwAQIDBAUI+fr7/P7yEupu8AAAAJcEhZcwAADsMAAA7DAcdvqGQAAAF8SURBVGhD7df
LdoMwDEVR6Cspzf9/b20QYOthS5Zn0Z2kVdY6O2WULrFYLBaLxd5ur4mDZD14b8ogWS/dtxV+dmx
9ysA2QUj9TQRWv5D7HyKwuIW9n0vc8tkpHP0W4BOg3wQ8wtlvA+PC1e8Ao8Ld7wFjQtHvAiNC2e8
DdqHqKwCrUPc1gE1AfRVgEXBfB+gF0lcCWoH2tYBOYPpqQCNwfT3QF9i+AegJfN8CtAWhbwJagtS
3AbIg9o2AJMh9M5C+SVGBvx6zAfmT0r+Bv8JMwP4kyFPir+cswF5KL3WLv14zAFBCLf56Tw9cpar
FX4upgaJUtPhrOS1QlY5W+vWTXrGgBFB/b72ev3/0igUdQPppP/nfowfKUUEFcP207y/yxKmgAYQ
+PywoAFOfCH3A2MdCFzD3kdADBvq10AGG+pXQBgb7pdAEhvuF0AIc/VtoAK7+JciAs38KIuDugyA
C/v4hiMCE/i7IwLRBsh68N2WQjMVisVgs9i5bln8LGScNcCrONQAAAABJRU5ErkJggg==";
The following JavaScript function, addItemAttachment , extends the first example above,
and adds an item as an attachment to the email or appointment that is being
composed. The function takes as an argument the EWS ID of the item that is to be
attached. If attaching succeeds, it gets the attachment ID for further processing,
including removing that attachment in the same session.
JavaScript
7 Note
Get attachments
APIs to get attachments in compose mode are available from requirement set 1.8.
getAttachmentsAsync
getAttachmentContentAsync
You can use the getAttachmentsAsync method to get the attachments of the message
or appointment being composed.
You should provide a callback function to check for the status and any error by using the
AsyncResult output parameter object. You can also pass any additional parameters to
JavaScript
function callback(result) {
if (result.value.length > 0) {
for (let i = 0 ; i < result.value.length ; i++) {
result.asyncContext.currentItem.getAttachmentContentAsync(result.value[i].id
, handleAttachmentsCallback);
}
}
}
function handleAttachmentsCallback(result) {
// Parse string to be a url, an .eml file, a Base64-encoded string, or an
.icalendar file.
switch (result.value.format) {
case Office.MailboxEnums.AttachmentContentFormat.Base64:
// Handle file attachment.
break;
case Office.MailboxEnums.AttachmentContentFormat.Eml:
// Handle email item attachment.
break;
case Office.MailboxEnums.AttachmentContentFormat.ICalendar:
// Handle .icalender attachment.
break;
case Office.MailboxEnums.AttachmentContentFormat.Url:
// Handle cloud attachment.
break;
default:
// Handle attachment formats that are not supported.
}
}
Remove an attachment
You can remove a file or item attachment from a message or appointment item in a
compose form by specifying the corresponding attachment ID when using the
removeAttachmentAsync method.
) Important
If you're using requirement set 1.7 or earlier, you should only remove attachments
that the same add-in has added in the same session.
JavaScript
See also
Create Outlook add-ins for compose forms
Asynchronous programming in Office Add-ins
Limits for activation and JavaScript API for Outlook add-ins
Get and set item data in a compose
form in Outlook
Article • 10/04/2022
Learn how to get or set various properties of an item in an Outlook add-in in a compose
scenario, including its recipients, subject, body, and appointment location and time.
For most of these properties, because it's possible that an Outlook add-in and the user
can be modifying the same property in the user interface at the same time, the methods
to get and set them are asynchronous. Table 1 lists the item-level properties and
corresponding asynchronous methods to get and set them in a compose form. The
item.itemType and item.conversationId properties are exceptions because users cannot
modify them. You can programmatically get them the same way in a compose form as in
a read form, directly from the parent object.
Other than accessing item properties in the Office JavaScript API, you can access item-
level properties using Exchange Web Services (EWS). With the read/write mailbox
permission, you can use the mailbox.makeEwsRequestAsync method to access EWS
operations, GetItem and UpdateItem, to get and set more properties of an item or items
in the user's mailbox.
The makeEwsRequestAsync method is available in both compose and read forms. For
more information about the read/write mailbox permission, and accessing EWS through
the Office Add-ins platform, see Understanding Outlook add-in permissions and Call
web services from an Outlook add-in.
See also
Create Outlook add-ins for compose forms
Understanding Outlook add-in permissions
Call web services from an Outlook add-in
Get and set Outlook item data in read or compose forms
Get, set, or add recipients when
composing an appointment or message
in Outlook
Article • 08/15/2023
In a read form, you can access the property directly from the parent object, such as:
JavaScript
Office.context.mailbox.item.cc;
But in a compose form, because both the user and your add-in can be inserting or
changing a recipient at the same time, you must use the asynchronous method
getAsync to get these properties, as in the following example.
JavaScript
Office.context.mailbox.item.cc.getAsync(callback);
These properties are available for write access in only compose forms, and not read
forms.
As with most asynchronous methods in the JavaScript API for Office, getAsync ,
setAsync , and addAsync take optional input parameters. For more information on how
In the Office JavaScript API, because the properties that represent the recipients of an
appointment ( optionalAttendees and requiredAttendees ) are different from those of a
message (bcc, cc , and to ), you should first use the item.itemType property to identify
whether the item being composed is an appointment or message. In compose mode, all
these properties of appointments and messages are Recipients objects, so you can then
call the asynchronous method, Recipients.getAsync , to get the corresponding
recipients.
To use getAsync , provide a callback function to check for the status, results, and any
error returned by the asynchronous getAsync call. The callback function returns an
asyncResult output parameter. Use its status and error properties to check for the
status and any error messages of the asynchronous call, and its value property to get
the actual recipients. Recipients are represented as an array of EmailAddressDetails
objects. You can also provide additional information to the callback function using the
optional asyncContext parameter in the getAsync call.
Note that because the getAsync method is asynchronous, if there are subsequent
actions that depend on successfully getting the recipients, you should organize your
code to start such actions only in the corresponding callback function when the
asynchronous call has successfully completed.
) Important
The getAsync method only returns recipients resolved by the Outlook client. A
resolved recipient has the following characteristics.
If the recipient has a saved entry in the sender's address book, Outlook
resolves the email address to the recipient's saved display name.
A Teams meeting status icon appears before the recipient's name or email
address.
A semicolon appears after the recipient's name or email address.
The recipient's name or email address is underlined or enclosed in a box.
To resolve an email address once it's added to a mail item, the sender must use the
Tab key or select a suggested contact or email address from the auto-complete list.
In Outlook on the web and on Windows, if a user creates a new message by
selecting a contact's email address link from a contact or profile card, they must
first resolve the email address so that it can be included in the results of the
getAsync call.
JavaScript
let item;
// Gets the email addresses of all the recipients of the item being
composed.
function getAllRecipients() {
let toRecipients, ccRecipients, bccRecipients;
// Get the recipients from the To or Required field of the item being
composed.
toRecipients.getAsync((asyncResult) => {
if (asyncResult.status === Office.AsyncResultStatus.Failed) {
write(asyncResult.error.message);
return;
}
// Get the recipients from the Cc or Optional field of the item being
composed.
ccRecipients.getAsync((asyncResult) => {
if (asyncResult.status === Office.AsyncResultStatus.Failed) {
write(asyncResult.error.message);
return;
}
// Get the recipients from the Bcc field of the message being composed,
if applicable.
if (bccRecipients.length > 0) {
bccRecipients.getAsync((asyncResult) => {
if (asyncResult.status === Office.AsyncResultStatus.Failed) {
write(asyncResult.error.message);
return;
}
Set recipients
This section shows a code sample that sets the recipients of the appointment or
message that is being composed by the user. Setting recipients overwrites any existing
recipients. This example first verifies if the mail item is an appointment or message, so
that it can call the asynchronous method, Recipients.setAsync , on the appropriate
properties that represent recipients of the appointment or message.
When calling setAsync , provide an array as the input argument for the recipients
parameter, in one of the following formats.
You can optionally provide a callback function as an input argument to the setAsync
method, to make sure any code that depends on successfully setting the recipients
would execute only when that happens. If you implement a callback function, use the
status and error properties of the asyncResult output parameter to check the status
and any error messages of the asynchronous call. To provide additional information to
the callback function, use the optional asyncContext parameter in the setAsync call.
JavaScript
let item;
// Set the recipients in the Bcc field of the message being composed.
if (bccRecipients) {
bccRecipients.setAsync(
[{
"displayName": "Lewis Cate",
"emailAddress": "lewis@contoso.com"
},
{
"displayName": "Francisco Stitt",
"emailAddress": "francisco@contoso.com"
}],
(asyncResult) => {
if (asyncResult.status === Office.AsyncResultStatus.Failed)
{
console.log(asyncResult.error.message);
return;
}
Add recipients
If you don't want to overwrite any existing recipients in an appointment or message,
instead of using Recipients.setAsync , use the Recipients.addAsync asynchronous
method to append recipients. addAsync works similarly as setAsync in that it requires a
recipients input argument. You can optionally provide a callback function, and any
arguments for the callback using the asyncContext parameter. Then, check the status,
result, and any error of the asynchronous addAsync call using the asyncResult output
parameter of the callback function. The following example checks if the item being
composed is an appointment, then appends two required attendees to it.
JavaScript
let item;
See also
Get and set item data in a compose form in Outlook
Get and set Outlook item data in read or compose forms
Create Outlook add-ins for compose forms
Asynchronous programming in Office Add-ins
Get or set the subject when composing an appointment or message in Outlook
Insert data in the body when composing an appointment or message in Outlook
Get or set the location when composing an appointment in Outlook
Get or set the time when composing an appointment in Outlook
Insert data in the body when composing
an appointment or message in Outlook
Article • 08/15/2023
In Outlook, a user can create a message in text, HTML, or Rich Text Format (RTF), and
can create an appointment in HTML format. Before inserting data, you must first verify
the supported item format by calling getTypeAsync , as you may need to take additional
steps. The value that getTypeAsync returns depends on the original item format, as well
as the support of the device operating system and application to edit in HTML format.
Once you've verified the item format, set the coercionType parameter of prependAsync
or setSelectedDataAsync accordingly to insert the data, as shown in the following table.
If you don't specify an argument, prependAsync and setSelectedDataAsync assume the
data to insert is in text format.
7 Note
2
If your data to insert is HTML and getTypeAsync returns a text type for the current
mail item, you must reorganize your data as text and set coercionType to
Office.CoercionType.Text . If you simply insert the HTML data into a text-formatted
item, the application displays the HTML tags as text. If you attempt to insert the
HTML data and set coercionType to Office.CoercionType.Html , you'll get an error.
method, then extract the needed information from the asyncResult output parameter of
the callback. If the method succeeds, you can get the type of the item body from the
asyncResult.value property, which is either "text" or "html".
If the user hasn't placed the cursor in the item body, setSelectedDataAsync inserts the
data at the top of the body. If the user has selected text in the item body,
setSelectedDataAsync replaces the selected text with the data you specify. Note that
setSelectedDataAsync can fail if the user simultaneously changes the cursor position
while composing the item. The maximum number of characters you can insert at one
time is 1,000,000 characters.
JavaScript
let item;
/*
Run additional operations appropriate to your scenario
and
use the optionalVariable1 and optionalVariable2 values
as needed.
*/
});
}
else {
// Insert plain text into the body.
item.body.setSelectedDataAsync(
"Kindly note we now open 7 days a week.",
{ coercionType: Office.CoercionType.Text, asyncContext: {
optionalVariable1: 1, optionalVariable2: 2 } },
(asyncResult) => {
if (asyncResult.status ===
Office.AsyncResultStatus.Failed) {
console.log(asyncResult.error.message);
return;
}
/*
Run additional operations appropriate to your scenario
and
use the optionalVariable1 and optionalVariable2 values
as needed.
*/
});
}
});
}
Insert data at the beginning of the item body
Alternatively, you can use prependAsync to insert data at the beginning of the item body
and disregard the current cursor location. Other than the point of insertion,
prependAsync and setSelectedDataAsync behave in similar ways. You must first check the
type of the message body to avoid prepending HTML data to a message in text format.
Then, pass the data string to be prepended in either text or HTML format to
prependAsync . The maximum number of characters you can prepend at one time is
1,000,000 characters.
The following JavaScript code first calls getTypeAsync to verify the type of the item body.
Then, depending on the type, it inserts the data as HTML or text to the top of the body.
JavaScript
let item;
/*
Run additional operations appropriate to your scenario
and
use the optionalVariable1 and optionalVariable2 values
as needed.
*/
});
}
else {
// Prepend plain text to the body.
item.body.prependAsync(
'Greetings!',
{ coercionType: Office.CoercionType.Text, asyncContext: {
optionalVariable1: 1, optionalVariable2: 2 } },
(asyncResult) => {
if (asyncResult.status ===
Office.AsyncResultStatus.Failed) {
console.log(asyncResult.error.message);
return;
}
/*
Run additional operations appropriate to your scenario
and
use the optionalVariable1 and optionalVariable2 values
as needed.
*/
});
}
});
}
See also
Get and set item data in a compose form in Outlook
Get and set Outlook item data in read or compose forms
Create Outlook add-ins for compose forms
Asynchronous programming in Office Add-ins
Get, set, or add recipients when composing an appointment or message in
Outlook
Get or set the subject when composing an appointment or message in Outlook
Get or set the location when composing an appointment in Outlook
Get or set the time when composing an appointment in Outlook
Get or set the subject when composing
an appointment or message in Outlook
Article • 08/15/2023
The subject property is available for read access in both compose and read forms of
appointments and messages. In a read form, access the property directly from the
parent object, as in:
JavaScript
Office.context.mailbox.item.subject;
But in a compose form, because both the user and your add-in can be inserting or
changing the subject at the same time, you must use the getAsync method to get the
subject asynchronously.
JavaScript
Office.context.mailbox.item.subject.getAsync(callback);
The subject property is available for write access in only compose forms and not in
read forms.
Tip
To temporarily set the content displayed in the subject of a message in read mode,
use Office.context.mailbox.item.display.subject (preview).
As with most asynchronous methods in the Office JavaScript API, getAsync and
setAsync take optional input parameters. For more information on how to specify these
To use item.subject.getAsync , provide a callback function that checks for the status and
result of the asynchronous call. You can provide any necessary arguments to the
callback function through the optional asyncContext parameter. To obtain the status,
results, and any error from the callback function, use the asyncResult output parameter
of the callback. If the asynchronous call is successful, use the AsyncResult.value property
to get the subject as a plain text string.
JavaScript
let item;
JavaScript
let item;
item.subject.setAsync(
subject,
{ asyncContext: { optionalVariable1: 1, optionalVariable2: 2 } },
(asyncResult) => {
if (asyncResult.status === Office.AsyncResultStatus.Failed) {
write(asyncResult.error.message);
return;
}
/*
The subject was successfully set.
Run additional operations appropriate to your scenario and
use the optionalVariable1 and optionalVariable2 values as
needed.
*/
});
}
See also
Get and set item data in a compose form in Outlook
Get and set Outlook item data in read or compose forms
Create Outlook add-ins for compose forms
Asynchronous programming in Office Add-ins
Get, set, or add recipients when composing an appointment or message in
Outlook
Insert data in the body when composing an appointment or message in Outlook
Get or set the location when composing an appointment in Outlook
Get or set the time when composing an appointment in Outlook
Get or set the time when composing an
appointment in Outlook
Article • 08/15/2023
The start and end properties are available for appointments in both compose and read
forms. In a read form, you can access the properties directly from the parent object, as
in:
JavaScript
Office.context.mailbox.item.start;
Office.context.mailbox.item.end;
But in a compose form, because both the user and your add-in can be inserting or
changing the time at the same time, you must use the getAsync asynchronous method
to get the start or end time.
JavaScript
Office.context.mailbox.item.start.getAsync(callback);
Office.context.mailbox.item.end.getAsync(callback);
As with most asynchronous methods in the Office JavaScript API, getAsync and
setAsync take optional input parameters. For more information on how to specify these
JavaScript
let item;
7 Note
In Outlook on Windows, the setAsync method can't be used to change the start or
end time of a recurring appointment.
JavaScript
let item;
item.start.setAsync(
startDate,
{ asyncContext: { optionalVariable1: 1, optionalVariable2: 2 } },
(asyncResult) => {
if (asyncResult.status === Office.AsyncResultStatus.Failed) {
console.log(asyncResult.error.message);
return;
}
See also
Get and set item data in a compose form in Outlook
Get and set Outlook item data in read or compose forms
Create Outlook add-ins for compose forms
Asynchronous programming in Office Add-ins
Get, set, or add recipients when composing an appointment or message in
Outlook
Get or set the subject when composing an appointment or message in Outlook
Insert data in the body when composing an appointment or message in Outlook
Get or set the location when composing an appointment in Outlook
Get or set the location when composing
an appointment in Outlook
Article • 03/21/2023
The Office JavaScript API provides properties and methods to manage the location of an
appointment that the user is composing. Currently, there are two properties that
provide an appointment's location:
item.location: Basic API that allows you to get and set the location.
item.enhancedLocation: Enhanced API that allows you to get and set the location,
and includes specifying the location type. The type is LocationType.Custom if you
set the location using item.location .
The following table lists the location APIs and the modes (i.e., Compose or Read) where
they are available.
item.location Attendee/Read
item.location.getAsync Organizer/Compose
item.location.setAsync Organizer/Compose
item.enhancedLocation.getAsync Organizer/Compose,
Attendee/Read
item.enhancedLocation.addAsync Organizer/Compose
item.enhancedLocation.removeAsync Organizer/Compose
To use the methods that are available only to compose add-ins, configure the add-in
XML manifest to activate the add-in in Organizer/Compose mode. See Create Outlook
add-ins for compose forms for more details. Activation rules aren't supported in add-ins
that use a Unified manifest for Microsoft 365 (preview).
JavaScript
let item;
const locations = [
{
"id": "Contoso",
"type": Office.MailboxEnums.LocationType.Custom
}
];
Office.initialize = function () {
item = Office.context.mailbox.item;
// Check for the DOM to load using the jQuery ready method.
$(document).ready(function () {
// After the DOM is loaded, app-specific code can run.
// Add to the location of the item being composed.
item.enhancedLocation.addAsync(locations);
});
}
Get location
The following example shows how to get the location by calling getAsync on
mailbox.item.enhancedLocation.
JavaScript
let item;
Office.initialize = function () {
item = Office.context.mailbox.item;
// Checks for the DOM to load using the jQuery ready method.
$(document).ready(function () {
// After the DOM is loaded, app-specific code can run.
// Get the location of the item being composed.
item.enhancedLocation.getAsync(callbackFunction);
});
}
function callbackFunction(asyncResult) {
asyncResult.value.forEach(function (place) {
console.log("Display name: " + place.displayName);
console.log("Type: " + place.locationIdentifier.type);
if (place.locationIdentifier.type ===
Office.MailboxEnums.LocationType.Room) {
console.log("Email address: " + place.emailAddress);
}
});
}
7 Note
Remove location
The following example shows how to remove the location by calling removeAsync on
mailbox.item.enhancedLocation.
JavaScript
let item;
Office.initialize = function () {
item = Office.context.mailbox.item;
// Checks for the DOM to load using the jQuery ready method.
$(document).ready(function () {
// After the DOM is loaded, app-specific code can run.
// Get the location of the item being composed.
item.enhancedLocation.getAsync(callbackFunction);
});
}
function callbackFunction(asyncResult) {
asyncResult.value.forEach(function (currentValue) {
// Remove each location from the item being composed.
item.enhancedLocation.removeAsync([currentValue.locationIdentifier]);
});
}
To use item.location.getAsync , provide a callback function that checks for the status
and result of the asynchronous call. You can provide any necessary arguments to the
callback function through the asyncContext optional parameter. You can obtain status,
results, and any error using the output parameter asyncResult of the callback. If the
asynchronous call is successful, you can get the location as a string using the
AsyncResult.value property.
JavaScript
let item;
Office.initialize = function () {
item = Office.context.mailbox.item;
// Checks for the DOM to load using the jQuery ready method.
$(document).ready(function () {
// After the DOM is loaded, app-specific code can run.
// Get the location of the item being composed.
getLocation();
});
}
7 Note
You can set multiple locations by using a semi-colon as the separator (e.g.,
'Conference room A; Conference room B').
JavaScript
let item;
Office.initialize = function () {
item = Office.context.mailbox.item;
// Check for the DOM to load using the jQuery ready method.
$(document).ready(function () {
// After the DOM is loaded, app-specific code can run.
// Set the location of the item being composed.
setLocation();
});
}
Collaboration in the workplace not only occurs within the organization, but extends to
external partners as well. With information being shared beyond an organization's
network, it's important to establish measures to prevent data loss and enforce
compliance policies. Microsoft Purview Information Protection helps you implement
solutions to classify and protect sensitive information. The use of sensitivity labels in
Outlook is a capability you can configure to protect your data.
You can use the Office JavaScript API to implement sensitivity label solutions in your
Outlook add-in projects and support the following scenarios.
7 Note
Support for the sensitivity label feature was introduced in requirement set 1.13. For
information about client support for this feature, see Supported clients and
platforms.
Prerequisites
To implement the sensitivity label feature in your add-in, you must have a Microsoft 365
E5 subscription. For access to a free developer sandbox that includes a renewable E5
subscription, join the Microsoft 365 Developer Program.
Windows Supported
Version 2304 (Build 16327.20248) or later
Mac Supported
Version 16.71.312.0 or later (preview)
7 Note
The sensitivity label feature isn't yet supported for the Unified manifest for
Microsoft 365 (preview).
To use the sensitivity feature in your Outlook add-in project, you must set the
<Permissions> element of the XML manifest to ReadWriteItem.
XML
<Permissions>ReadWriteItem</Permissions>
If your add-in will detect and handle the OnSensitivityLabelChanged event, additional
manifest configurations are required to enable the event-based activation feature. To
learn more, see Detect sensitivity label changes with the OnSensitivityLabelChanged
event.
Verify the status of the catalog of sensitivity
labels
Sensitivity labels and policies are configured by an organization's administrator through
the Microsoft Purview compliance portal. For guidance on how to configure sensitivity
labels in your tenant, see Create and configure sensitivity labels and their policies.
Before you can get or set the sensitivity label on a message or appointment, you must
first ensure that the catalog of sensitivity labels is enabled on the mailbox where the
add-in is installed. To check the status of the catalog of sensitivity labels, call
context.sensitivityLabelsCatalog.getIsEnabledAsync in compose mode.
JavaScript
The following example shows how to identify the sensitivity labels available in the
catalog.
JavaScript
JavaScript
JavaScript
Instead of using the GUID to set the sensitivity label, you can pass the
SensitivityLabelDetails object retrieved from the catalog call, as shown in the following
example.
JavaScript
Office.context.mailbox.item.sensitivityLabel.setAsync(catalog[0],
(asyncResult) => {
if (asyncResult.status ===
Office.AsyncResultStatus.Succeeded) {
console.log(asyncResult.status);
} else {
console.log("Action failed with error: " +
asyncResult.error.message);
}
});
} else {
console.log("Catalog list is empty");
}
} else {
console.log("Action failed with error: " +
asyncResult.error.message);
}
});
} else {
console.log("Action failed with error: " +
asyncResult.error.message);
}
});
7 Note
The OnSensitivityLabelChanged event isn't yet supported for the Unified manifest
for Microsoft 365 (preview).
See also
Learn about sensitivity labels
Get started with sensitivity labels
Create and configure sensitivity labels and their policies
Configure your Outlook add-in for event-based activation
Office Add-ins code sample: Verify the sensitivity label of a message
Manage the delivery date and time of a
message
Article • 06/08/2023
The Outlook client gives you the option to delay the delivery of a message, but requires
you to keep Outlook and your device running to send it at the specified time. With the
Office JavaScript API, you can now implement an Outlook add-in that sends scheduled
messages even with your Outlook client closed or with your device turned off. This
capability provides your users with the convenience to schedule email marketing
campaigns or time a message to be delivered during a colleague or customer's business
hours.
7 Note
Support for this feature was introduced in requirement set 1.13. See clients and
platforms that support this requirement set.
For further guidance on how to configure an Outlook add-in manifest, see Office add-in
manifests.
JavaScript
JavaScript
// Delays the delivery time by five minutes from the current time.
const currentTime = new Date().getTime();
const milliseconds = 5 * 60 * 1000;
const timeDelay = new Date(currentTime + milliseconds);
Office.context.mailbox.item.delayDeliveryTime.setAsync(timeDelay,
(asyncResult) => {
if (asyncResult.status === Office.AsyncResultStatus.Failed) {
console.log(asyncResult.error.message);
return;
}
allows the message to be sent even if the Outlook client isn’t running. However, because
of this, the message doesn't appear in the Outbox folder, so you won't be able to edit
the message or cancel its delivery after selecting Send. You'll be able to review the
message from the Sent Items folder once the message is sent.
This behavior differs from a message scheduled using the native Delay Delivery option
in the Outlook client, which processes the delay client-side. A message scheduled using
this option appears in the Outbox folder and is only delivered if the Outlook client from
which it was sent is running at the specified delivery time.
See also
Create Outlook add-ins for compose forms
Privacy, permissions, and security for
Outlook add-ins
Article • 07/17/2023
End users, developers, and administrators can use the tiered permission levels of the
security model for Outlook add-ins to control privacy and performance.
This article describes the possible permissions that Outlook add-ins can request, and
examines the security model from the following perspectives.
Permissions model
Because customers' perception of add-in security can affect add-in adoption, Outlook
add-in security relies on a tiered permissions model. An Outlook add-in would disclose
the level of permissions it needs, identifying the possible access and actions that the
add-in can make on the customer's mailbox data.
regular expressions
Outlook add-in API read
access
getting the item
properties and the
callback token
Permission XML manifest unified manifest for Summary description
level name Microsoft 365 name
canonical
name
writing custom
properties
Permissions are declared in the manifest. The markup varies depending on the type of
manifest.
7 Note
There is a supplementary permission needed for add-ins that use the append-
on-send feature. With the XML manifest, you specify the permission in the
ExtendedPermissions element. For details, see Implement append-on-send
in your Outlook add-in. With the unified manifest (preview), you specify this
permission with the name Mailbox.AppendOnSend.User in an additional
object in the "authorization.permissions.resourceSpecific" array.
There is a supplementary permission needed for add-ins that use shared
folders. With the XML manifest, you specify the permission by setting the
SupportsSharedFolders element to true . For details, see Enable shared
folders and shared mailbox scenarios in an Outlook add-in. With the unified
manifest (preview), you specify this permission with the name
Mailbox.SharedFolder in an additional object in the
"authorization.permissions.resourceSpecific" array.
The four levels of permissions are cumulative: the read/write mailbox permission
includes the permissions of read/write item, read item and restricted, read/write item
includes read item and restricted, and the read item permission includes restricted.
The following figure shows the four levels of permissions and describes the capabilities
offered to the end user, developer, and administrator by each tier. For more information
about these permissions, see End users: privacy and performance concerns, Developers:
permission choices and resource usage limits, and Understanding Outlook add-in
permissions.
Relating the four-tier permission model to the end user, developer, and administrator
AppSource: Add-in integrity
AppSource hosts add-ins that can be installed by end users and administrators.
AppSource enforces the following measures to maintain the integrity of these Outlook
add-ins.
Requires the host server of an add-in to always use Secure Socket Layer (SSL) to
communicate.
- Windows1 The Get Add-ins or All Apps2 button isn't displayed, so users aren't able to manage
- Mac their add-ins or access AppSource.
Web Availability of add-ins and access to AppSource are unaffected, so users can
browser continue to manage their add-ins including admin-deployed ones.
7 Note
1
On Windows, support for this experience is available from Version 2008 (Build
13127.20296). For more details on your client version, see the update history page
for Microsoft 365 and how to find your Office client version and update
channel .
2
Starting in Outlook on Windows Version 2303 (Build 16215.10000), the All Apps
button is used to manage add-ins and access AppSource.
For general add-in behavior, see Privacy and security for Office Add-ins.
) Important
Add-ins activate on digitally signed messages in Outlook on Windows
associated with a Microsoft 365 subscription. This support was introduced
with Version 1711 (Build 8711.1000).
Before installing an add-in from AppSource, end users can see the access and
actions that the add-in can make on their data and must explicitly confirm to
proceed. No Outlook add-in is automatically pushed onto a client computer
without manual validation by the user or administrator.
Granting the restricted permission allows the Outlook add-in to have limited
access on only the current item. Granting the read item permission allows the
Outlook add-in to access personal identifiable information, such as sender and
recipient names and email addresses, on only the current item.
An end user can install an Outlook add-in for only himself or herself. Outlook add-
ins that affect an organization are installed by an administrator.
End users can install Outlook add-ins that enable context-sensitive scenarios that
are compelling to users while minimizing the users' security risks.
Manifest files of installed Outlook add-ins are secured in the user's email account.
Applicable to only the Outlook rich clients: The Outlook rich clients monitor the
performance of installed Outlook add-ins, exercise governance control, and disable
those Outlook add-ins that exceed limits in the following areas.
Memory usage
CPU usage
Governance deters denial-of-service attacks and maintains add-in performance at
a reasonable level. The Business Bar alerts end users about Outlook add-ins that
the Outlook rich client has disabled based on such governance control.
At any time, end users can verify the permissions requested by installed Outlook
add-ins, and disable or subsequently enable any Outlook add-in in the Exchange
Admin Center.
The following example requests the read item permission in the XML manifest.
XML
<Permissions>ReadItem</Permissions>
The following example requests the read item permission in the Unified manifest
for Microsoft 365 (preview).
JSON
"authorization": {
"permissions": {
"resourceSpecific": [
...
{
"name": "MailboxItem.Read.User",
"type": "Delegated"
},
]
}
},
Developers can request the restricted permission if the Outlook add-in activates
on a specific type of Outlook item (appointment or message), or on specific
extracted entities (phone number, address, URL) being present in the item's subject
or body. For example, the following rule activates the Outlook add-in if one or
more of three entities - phone number, postal address, or URL - are found in the
subject or body of the current message.
7 Note
Activation rules, as seen in this example, aren't supported in add-ins that use the
Unified manifest for Microsoft 365 (preview).
XML
<Permissions>Restricted</Permissions>
<Rule xsi:type="RuleCollection" Mode="And">
<Rule xsi:type="ItemIs" FormType="Read" ItemType="Message" />
<Rule xsi:type="RuleCollection" Mode="Or">
<Rule xsi:type="ItemHasKnownEntity" EntityType="PhoneNumber" />
<Rule xsi:type="ItemHasKnownEntity" EntityType="Address" />
<Rule xsi:type="ItemHasKnownEntity" EntityType="Url" />
</Rule>
</Rule>
Developers should request the read item permission if the Outlook add-in needs
to read properties of the current item other than the default extracted entities, or
write custom properties set by the add-in on the current item, but doesn't require
reading or writing to other items, or creating or sending a message in the user's
mailbox. For example, a developer should request read item permission if an
Outlook add-in needs to look for an entity like a meeting suggestion, task
suggestion, email address, or contact name in the item's subject or body, or uses a
regular expression to activate.
Developers should request the read/write item permission if the Outlook add-in
needs to write to properties of the composed item, such as recipient names, email
addresses, body, and subject, or needs to add or remove item attachments.
Developers request the read/write mailbox permission only if the Outlook add-in
needs to do one or more of the following actions by using the
mailbox.makeEWSRequestAsync method.
Read or write to properties of items in the mailbox.
Create, read, write, or send items in the mailbox.
Create, read, or write to folders in the mailbox.
Developers can't use ActiveX controls in add-ins because they're not supported.
Host the add-in they are submitting on a web server that supports SSL.
Administrators: Privileges
The security model provides the following rights and responsibilities to administrators.
Can prevent end users from installing any Outlook add-in, including add-ins from
AppSource.
Can disable or enable any Outlook add-in on the Exchange Admin Center.
Outlook add-ins specify the required permission level in their manifest. There are four
available levels.
regular expressions
Outlook add-in API read
access
getting the item
properties and the
callback token
writing custom properties
7 Note
There is a supplementary permission needed for add-ins that use the append-
on-send feature. With the XML manifest, you specify the permission in the
ExtendedPermissions element. For details, see Implement append-on-send
in your Outlook add-in. With the unified manifest (preview), you specify this
permission with the name Mailbox.AppendOnSend.User in an additional
object in the "authorization.permissions.resourceSpecific" array.
There is a supplementary permission needed for add-ins that use shared
folders. With the XML manifest, you specify the permission by setting the
SupportsSharedFolders element to true . For details, see Enable shared
folders and shared mailbox scenarios in an Outlook add-in. With the unified
manifest (preview), you specify this permission with the name
Mailbox.SharedFolder in an additional object in the
"authorization.permissions.resourceSpecific" array.
The four levels of permissions are cumulative: the read/write mailbox permission
includes the permissions of read/write item, read item and restricted, read/write item
includes read item and restricted, and the read item permission includes restricted.
You can see the permissions requested by a mail add-in before installing it from
AppSource . You can also see the required permissions of installed add-ins in the
Exchange Admin Center.
restricted permission
The restricted permission is the most basic level of permission. Outlook assigns this
permission to a mail add-in by default if the add-in doesn't request a specific permission
in its manifest.
Can do
Get only specific entities (phone number, address, URL) from the item's subject or
body.
Specify an ItemIs activation rule that requires the current item in a read or
compose form to be a specific item type, or ItemHasKnownEntity rule that matches
any of a smaller subset of supported well-known entities (phone number, address,
URL) in the selected item.
7 Note
Access any properties and methods that do not pertain to specific information
about the user or item (see the next section for the list of members that do).
Can't do
Use an ItemHasKnownEntity rule on the contact, email address, meeting
suggestion, or task suggestion entity.
Access the members in the following list that pertain to the information of the user
or item. Attempting to access members in this list will return null and result in an
error message which states that Outlook requires the mail add-in to have elevated
permission.
item.addFileAttachmentAsync
item.addItemAttachmentAsync
item.attachments
item.bcc
item.body
item.cc
item.from
item.getRegExMatches
item.getRegExMatchesByName
item.optionalAttendees
item.organizer
item.removeAttachmentAsync
item.requiredAttendees
item.sender
item.to
mailbox.getCallbackTokenAsync
mailbox.getUserIdentityTokenAsync
mailbox.makeEwsRequestAsync
mailbox.userProfile
Body and all its child members
Location and all its child members
Recipients and all its child members
Subject and all its child members
Time and all its child members
Can do
Read all the properties of the current item in a read or compose form, for example,
item.to in a read form and item.to.getAsync in a compose form.
Get a callback token to get item attachments or the full item with Exchange Web
Services (EWS) or Outlook REST APIs.
Get all existing well-known entities, not just a subset, from the item's subject or
body.
7 Note
XML
<Permissions>ReadItem</Permissions>
<Rule xsi:type="RuleCollection" Mode="And">
<Rule xsi:type="ItemIs" FormType = "Read" ItemType="Message" />
<Rule xsi:type="RuleCollection" Mode="Or">
<Rule xsi:type="ItemHasKnownEntity"
EntityType="PhoneNumber" />
<Rule xsi:type="ItemHasKnownEntity" EntityType="Address" />
<Rule xsi:type="ItemHasKnownEntity" EntityType="Url" />
<Rule xsi:type="ItemHasKnownEntity"
EntityType="MeetingSuggestion" />
<Rule xsi:type="ItemHasKnownEntity"
EntityType="TaskSuggestion" />
<Rule xsi:type="ItemHasKnownEntity"
EntityType="EmailAddress" />
<Rule xsi:type="ItemHasKnownEntity" EntityType="Contact" />
</Rule>
Can't do
Use the token provided by mailbox.getCallbackTokenAsync to:
Update or delete the current item using the Outlook REST API or access any
other items in the user's mailbox.
Get the current calendar event item using the Outlook REST API.
Can do
Read and write all item-level properties of the item that is being viewed or
composed in Outlook.
Use all other members of the Office JavaScript API that are applicable to mail add-
ins, except Mailbox.makeEWSRequestAsync.
Can't do
Use the token provided by mailbox.getCallbackTokenAsync to:
Update or delete the current item using the Outlook REST API or access any
other items in the user's mailbox.
Get the current calendar event item using the Outlook REST API.
Use mailbox.makeEWSRequestAsync.
In addition to what the read/write item permission supports, the token provided by
mailbox.getCallbackTokenAsync provides access to use Exchange Web Services (EWS)
operations or Outlook REST APIs to do the following:
Read and write all properties of any item in the user's mailbox.
Create, read, and write to any folder or item in that mailbox.
Send an item from that mailbox
CopyItem
CreateFolder
CreateItem
FindConversation
FindFolder
FindItem
GetConversationItems
GetFolder
GetItem
MarkAsJunk
MoveItem
SendItem
UpdateFolder
UpdateItem
See also
Privacy, permissions, and security for Outlook add-ins
Match strings in an Outlook item as well-known entities
Authentication options in Outlook add-
ins
Article • 08/14/2023
Your Outlook add-in can access information from anywhere on the Internet, whether
from the server that hosts the add-in, from your internal network, or from somewhere
else in the cloud. If that information is protected, your add-in needs a way to
authenticate your user. Outlook add-ins provide a number of different methods to
authenticate, depending on your specific scenario.
7 Note
The Single Sign-on API is currently supported for Word, Excel, Outlook, and
PowerPoint. For more information about where the Single Sign-on API is currently
supported, see IdentityAPI requirement sets. If you're working with an Outlook
add-in, be sure to enable Modern Authentication for the Microsoft 365 tenancy. For
information about how to do this, see Enable or disable modern authentication
for Outlook in Exchange Online.
The SSO authentication method uses the OAuth2 On-Behalf-Of flow provided by Azure
Active Directory. It requires that the add-in register in the Application Registration
Portal and specify any required Microsoft Graph scopes in its manifest.
7 Note
If the add-in is using the Unified manifest for Microsoft 365 (preview), there is
some manifest configuration, but Microsoft Graph scopes aren't specified. SSO-
enabled add-ins that use the unified manifest can be sideloaded, but can't be
deployed in any other way at this time.
Using this method, your add-in can obtain an access token scoped to your server back-
end API. The add-in uses this as a bearer token in the Authorization header to
authenticate a call back to your API. At that point your server can:
For a more detailed overview, see the full overview of the SSO authentication method.
For details on using the SSO token in an Outlook add-in, see Authenticate a user with an
single-sign-on token in an Outlook add-in.
For a sample add-in that uses the SSO token, see Outlook Add-in SSO .
Your add-in can call getUserIdentityTokenAsync to get Exchange user identity tokens.
For details on using these tokens, see Authenticate a user with an identity token for
Exchange.
Using this method, your add-in prompts the user to sign-in to the service either by
using the displayDialogAsync method to initialize the OAuth2 flow.
Callback tokens
Callback tokens provide access to the user's mailbox from your server back-end, either
using Exchange Web Services (EWS), or the Outlook REST API. Consider using callback
tokens if your add-in:
Add-ins obtain callback tokens using one of the getCallbackTokenAsync methods. The
level of access is controlled by the permissions specified in the add-in manifest.
Authenticate a user with a single-sign-
on token in an Outlook add-in
Article • 08/14/2023
Single sign-on (SSO) provides a seamless way for your add-in to authenticate users (and
optionally to obtain access tokens to call the Microsoft Graph API).
Using this method, your add-in can obtain an access token scoped to your server back-
end API. The add-in uses this as a bearer token in the Authorization header to
authenticate a call back to your API. Optionally, you can also have your server-side code.
For an overview of SSO in Office Add-ins, see Enable single sign-on for Office Add-ins
and Authorize to Microsoft Graph in your Office Add-in.
elements. For detailed information about the markup, see Configure the add-in.
JSON
"webApplicationInfo": {
"id": "a661fed9-f33d-4e95-b6cf-624a34a2f51d",
"resource": "api://addin.contoso.com/a661fed9-f33d-4e95-b6cf-
624a34a2f51d"
},
7 Note
SSO-enabled add-ins that use the unified manifest can be sideloaded, but
can't be deployed in any other way at this time.
When using the SSO token as an identity in an Outlook add-in, we recommend that
you also use the Exchange identity token as an alternate identity. Users of your
add-in may use multiple clients, and some may not support providing an SSO
token. By using the Exchange identity token as an alternate, you can avoid having
to prompt these users for credentials multiple times. For more information, see
Scenario: Implement single sign-on to your service in an Outlook add-in.
See also
getAccessToken
For a sample Outlook add-in that uses the SSO token to access the Microsoft
Graph API, see Outlook Add-in SSO .
SSO API reference
IdentityAPI requirement set
Enable single sign-on (SSO) or cross-origin resource sharing (CORS) in your event-
based Outlook add-in
Enable single sign-on (SSO) or cross-
origin resource sharing (CORS) in your
event-based Outlook add-in
Article • 07/07/2023
When an Outlook add-in uses event-based activation, the events run in a separate
runtime. To enable single sign-on (SSO) in your event-based add-in or allow it to
request external data through cross-origin resource sharing (CORS), you must configure
a well-known URI. Through this resource, Office will be able to identify the add-ins,
including their JavaScript files, that support SSO or CORS requests.
7 Note
The steps in this article only apply when running your Outlook add-in on Windows.
This is because Outlook on Windows uses a JavaScript file, while Outlook on Mac
and on the web use an HTML file that references the same JavaScript file. To learn
more about event-based activation in Outlook add-ins, see Configure your
Outlook add-in for event-based activation.
The following example shows how to enable SSO or CORS for two add-ins (a main
version and beta version). You can list as many add-ins as necessary depending on how
many you provide from your web server.
JSON
{
"allowed":
[
"https://addin.contoso.com:8000/main/js/autorun.js",
"https://addin.contoso.com:8000/beta/js/autorun.js"
]
}
Host the JSON file under a location named .well-known in the URI at the root of the
origin. For example, if the origin is https://addin.contoso.com:8000/ , then the well-
known URI is https://addin.contoso.com:8000/.well-known/microsoft-officeaddins-
allowed.json .
The origin refers to a pattern of scheme + subdomain + domain + port. The name of
the location must be .well-known , and the name of the resource file must be
microsoft-officeaddins-allowed.json . This file must contain a JSON object with an
attribute named allowed whose value is an array of all JavaScript files authorized for
SSO for their respective add-ins.
After you configure the well-known URI, if your add-in implements SSO, you can then
call the getAccessToken() API to get an access token with the user's identity.
) Important
See also
Authenticate a user with a single-sign-on token in an Outlook add-in
Configure your Outlook add-in for event-based activation
Authenticate a user with an identity
token for Exchange
Article • 03/28/2023
Exchange user identity tokens provide a way for your add-in to uniquely identify an add-
in user. By establishing the user's identity, you can implement a single sign-on (SSO)
authentication scheme for your back-end service that enables customers who are using
Outlook add-ins to connect to your service without signing in. See Exchange user
identity token for more about when to use this token type. In this article, we'll take a
look at a simplistic method of using the Exchange identity token to authenticate a user
to your back-end.
) Important
Once validated and decoded, the payload of the token looks something like the
following:
JSON
{
"aud" : "https://mailhost.contoso.com/IdentityTest.html",
"iss" : "00000002-0000-0ff1-ce00-000000000000@mailhost.contoso.com",
"nbf" : "1505749527",
"exp" : "1505778327",
"appctxsender":"00000002-0000-0ff1-ce00-
000000000000@mailhost.context.com",
"isbrowserhostedapp":"true",
"appctx" : {
"msexchuid" : "53e925fa-76ba-45e1-be0f-4ef08b59d389",
"version" : "ExIdTok.V1",
"amurl" :
"https://mailhost.contoso.com:443/autodiscover/metadata/json/1"
}
}
Generate a unique ID
Use a combination of the msexchuid and amurl properties. For example, you could
concatenate the two values together and generate a base 64-encoded string. This value
can be reliably generated from the token every time, so you can map an Exchange user
identity token back to the user in your system.
If the user is found, the back-end treats the request as authenticated, and allows
the request to proceed.
If the user is not found, then the back-end returns an error indicating that the user
needs to sign in. The add-in then prompts the user to sign in to the back-end
using your existing authentication method. Once the user is authenticated, the
Exchange user identity token is submitted with the user authentication details. The
back-end can then update the user's record in your system with the unique ID.
Validate an Exchange identity token
Article • 03/28/2023
Your Outlook add-in can send you an Exchange user identity token, but before you trust
the request you must validate the token to ensure that it came from the Exchange server
that you expect. Exchange user identity tokens are JSON Web Tokens (JWT). The steps
required to validate a JWT are described in RFC 7519 JSON Web Token (JWT) .
We suggest that you use a four-step process to validate the identity token and obtain
the user's unique identifier. First, extract the JSON Web Token (JWT) from a base64 URL-
encoded string. Second, make sure that the token is well-formed, that it is for your
Outlook add-in, that it has not expired, and that you can extract a valid URL for the
authentication metadata document. Next, retrieve the authentication metadata
document from the Exchange server and validate the signature attached to the identity
token. Finally, compute a unique identifier for the user by concatenating the user's
Exchange ID with the URL of the authentication metadata document.
JSON
{header}.{payload}.{signature}
For more information about the contents of the token, see Inside the Exchange identity
token.
After you have the three decoded components, you can proceed with validating the
content of the token.
signing key manifest file. For example, the expected amurl value for Microsoft
365 is https://outlook.office365.com:443/autodiscover/metadata/json/1 . See
the next section Verify the domain for additional information.
Current time is between the times specified in the nbf and exp claims. The nbf
claim specifies the earliest time that the token is considered valid, and the exp
claim specifies the expiration time for the token. It is recommended to allow for
some variation in clock settings between servers.
aud claim is the expected URL for your add-in.
version claim inside the appctx claim is set to ExIdTok.V1 .
If your add-in service has a preexisting configuration with the user's tenant, then
you can establish if this amurl is trusted.
If your add-in can't verify the amurl using any of these options, you may choose to have
your add-in shut down gracefully with an appropriate notification to the user if
authentication is necessary for the add-in's workflow.
JSON
{
"id": "_70b34511-d105-4e2b-9675-39f53305bb01",
"version": "1.0",
"name": "Exchange",
"realm": "*",
"serviceName": "00000002-0000-0ff1-ce00-000000000000",
"issuer": "00000002-0000-0ff1-ce00-000000000000@*",
"allowedAudiences": [
"00000002-0000-0ff1-ce00-000000000000@*"
],
"keys": [
{
"usage": "signing",
"keyinfo": {
"x5t": "enh9BJrVPU5ijV1qjZjV-fL2bco"
},
"keyvalue": {
"type": "x509Certificate",
"value": "MIIHNTCC..."
}
}
],
"endpoints": [
{
"location":
"https://by2pr06mb2229.namprd06.prod.outlook.com:444/autodiscover/metadata/j
son/1",
"protocol": "OAuth2",
"usage": "metadata"
}
]
}
The available signing keys are in the keys array. Select the correct key by ensuring that
the x5t value in the keyinfo property matches the x5t value in the header of the
token. The public key is inside the value property in the keyvalue property, stored as a
base64-encoded byte array.
After you have the correct public key, verify the signature. The signed data is the first
two parts of the encoded token, separated by a period:
JSON
{header}.{payload}
) Important
We no longer recommend the Exchange Web Services Managed API because the
Microsoft.Exchange.WebServices.Auth.dll, though still available, is now obsolete
and relies on unsupported libraries like Microsoft.IdentityModel.Extensions.dll.
System.IdentityModel.Tokens.Jwt
The System.IdentityModels.Tokens.Jwt library can parse the token and also perform
the validation, though you will need to parse the appctx claim yourself and retrieve the
public signing key.
C#
// Load the encoded token
string encodedToken = "...";
JwtSecurityToken jwt = new JwtSecurityToken(encodedToken);
authMetadataUrl = AppContext.MetadataUrl;
}
tvp.ValidateIssuer = false;
tvp.ValidateAudience = true;
tvp.ValidAudience = "{URL to add-in}";
tvp.ValidateIssuerSigningKey = true;
// GetSigningKeys downloads the auth metadata doc and
// returns a List<SecurityKey>
tvp.IssuerSigningKeys = GetSigningKeys(authMetadataUrl);
tvp.ValidateLifetime = true;
try
{
var claimsPrincipal = tokenHandler.ValidateToken(encodedToken, tvp, out
SecurityToken validatedToken);
C#
using Newtonsoft.Json;
/// <summary>
/// Representation of the appctx claim in an Exchange user identity token.
/// </summary>
public class ExchangeAppContext
{
/// <summary>
/// The Exchange identifier for the user
/// </summary>
[JsonProperty("msexchuid")]
public string ExchangeUid { get; set; }
/// <summary>
/// The token version
/// </summary>
public string Version { get; set; }
/// <summary>
/// The URL to download authentication metadata
/// </summary>
[JsonProperty("amurl")]
public string MetadataUrl { get; set; }
}
For an example that uses this library to validate Exchange tokens and has an
implementation of GetSigningKeys , see Outlook-Add-In-Token-Viewer .
See also
Outlook-Add-In-Token-Viewer
Outlook-Add-in-JavaScript-ValidateIdentityToken
Inside the Exchange identity token
Article • 05/20/2023
An Exchange user identity token is a base-64 URL-encoded string that is signed by the
Exchange server that sent it. The token is not encrypted, and the public key that you use
to validate the signature is stored on the Exchange server that issued the token. The
token has three parts: a header, a payload, and a signature. In the token string, the parts
are separated by a period character ( . ) to make it easy for you to split the token.
Exchange uses a the JSON Web Token (JWT) format for the identity token. For
information about JWT tokens, see RFC 7519 JSON Web Token (JWT) .
JSON
{
"typ": "JWT",
"alg": "RS256",
"x5t": "Un6V7lYN-rMgaCoFSTO5z707X-4"
}
typ JWT Identifies the token as a JSON Web Token. All identity tokens provided by
Exchange server are JWT tokens.
alg RS256 The hashing algorithm that is used to create the signature. All tokens
provided by Exchange server use the RSASSA-PKCS1-v1_5 with SHA-256
hash algorithm.
JSON
{
"aud": "https://mailhost.contoso.com/IdentityTest.html",
"iss": "00000002-0000-0ff1-ce00-000000000000@mailhost.contoso.com",
"nbf": "1331579055",
"exp": "1331607855",
"appctxsender": "00000002-0000-0ff1-ce00-
000000000000@mailhost.context.com",
"isbrowserhostedapp": "true",
"appctx": {
"msexchuid": "53e925fa-76ba-45e1-be0f-
4ef08b59d389@mailhost.contoso.com",
"version": "ExIdTok.V1",
"amurl": "https://mailhost.contoso.com:443/autodiscover/metadata/json/1"
}
}
The following table lists the parts of the identity token payload.
Claim Description
aud The URL of the add-in that requested the token. A token is only valid if it is
sent from the add-in that is running in the client's webview control. The
URL of the add-in is specified in the manifest. The markup depends on the
type of manifest.
XML manifest: If the add-in uses the Office Add-ins manifests schema v1.1,
this URL is the URL specified in the first <SourceLocation> element, under
the form type ItemRead or ItemEdit , whichever occurs first as part of the
FormSettings element in the add-in manifest.
Unified manifest for Microsoft 365 (preview): The URL is specified in the
"extensions.audienceClaimUrl" property.
iss A unique identifier for the Exchange server that issued the token. All tokens
issued by this Exchange server will have the same identifier.
nbf The date and time that the token is valid starting from. The value is the
number of seconds since January 1, 1970.
Claim Description
exp The date and time that the token is valid until. The value is the number of
seconds since January 1, 1970.
appctxsender A unique identifier for the Exchange server that sent the application
context.
The information in the appctx claim provides you with the unique identifier for the
account and the location of the public key used to sign the token. The following table
lists the parts of the appctx claim.
Application Description
context
property
msexchuid A unique identifier associated with the email account and the Exchange server.
version The version number of the token. For all tokens provided by Exchange, the
value is ExIdTok.V1 .
amurl The URL of the authentication metadata document that contains the public
key of the X.509 certificate that was used to sign the token.
See also
For an example that parses the Exchange user identity token, see Outlook-Add-In-
Token-Viewer .
Scenario: Implement single sign-on to
your service in an Outlook add-in
Article • 08/14/2023
In this article we'll explore a recommended method of using the single sign-on access
token and the Exchange identity token together to provide a single-sign on
implementation to your own backend service. By using both tokens together, you can
take advantage of the benefits of the SSO access token when it is available, while
ensuring that your add-in will work when it is not, such as when the user switches to a
client that does not support them, or if the user's mailbox is on an on-premises
Exchange server.
7 Note
The Single Sign-on API is currently supported for Word, Excel, Outlook, and
PowerPoint. For more information about where the Single Sign-on API is currently
supported, see IdentityAPI requirement sets. If you're working with an Outlook
add-in, be sure to enable Modern Authentication for the Microsoft 365 tenancy. For
information about how to do this, see Enable or disable modern authentication
for Outlook in Exchange Online.
The SSO token uses a standard OpenID format and is issued by Azure. This greatly
simplifies the process of validating these tokens. In comparison, Exchange identity
tokens use a custom format based on the JSON Web Token standard, requiring
custom work to validate the token.
The SSO token can be used by your backend to retrieve an access token for
Microsoft Graph without the user having to do any additional sign in action.
The SSO token provides richer identity information, such as the user's display
name.
Add-in scenario
For the purposes of this example, consider an add-in that consists of both the add-in UI
and scripts (HTML + JavaScript) and a backend Web API that is called by the add-in. The
backend Web API makes calls both to the Microsoft Graph API and the Contoso Data
API, a fictional API created by a third party. Like the Microsoft Graph API, the Contoso
Data API requires OAuth authentication. The requirement is that the backend Web API
should be able to call both APIs without having to prompt the user for their credentials
every time an access token expires.
To do this, the backend API creates a secure database of users. Each user will get an
entry in the database where the backend can store long-lived refresh tokens for both
the Microsoft Graph API and the Contoso Data API. The following JSON markup
represents a user's entry in the database.
JSON
{
"userDisplayName": "...",
"ssoId": "...",
"exchangeId": "...",
"graphRefreshToken": "...",
"contosoRefreshToken": "..."
}
The add-in includes either the SSO access token (if it is available) or the Exchange
identity token (if the SSO token is not available) with every call it makes to the backend
Web API.
Add-in startup
1. When the add-in starts, it sends a request to the backend Web API to determine if
the user is registered (i.e. has an associated record in the user database) and that
the API has refresh tokens for both Graph and Contoso. In this call, the add-in
includes both the SSO token (if available) and the identity token.
2. The Web API uses the methods in Authenticate a user with an single-sign-on token
in an Outlook add-in and Authenticate a user with an identity token for Exchange
to validate and generate a unique identifier from both tokens.
3. If an SSO token was provided, the Web API then queries the user database for an
entry that has an ssoId value that matches the unique identifier generated from
the SSO token.
If an entry exists and an SSO token was provided, update the user's record in
the database to set the ssoId value to the unique identifier generated from
the SSO token and proceed to step 5.
If an entry exists and no SSO token was provided, proceed to step 5.
If no entry exists, create a new entry. Set ssoId to the unique identifier
generated from the SSO token (if available), and set exchangeId to the unique
identifier generated from the Exchange identity token.
If the value is missing or invalid and an SSO token was provided, use the
OAuth2 On-Behalf-Of flow to obtain an access token and refresh token for
Graph. Save the refresh token in the graphRefreshToken value for the user.
If both values are valid, respond to the add-in to indicate that the user is
already registered and configured.
If either value is invalid, respond to the add-in to indicate that user setup is
required, along with which services (Graph or Contoso) need to be
configured.
If the user is already registered and configured, the add-in continues with
normal operation.
If user setup is required, the add-in enters "setup" mode and prompts the
user to authorize the add-in.
Based on the response from the backend Web API, the add-in may need to authorize
the user for the Microsoft Graph API, the Contoso Data API, or both. Since both APIs use
OAuth2 authentication, the method is similar for both.
1. The add-in notifies the user that it needs them to authorize their use of the API
and asks them to click a link or button to start the process.
2. Once the flow completes, the add-in sends the refresh token to the backend Web
API and includes the SSO token (if available) or the Exchange identity token.
3. The backend Web API locates the user in the database and updates the
appropriate refresh token.
Normal operation
Whenever the add-in calls the backend Web API, it includes either the SSO token or the
Exchange identity token. The backend Web API locates the user by this token, then uses
the stored refresh tokens to obtain access tokens for the Microsoft Graph API and the
Contoso Data API. As long as the refresh tokens are valid, the user will not have to sign
in again.
Deploy and install Outlook add-ins for
testing
Article • 03/28/2023
As part of the process of developing an Outlook add-in, you'll probably find yourself
iteratively deploying and installing the add-in for testing, which involves the following
steps.
7 Note
Custom panes have been deprecated so please ensure that you're using a
supported add-in extension point.
The Exchange administrator can run the following PowerShell cmdlet to assign a single
user the necessary permissions. In this example, wendyri is the user's email alias.
PowerShell
If necessary, the administrator can run the following cmdlet to assign multiple users the
similar necessary permissions.
PowerShell
For more information about the My Custom Apps role, see My Custom Apps role.
Using Microsoft 365 or Visual Studio to develop add-ins assigns you the organization
administrator role which allows you to install add-ins by file or URL in the EAC, or by
Powershell cmdlets.
PowerShell
Use the following additional PowerShell cmdlets to manage the add-ins for a mailbox.
Client versions
Deciding what versions of the Outlook client to test depends on your development
requirements.
If you're developing an add-in for private use, or only for members of your
organization, then it is important to test the versions of Outlook that your
company uses. Keep in mind that some users may use Outlook on the web, so
testing your company's standard browser versions is also important.
If you're developing an add-in to list in AppSource , you must test the required
versions as specified in the Commercial marketplace certification policies 1120.3.
This includes:
The latest version of Outlook on Windows and the version prior to the latest.
The latest version of Outlook on Mac.
The latest version of Outlook on iOS and Android (if your add-in supports
mobile form factor).
The browser versions specified in the Commercial marketplace validation policy
1120.3.
7 Note
If your add-in does not support one of the above clients due to requesting an API
requirement set that the client does not support, that client would be removed
from the list of required clients.
To mitigate this, we recommend you test your add-in in Outlook on the web connected
to your own private on-premises Exchange environment. For more information, see
guidance on how to Establish an Exchange 2016 or Exchange 2019 test environment and
how to manage Outlook on the web in Exchange Server.
Alternatively, you can opt to pay for and use a service that hosts and manages on-
premises Exchange servers. A couple of options are:
Rackspace
Hostway
Furthermore, if you don't want your add-ins to be available for users who are connected
to on-premises Exchange, you can set the requirement set in the add-in manifest to be
1.6 or higher. Such add-ins will not be tested or validated on the classic Outlook on the
web UI.
See also
Troubleshoot user errors with Office Add-ins
Sideload Outlook add-ins for testing
Article • 08/15/2023
Sideload your Outlook add-in for testing without having to first put it in an add-in
catalog.
) Important
If your Outlook add-in supports mobile, sideload the manifest using the
instructions in this article for your Outlook client on the web, on Windows, or on
Mac, then follow the guidance in Testing your add-ins on mobile.
Sideload automatically
If you created your Outlook add-in using the Yeoman generator for Office Add-ins,
sideloading is best done through the command line on Windows. This takes advantage
of our tooling and allows you to sideload across all of your supported devices in one
command.
1. On Windows, open a command prompt and navigate to the root directory of your
Yeoman generated add-in project. Run the command npm start .
) Important
If the manifest contains an error or the path to the manifest is invalid, you'll
receive an error message.
3. If your manifest contains no errors and the path is valid, your add-in will now be
sideloaded and available on both your desktop and in Outlook on the web. It will
also be installed across all your supported devices.
Sideload manually
Though we strongly recommend sideloading automatically through the command line
as covered in the previous section, you can also manually sideload an Outlook add-in
based on the Outlook client. Select the tab for your preferred Outlook client.
Windows
2. Depending on your Outlook version, select Get Add-ins or All Apps from the
ribbon.
7 Note
) Important
If you don't see Get Add-ins or All Apps in your version of Outlook, do
one of the following:
) Important
If you see the Add Apps option instead of Get Add-ins in your version of
Outlook, you must manually sideload your add-in through Outlook on
the web.
To access the Add-Ins for Outlook dialog in Outlook on the web, do one
of the following:
Outlook on the web opens in your preferred browser. When the Add-Ins
for Outlook dialog appears, follow the succeeding steps to sideload your
add-in.
Note that due to caching, it may take up to 24 hours for the sideloaded
add-in to appear in your Outlook client on Windows.
4. If there are tabs near the top of the dialog that opens, ensure that the Add-ins
tab is selected. Then, choose My add-ins.
5. Locate the Custom add-ins section at the bottom of the dialog. Select the
Add a custom add-in link, and then select Add from File.
6. Locate the manifest file for your custom add-in and install it. Accept all
prompts during the installation.
Outlook 2013
1. Open Outlook 2013 on Windows.
2. Select File > Info > Manage Add-ins. Outlook will open the web version in a
browser.
3. Depending on your version of Outlook on the web, follow the steps in the
Web tab of Sideload manually.
To remove a sideloaded add-in from Outlook, in the Add-Ins for Outlook dialog,
navigate to the Custom add-ins section. Choose the ellipsis ( ... ) for the add-in, then
choose Remove.
See also
Add-ins for Outlook on mobile devices
Compare Outlook add-in support in
Outlook on Mac with other Outlook
clients
Article • 10/11/2022
You can create and run an Outlook add-in the same way in Outlook on Mac as in the
other clients, including Outlook on the web, Windows, iOS, and Android, without
customizing the JavaScript for each client. The same calls from the add-in to the Office
JavaScript API generally work the same way, except for the areas described in the
following table.
For more information, see Deploy and install Outlook add-ins for testing.
For information about new UI support, see Add-in support in Outlook on new Mac UI.
Instances of a Can get the item ID and other Can get the item ID and other
recurring properties of a master appointment or properties of the master
appointment appointment instance of a recurring appointment, but not those of
series series. an instance of a recurring
Can use series.
mailbox.displayAppointmentForm to Can display the master
display an instance or the master of a appointment of a recurring
recurring series. series. Without the item ID,
cannot display an instance of a
recurring series.
Version string of The format of the version string returned by An example of the version string
the client diagnostics.hostVersion depends on the returned by Diagnostics.hostVersion
application actual type of client. For example: on Outlook on Mac: 15.0 (140325)
Custom If the network goes down, an add-in can still Because Outlook on Mac does not
properties of an access cached custom properties. cache custom properties, if the
item network goes down, add-ins would
not be able to access them.
NOTE: If a file is
programmatically attached (e.g
through an add-in) without an
extension then the
AttachmentDetails.name will not
contain the extension as part of
filename.
String As an example: Thu Mar 13 2014 14:09:11 As an example: Thu Mar 13 2014
representing the GMT+0800 (China Standard Time) 14:09:11 GMT+0800 (CST)
time zone in the
dateTimeCreated
and
dateTimeModified
properties
Area Outlook on the web, Windows, and mobile Outlook on Mac
devices
Time accuracy of If an add-in uses the following code, the The accuracy is up to only a second.
dateTimeCreated accuracy is up to a millisecond.
and JSON.stringify(Office.context.mailbox.item,
dateTimeModified null, 4);
To learn more about the new Mac UI, see The new Outlook for Mac .
Classic UI
New UI
Tips for handling date values in Outlook add-ins
Article • 07/11/2022
The Office JavaScript API uses the JavaScript Date object for most of the storage and retrieval of dates and times.
That Date object provides methods such as getUTCDate , getUTCHour , getUTCMinutes , and toUTCString , which return the
requested date or time value according to Universal Coordinated Time (UTC) time.
The Date object also provides other methods such as getDate , getHour , getMinutes , and toString , which return the
requested date or time according to "local time".
The concept of "local time" is largely determined by the browser and operating system on the client computer. For instance, on
most browsers running on a Windows-based client computer, a JavaScript call to getDate , returns a date based on the time zone
set in Windows on the client computer.
The following example creates a Date object myLocalDate in local time, and calls toUTCString to convert that date to a date string
in UTC.
JavaScript
While you can use the JavaScript Date object to get a date or time value based on UTC or the client computer time zone, the Date
object is limited in one respect - it does not provide methods to return a date or time value for any other specific time zone. For
example, if your client computer is set to be on Eastern Standard Time (EST), there is no Date method that allows you to get the
hour value other than in EST or UTC, such as Pacific Standard Time (PST).
Client computer This is set on the operating system of the client computer. Most browsers use the client computer time zone to display date or
time zone time values of the JavaScript Date object.
An Outlook rich client uses this time zone to display date or time values in the user interface.
For example, on a client computer running Windows, Outlook uses the time zone set on Windows as the local time zone. On
the Mac, if the user changes the time zone on the client computer, Outlook on Mac would prompt the user to update the time
zone in Outlook as well.
Exchange Admin The user sets this time zone value (and the preferred language) when he or she logs on to Outlook on the web or mobile
Center (EAC) devices the first time.
time zone
Outlook on the web and mobile devices use this time zone to display date or time values in the user interface.
Because an Outlook rich client uses the client computer time zone, and the user interface of Outlook on the web and mobile
devices uses the EAC time zone, the local time for the same add-in installed for the same mailbox can be different when running in
an Outlook rich client and in Outlook on the web or mobile devices. As an Outlook add-in developer, you should appropriately
input and output date values so that those values are always consistent with the time zone that the user expects on the
corresponding client.
Date-related API
The following are the properties and methods in the Office JavaScript API that support date-related features.
Office.context.mailbox.item.dateTimeCreated and Each of these properties returns a If the item is created at 9 If the item creation time is
Office.context.mailbox.item.dateTimeModified JavaScript Date object. This Date AM UTC: 9 AM UTC:
value is UTC-correct, as shown in the
following example - myUTCDate has Office.mailbox.item. Office.mailbox.item.
the same value in an Outlook rich dateTimeCreated.getHours dateTimeCreated.getHours
client, Outlook on the web and mobile returns 4am EST. returns 4am EST.
devices.
If the item is modified at If the item is modified at
const myDate = 11 AM UTC: 11 AM UTC:
Office.mailbox.item.dateTimeCreated;
const myUTCDate = Office.mailbox.item. Office.mailbox.item.
Office.context.mailbox.displayNewAppointmentForm Each of the Start and End parameters If the start and end times If the start and end times
requires a JavaScript Date object. The for the appointment form for the appointment form
arguments should be UTC-correct are 9 AM UTC and 11 AM are 9 AM UTC and 11 AM
regardless of the time zone used in UTC, then you should UTC, then you should
the user interface of an Outlook rich ensure that the start and ensure that the start and
client, or Outlook on the web or end arguments are UTC- end arguments are UTC-
mobile devices. correct, which means: correct, which means:
start.getUTCHours start.getUTCHours
returns 9am UTC returns 9am UTC
end.getUTCHours end.getUTCHours
returns 11am UTC returns 11am UTC
These helper methods take care of any need to handle date or time differently for the following two date-related scenarios, in an
Outlook rich client, Outlook on the web and mobile devices, thus reinforcing "write-once" for different clients of your add-in.
JavaScript
Note that convertToLocalClientTime takes care of the difference between an Outlook rich client, and Outlook on the web or
mobile devices:
If convertToLocalClientTime detects the current application is a rich client, the method converts the Date representation to a
dictionary representation in the same client computer time zone, consistent with the rest of the rich client user interface.
If convertToLocalClientTime detects the current application is Outlook on the web or mobile devices, the method converts
the UTC-correct Date representation to a dictionary format in the EAC time zone, consistent with the rest of the Outlook on
the web or mobile devices user interface.
In the following example, assume myLocalDictionaryStartDate and myLocalDictionaryEndDate are date-time values in dictionary
format that you have obtained from the user. These values are based on the local time, dependent on the client platform.
JavaScript
The resultant values, myUTCCorrectStartDate and myUTCCorrectEndDate , are UTC-correct. Then pass these Date objects as
arguments for the Start and End parameters of the Mailbox.displayNewAppointmentForm method to display the new appointment
form.
Note that convertToUtcClientTime takes care of the difference between an Outlook rich client, and Outlook on the web or mobile
devices:
If convertToUtcClientTime detects the current application is an Outlook rich client, the method simply converts the dictionary
representation to a Date object. This Date object is UTC-correct, as expected by displayNewAppointmentForm .
If convertToUtcClientTime detects the current application is Outlook on the web or mobile devices, the method converts the
dictionary format of the date and time values expressed in the EAC time zone to a Date object. This Date object is UTC-
correct, as expected by displayNewAppointmentForm .
See also
Deploy and install Outlook add-ins for testing
Limits for activation and JavaScript API
for Outlook add-ins
Article • 07/05/2023
To provide a satisfactory experience for users of Outlook add-ins, you should be aware of
certain activation and API usage guidelines, and implement your add-ins to stay within
these limits. These guidelines exist so that an individual add-in cannot require Exchange
Server or Outlook to spend an unusually long period of time to process its activation rules
or calls to the Office JavaScript API, affecting the overall user experience for Outlook and
other add-ins. These limits apply to designing activation rules in the add-in manifest, and
using custom properties, roaming settings, recipients, Exchange Web Services (EWS)
requests and responses, and asynchronous calls.
7 Note
If your add-in runs on an Outlook rich client, you must also verify that the add-in
performs within certain runtime resource usage limits.
7 Note
Outlook Add-in features that depend on activation rules aren't supported when the
add-in uses a Unified manifest for Microsoft 365 (preview).
Follow these guidelines when designing activation rules for Outlook add-ins:
Limit the size of the manifest to 256 KB. You can't install the Outlook add-in for an
Exchange mailbox if you exceed that limit.
Specify up to 15 activation rules for the add-in. You can't install the add-in if you
exceed that limit.
If you use an ItemHasKnownEntity rule on the body of the selected item, expect an
Outlook rich client to apply the rule against only the first 1 MB of the body and not
to the rest of the body over that limit. Your add-in wouldn't activate if matches exist
only after the first MB of the body. If you expect that to be a likely scenario, re-
design your conditions for activation.
Table 1 lists the limits and describes the differences in the support for regular expressions
between an Outlook rich client and Outlook on the web or mobile devices. The support is
independent of any specific type of device and item body.
Uses the C++ regular expression engine Uses regular expression evaluation that is part
provided as part of the Visual Studio standard of JavaScript, is provided by the browser, and
template library. This engine complies with supports a superset of ECMAScript 5.
ECMAScript 5 standards.
Outlook rich client Outlook on the web or mobile devices
Because of the different regex engines, expect a You should test each regex thoroughly on each
regex that includes a custom character class Outlook client, and if a regex returns different
based on predefined character classes to return results, rewrite the regex.
different results in an Outlook rich client than in
Outlook on the web or mobile devices.
By default, limits the evaluation of all regular Don't support the same resource monitoring or
expressions for an add-in to 1 second. Exceeding registry settings as in an Outlook rich client.
this limit causes reevaluation of up to 3 times. However, add-ins with regular expressions that
Beyond the reevaluation limit, an Outlook rich require excessive amount of evaluation time on
client disables the add-in from running for the an Outlook rich client are disabled for the same
same mailbox in any of the Outlook clients. mailbox on all the Outlook clients.
Table 2 lists the limits and describes the differences in the portion of the item body that
the each of the Outlook applies a regular expression. Some of these limits depend on the
type of device and item body, if the regular expression is applied on the item body.
Plain Applies the regex on the first 1 MB of the Activates the add-in only Activates the
text data of the body, but not on the rest of the if the body < 16,000 add-in only if
item body over that limit. characters. the body <
body 500,000
characters.
HTML Applies the regex on the first 512 KB of the Applies the regex on the Activates the
item data of the body, but not on the rest of the first 64,000 characters add-in only if
body body over that limit. (The actual number of (including HTML tag the body <
characters depends on the encoding which characters), but not on 500,000
can range from 1 to 4 bytes per character.) the rest of the body over characters.
that limit.
Table 3 lists the limits and describes the differences in the matches that each Outlook
client returns after evaluating a regular expression. The support is independent of any
specific type of device, but may depend on the type of item body, if the regular
expression is applied on the item body.
Order of Assume getRegExMatches returns matches for the same Assume getRegExMatches
returned regular expression applied on the same item to be returns matches in
matches different in an Outlook rich client than in Outlook on the different order in an
web or mobile devices. Outlook rich client than in
Outlook on the web or
mobile devices.
Plain getRegExMatches returns any matches that are up to 1,536 getRegExMatches returns
text (1.5 KB) characters, for a maximum of 50 matches. any matches that are up
item to 3,072 (3 KB) characters,
body Note: getRegExMatches doesn't return matches in any for a maximum of 50
specific order in the returned array. In general, assume the matches.
order of matches in an Outlook rich client for the same
regular expression applied on the same item is different
from that in Outlook on the web and mobile devices.
Outlook rich client Outlook on the web or
mobile devices
HTML getRegExMatches returns any matches that are up to 3,072 getRegExMatches returns
item (3 KB) characters, for a maximum of 50 matches. any matches that are up
body to 3,072 (3 KB) characters,
Note: getRegExMatches does not return matches in any for a maximum of 50
specific order in the returned array. In general, assume the matches.
order of matches in an Outlook rich client for the same
regular expression applied on the same item is different
from that in Outlook on the web and mobile devices.
Table 4. Limits to get or set certain data using the Office JavaScript API
Internet 256 KB per InternetHeaders.setAsync method The total size limit of headers
headers message in that can be applied to a
Exchange message.
Online
Header size
limit
determined
by the
organization's
administrators
in Exchange
on-premises
Extract well- 2,000 number Item.getEntities method Limit for Exchange Server to
known of characters extract well-known entities
entities Item.getEntitiesByType method on the item body. Exchange
Server ignores entities
Item.getFilteredEntitiesByName method beyond that limit. Note that
this limit is independent of
whether the add-in uses an
ItemHasKnownEntity rule.
Recipients.addAsync method
Recipients.getAsync method
Recipients.setAsync method
Feature Limit Related API Description
Item.requiredAttendees property
Item.optionalAttendees property
Item.to property
Item.cc property
Set the 255 Location.setAsync method Limit for setting the location
location characters of an appointment or
meeting request.
Set the body 1 MB number Body.prependAsync method Limit for setting the body of
of characters an appointment or message
Body.setAsync item.
Body.setSelectedDataAsync method
Number of 499 files on Item.addFileAttachmentAsync method Limit for the number of files
attachments Outlook on that can be attached to an
the web and item for sending. Outlook on
mobile the web and mobile devices
devices generally limit attaching up
to 499 files, through the user
interface and
addFileAttachmentAsync . An
Outlook rich client does not
specifically limit the number
of file attachments. However,
all Outlook clients observe
the limit for the size of
attachments that user's
Exchange Server has been
configured with. See the next
row for "Size of
attachments".
Body.prependAsync method
Body.setSelectedDataAsync method
CustomProperties.saveAsync method
Item.LoadCustomPropertiesAsync method
Location.getAsync method
Location.setAsync method
Mailbox.getCallbackTokenAsync method
Mailbox.getUserIdentityTokenAsync
method
Mailbox.makeEwsRequestAsync method
Recipients.addAsync method
Recipients.getAsync method
Recipients.setAsync method
RoamingSettings.saveAsync method
Subject.getAsync method
Subject.setAsync method
Time.getAsync method
Time.setAsync method
Feature Limit Related API Description
See also
Deploy and install Outlook add-ins for testing
Privacy, permissions, and security for Outlook add-ins
Troubleshoot Outlook add-in activation
Article • 03/21/2023
Outlook contextual add-in activation is based on the activation rules in an XML manifest
for the add-in. When conditions for the currently selected item satisfy the activation
rules for the add-in, the application activates and displays the add-in button in the
Outlook UI (add-in selection pane for compose add-ins, add-in bar for read add-ins).
However, if your add-in doesn't activate as you expect, you should look into the
following areas for possible reasons.
7 Note
Outlook Add-in features that depend on activation rules aren't supported when the
add-in uses a Unified manifest for Microsoft 365 (preview).
You can verify the version of Exchange 2013 by using one of the following approaches.
If you are testing the add-in on Outlook on the web or mobile devices, in a script
debugger (for example, the JScript Debugger that comes with Internet Explorer),
look for the src attribute of the script tag that specifies the location from which
scripts are loaded. The path should contain a substring owa/15.0.516.x/owa2/...,
where 15.0.516.x represents the version of the Exchange Server, such as 15.0.516.2.
If you can test the add-in on Outlook, you can use the following simple debugging
technique that uses the Outlook object model and Visual Basic Editor.
1. First, verify that macros are enabled for Outlook. Choose File, Options, Trust
Center, Trust Center Settings, Macro Settings. Ensure that Notifications for
all macros is selected in the Trust Center. You should have also selected
Enable Macros during Outlook startup.
7 Note
Not seeing the Developer tab? See How to: Show the Developer Tab on
the Ribbon to turn it on.
4. Type the following in the Immediate window to display the version of the
Exchange Server. The major version of the returned value must be equal to or
greater than 15.
If there is only one Exchange account in the user's profile:
VB
?Session.ExchangeMailboxServerVersion
VB
?Session.Accounts.Item(emailAddress).ExchangeMailboxServerVersion
7 Note
Only Outlook rich clients monitor resource usage, but disabling an add-in in an
Outlook rich client also disables the add-in in Outlook on the web and mobile
devices.
In Outlook on the web, select Get Add-ins from the ribbon. To learn more, see
Using add-ins in Outlook on the web .
Even if a mail item is not one of the above types, if the item wasn't delivered by a
version of Exchange Server that's at least Exchange 2013, known entities and properties,
such as sender's SMTP address, wouldn't be identified on the item. Any activation rules
that rely on these entities or properties wouldn't be satisfied, and the add-in wouldn't
be activated.
In Outlook on clients besides Windows, if your add-in activates when the user is
composing a message or meeting request, make sure the item isn't protected by
Information Rights Management (IRM).
) Important
text
%LocalAppData%\Microsoft\Office\16.0\WEF
) Important
For Outlook 2013 on Windows, use 15.0 instead of 16.0 so the location would be:
text
%LocalAppData%\Microsoft\Office\15.0\WEF
If an add-in does not activate for any items, the manifest might not have been installed
properly on the Exchange Server, or Outlook has not read the manifest properly on
startup. Using the Exchange Admin Center, ensure that the add-in is installed and
enabled for your mailbox, and reboot the Exchange Server, if necessary.
Figure 1 shows a summary of the steps to verify whether Outlook has a valid version of
the manifest.
Figure 1. Flow chart of the steps to verify whether Outlook properly cached the
manifest
1. If you have modified the manifest while Outlook is open, and you are not using
Visual Studio 2012 or a later version of Visual Studio to develop the add-in, you
should uninstall the add-in and reinstall it using the Exchange Admin Center.
2. Restart Outlook and test whether Outlook now activates the add-in.
3. If Outlook doesn't activate the add-in, check whether Outlook has a properly
cached copy of the manifest for the add-in. Look under the following path.
text
%LocalAppData%\Microsoft\Office\16.0\WEF
text
7 Note
text
C:\Users\john\appdata\Local\Microsoft\Office\16.0\WEF\{8D8445A4-
80E4-4D6B-B7AC-
D4E6AF594E73}\GoRshCWa7vW8+jhKmyiDhA==\Manifests\b3d7d9d5-6f57-
437d-9830-94e2aaccef16_1.2
Verify whether the manifest of the add-in you're testing is among the cached
manifests.
4. If the manifest is in the cache, skip the rest of this section and consider the other
possible reasons following this section.
5. If the manifest is not in the cache, check whether Outlook indeed successfully read
the manifest from the Exchange Server. To do that, use the Windows Event Viewer:
b. Look for a reasonably recent event for which the Event ID equals 63, which
represents Outlook downloading a manifest from an Exchange Server.
c. If Outlook successfully read a manifest, the logged event should have the
following description.
text
6. If you don't see a successful event, close Outlook, and delete all the manifests in
the following path.
text
Start Outlook and test whether Outlook now activates the add-in.
7. If Outlook doesn't activate the add-in, go back to Step 3 to verify again whether
Outlook has properly read the manifest.
While in most cases, these Outlook clients find the same matches for the same regular
expression in an activation rule, there are exceptions. For instance, if the regex includes a
custom character class based on predefined character classes, an Outlook rich client
may return results different from Outlook on the web and mobile devices. As an
example, character classes that contain shorthand character classes [\d\w] within them
would return different results. In this case, to avoid different results on different
applications, use (\d|\w) instead.
Test your regular expression thoroughly. If it returns different results, rewrite the regular
expression for compatibility with both engines. To verify evaluation results on an
Outlook rich client, write a small C++ program that applies the regular expression
against a sample of the text you are trying to match. Running on Visual Studio, the C++
test program would use the standard template library, simulating the behavior of the
Outlook rich client when running the same regular expression. To verify evaluation
results on Outlook on the web or mobile devices, use your favorite JavaScript regular
expression tester.
If you use an ItemIs, ItemHasAttachment, or
ItemHasRegularExpressionMatch rule, have you
verified the related item property?
If you use an ItemHasRegularExpressionMatch activation rule, verify whether the value
of the PropertyName attribute is what you expect for the selected item. The following
are some tips to debug the corresponding properties.
1. Ensure that macros are enabled and the Developer tab is displayed on the
ribbon for Outlook.
VB
?ActiveExplorer.Selection.Item(1).HTMLBody
The plain text body of the message or appointment item selected in the
Outlook explorer:
VB
?ActiveExplorer.Selection.Item(1).Body
VB
?ActiveInspector.CurrentItem.HTMLBody
The plain text body of the message or appointment item opened in the
current Outlook inspector:
VB
?ActiveInspector.CurrentItem.Body
ItemIs PidTagMessageClass
ItemHasAttachment PidTagHasAttachments
After verifying the property value, you can then use a regular expression evaluation tool
to test whether the regular expression finds a match in that value.
The size of the item body evaluated -- There are limits to the portion of an item
body on which Outlook evaluates a regular expression. These limits depend on the
Outlook client, form factor, and format of the item body. See the details in Table 2
in Limits for activation and JavaScript API for Outlook add-ins.
Number of regular expression matches -- The Outlook rich clients, and Outlook on
the web and mobile devices each returns a maximum of 50 regular expression
matches. These matches are unique, and duplicate matches do not count against
this limit. Do not assume any order to the returned matches, and do not assume
the order in an Outlook rich client is the same as that in Outlook on the web and
mobile devices. If you expect many matches to regular expressions in your
activation rules, and you're missing a match, you may be exceeding this limit.
Length of a regular expression match -- There are limits to the length of a regular
expression match that the Outlook application would return. Outlook does not
include any match above the limit and does not display any warning message. You
can run your regular expression using other regex evaluation tools or a stand-
alone C++ test program to verify whether you have a match that exceeds such
limits. Table 3 summarizes the limits. For more information, see Table 3 in Limits for
activation and JavaScript API for Outlook add-ins.
Time spent on evaluating all regular expressions of a read add-in for an Outlook
rich client: By default, for each read add-in, Outlook must finish evaluating all the
regular expressions in its activation rules within 1 second. Otherwise Outlook
retries up to three times and disables the add-in if Outlook cannot complete the
evaluation. Outlook displays a message in the notification bar that the add-in has
been disabled. The amount of time available for your regular expression can be
modified by setting a group policy or a registry key.
7 Note
If the Outlook rich client disables a read add-in, the read add-in is not
available for use for the same mailbox on the Outlook rich client, and Outlook
on the web and mobile devices.
See also
Deploy and install Outlook add-ins for testing
Activation rules for Outlook add-ins
Use regular expression activation rules to show an Outlook add-in
Limits for activation and JavaScript API for Outlook add-ins
Validate and troubleshoot issues with your manifest
Debug function commands in Outlook
add-ins
Article • 07/05/2023
7 Note
This article describes how to use the Office Add-in Debugger Extension in Visual Studio
Code to debug function commands. Function commands are initiated through an add-in
command button on the ribbon. For more information about add-in commands, see
Add-in commands.
This article assumes that you already have an add-in project that you'd like to debug. To
create an add-in with a function command to practice debugging, follow the steps in
Tutorial: Build a message compose Outlook add-in.
Otherwise, if you used another tool to create your add-in, perform the following steps.
1. Navigate to the
HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\16.0\WEF\Developer\[Add-in ID]
registry key. Replace [Add-in ID] with the <Id> from your add-in's manifest.
7 Note
If your add-in runs in the embedded webview control from Edge Legacy
(EdgeHTML), see Microsoft Office Add-in Debugger Extension for Visual Studio
Code.
If your add-in runs in the embedded webview control from Microsoft Edge
Chromium (WebView2), see Debug add-ins on Windows using Visual Studio Code
and Microsoft Edge WebView2 (Chromium-based).
See also
Add-in commands
Overview of debugging Office Add-ins
Debug your event-based Outlook add-in
Debug your event-based Outlook add-in
Article • 06/29/2023
This article discusses the key debugging stages to enable and set breakpoints in your
code as you implement event-based activation in your add-in. The event-based
activation feature was introduced in requirement set 1.10, with additional events now
available in subsequent requirement sets. For more information, see Supported events.
Before you proceed, review the event-based troubleshooting guide for additional
guidance.
Windows
If you used the Yeoman generator for Office Add-ins to create your add-in project
(for example, by doing the event-based activation walkthrough), follow the Created
with Yeoman generator option throughout this article. Otherwise, follow the Other
steps. Visual Studio Code should be at least version 1.56.1.
manifest.
XML manifest: Use the value of the <Id> element child of the root
<OfficeApp> element.
Unified manifest for Microsoft 365 (preview): Use the value of the "id"
property of the root anonymous { ... } object.
7 Note
command line
npm start
In addition to building the code and starting the local server, this command
sets the UseDirectDebugger registry key for this add-in to 1 .
ID]\ . Replace [Add-in ID] with your add-in's ID from the manifest. Set the
registry key to 1 .
4. Perform the action to initiate the event you're developing for, such as creating
a new message to initiate the OnNewMessageCompose event. The Debug Event-
based handler dialog should appear. Do not interact with the dialog yet.
Configure Visual Studio Code
command line
code .
2. In Visual Studio Code, open the ./.vscode/launch.json file and add the
following excerpt to your list of configurations. Save your changes.
JSON
{
"name": "Direct Debugging",
"type": "node",
"request": "attach",
"port": 9223,
"timeout": 600000,
"trace": true
}
Other
1. Create a new folder called Debugging (perhaps in your Desktop folder).
3. Go to File > Open Folder, navigate to the folder you just created, then choose
Select Folder.
7. Add the following excerpt to your list of configurations. Save your changes.
JSON
{
"name": "Direct Debugging",
"type": "node",
"request": "attach",
"port": 9223,
"timeout": 600000,
"trace": true
}
text
Tip
If the bundle.js file doesn't appear in the Wef folder, try the following:
4. In the DEBUG dropdown, select Direct Debugging, then select the Start
Debugging icon.
2. You can now hit your breakpoints in Visual Studio Code, enabling you to
debug your event-based activation code.
Stop the debugger
To stop debugging the rest of the current Outlook on Windows session, in the
Debug Event-based handler dialog, choose Cancel. To re-enable debugging, restart
Outlook.
To prevent the Debug Event-based handler dialog from popping up and stop
debugging for subsequent Outlook sessions, delete the associated registry key,
HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\16.0\Wef\Developer\[Add-in
See also
Configure your Outlook add-in for event-based activation
Event-based activation troubleshooting guide
Debug your add-in with runtime logging
PowerPoint add-ins documentation
With PowerPoint add-ins, you can use familiar web technologies such as HTML, CSS, and
JavaScript to build a solution that can run in PowerPoint across multiple platforms,
including on the web, Windows, Mac, and iPad. Learn how to build, test, debug, and
publish PowerPoint add-ins.
e OVERVIEW
f QUICKSTART
c HOW-TO GUIDE
e OVERVIEW
b GET STARTED
Resources
i REFERENCE
Ask questions
Request features
Report issues
You can use PowerPoint add-ins to build engaging solutions for your users'
presentations across platforms including Windows, iPad, Mac, and in a browser. You can
create two types of PowerPoint add-ins:
Use content add-ins to add dynamic HTML5 content to your presentations. For
example, see the LucidChart Diagrams for PowerPoint add-in, which you can use
to inject an interactive diagram from LucidChart into your deck.
Use task pane add-ins to bring in reference information or insert data into the
presentation via a service. For example, see the Pexels - Free Stock Photos add-
in, which you can use to add professional photos to your presentation.
Several of these examples also use a Globals object that is declared beyond the
scope of these functions as: var Globals = {activeViewHandler:0,
firstSlideId:0};
To use these examples, your add-in project must reference Office.js v1.1 library or
later.
7 Note
In PowerPoint on the web, the Document.ActiveViewChanged event will never fire
as Slide Show mode is treated as a new session. In this case, the add-in must fetch
the active view on load, as shown in the following code sample.
JavaScript
function getActiveFileView()
{
Office.context.document.getActiveViewAsync(function (asyncResult) {
if (asyncResult.status == "failed") {
app.showNotification("Action failed with error: " +
asyncResult.error.message);
}
else {
app.showNotification(asyncResult.value);
}
});
function registerActiveViewChanged() {
Globals.activeViewHandler = function (args) {
app.showNotification(JSON.stringify(args));
}
Office.context.document.addHandlerAsync(Office.EventType.ActiveViewChanged,
Globals.activeViewHandler,
function (asyncResult) {
if (asyncResult.status == "failed") {
app.showNotification("Action failed with error: " +
asyncResult.error.message);
}
else {
app.showNotification(asyncResult.status);
}
});
}
the ids, titles, and indexes of selected range of slides (or of the current slide, if multiple
slides are not selected). It also saves the id of the first slide in the selected range to a
global variable.
JavaScript
function getSelectedRange() {
// Get the id, title, and index of the current slide (or selected
slides) and store the first slide id */
Globals.firstSlideId = 0;
Office.context.document.getSelectedDataAsync(Office.CoercionType.SlideRange,
function (asyncResult) {
if (asyncResult.status == "failed") {
app.showNotification("Action failed with error: " +
asyncResult.error.message);
}
else {
Globals.firstSlideId = asyncResult.value.slides[0].id;
app.showNotification(JSON.stringify(asyncResult.value));
}
});
}
function goToFirstSlide() {
Office.context.document.goToByIdAsync(Globals.firstSlideId,
Office.GoToType.Slide, function (asyncResult) {
if (asyncResult.status == "failed") {
app.showNotification("Action failed with error: " +
asyncResult.error.message);
}
else {
app.showNotification("Navigation successful");
}
});
}
JavaScript
function goToSlideByIndex() {
const goToFirst = Office.Index.First;
const goToLast = Office.Index.Last;
const goToPrevious = Office.Index.Previous;
const goToNext = Office.Index.Next;
Office.context.document.goToByIdAsync(goToNext, Office.GoToType.Index,
function (asyncResult) {
if (asyncResult.status == "failed") {
app.showNotification("Action failed with error: " +
asyncResult.error.message);
}
else {
app.showNotification("Navigation successful");
}
});
}
JavaScript
function getFileUrl() {
//Get the URL of the current file.
Office.context.document.getFilePropertiesAsync(function (asyncResult) {
const fileUrl = asyncResult.value.url;
if (fileUrl == "") {
app.showNotification("The file hasn't been saved yet. Save the
file and try again");
}
else {
app.showNotification(fileUrl);
}
});
}
Create a presentation
Your add-in can create a new presentation, separate from the PowerPoint instance in
which the add-in is currently running. The PowerPoint namespace has the
createPresentation method for this purpose. When this method is called, the new
JavaScript
PowerPoint.createPresentation();
The createPresentation method can also create a copy of an existing presentation. The
method accepts a base64-encoded string representation of an .pptx file as an optional
parameter. The resulting presentation will be a copy of that file, assuming the string
argument is a valid .pptx file. The FileReader class can be used to convert a file into
the required base64-encoded string, as demonstrated in the following example.
JavaScript
PowerPoint.createPresentation(copyBase64);
};
// read in the file as a data URL so we can parse the base64-encoded string
reader.readAsDataURL(myFile.files[0]);
See also
Developing Office Add-ins
Learn about the Microsoft 365 Developer Program
PowerPoint Code Samples
How to save add-in state and settings per document for content and task pane
add-ins
Read and write data to the active selection in a document or spreadsheet
Get the whole document from an add-in for PowerPoint or Word
Use document themes in your PowerPoint add-ins
Build your first PowerPoint task pane
add-in
Article • 01/10/2023
In this article, you'll walk through the process of building a PowerPoint task pane add-in.
Yeoman generator
Prerequisites
7 Note
If you aren't familiar with Node.js or npm, you should start by setting up your
development environment.
The latest version of Yeoman and the Yeoman generator for Office Add-ins.
To install these tools globally, run the following command via the command
prompt.
command line
7 Note
command line
yo office
7 Note
When you run the yo office command, you may receive prompts about the
data collection policies of Yeoman and the Office Add-in CLI tools. Use the
information that's provided to respond to the prompts as you see fit.
When prompted, provide the following information to create your add-in project.
After you complete the wizard, the generator creates the project and installs
supporting Node components.
Tip
You can ignore the next steps guidance that the Yeoman generator provides
after the add-in project's been created. The step-by-step instructions within
this article provide all of the guidance you'll need to complete this tutorial.
The ./manifest.xml file in the root directory of the project defines the settings
and capabilities of the add-in. To learn more about the manifest.xml file, see
Office Add-ins XML manifest.
The ./src/taskpane/taskpane.html file contains the HTML markup for the task
pane.
The ./src/taskpane/taskpane.css file contains the CSS that's applied to
content in the task pane.
The ./src/taskpane/taskpane.js file contains the Office JavaScript API code
that facilitates interaction between the task pane and the Office client
application.
Try it out
1. Navigate to the root folder of the project.
command line
2. Complete the following steps to start the local web server and sideload your
add-in.
7 Note
Office Add-ins should use HTTPS, not HTTP, even while you're
developing. If you're prompted to install a certificate after you run one of
the following commands, accept the prompt to install the certificate that
the Yeoman generator provides. You may also have to run your command
prompt or terminal as an administrator for the changes to be made.
Tip
If you're testing your add-in on Mac, run the following command before
proceeding. When you run this command, the local web server starts.
command line
command line
npm start
7 Note
command line
https://contoso.sharepoint.com/:t:/g/EZGxP7ksiE5DuxvY638G798Bpuhwl
uxCMfF1WZQj3VYhYQ?e=F4QM1R
e=RSccmNP
If your add-in doesn't sideload in the document, manually sideload it by
following the instructions in Manually sideload add-ins to Office on the
web.
3. In PowerPoint, insert a new blank slide, choose the Home tab, and then
choose the Show Taskpane button on the ribbon to open the add-in task
pane.
4. At the bottom of the task pane, choose the Run link to insert the text "Hello
World" into the current slide.
Next steps
Congratulations, you've successfully created a PowerPoint task pane add-in! Next,
learn more about the capabilities of a PowerPoint add-in and build a more complex
add-in by following along with the PowerPoint add-in tutorial.
See also
Office Add-ins platform overview
Develop Office Add-ins
Using Visual Studio Code to publish
Tutorial: Create a PowerPoint task pane
add-in
Article • 04/04/2023
In this tutorial, you'll use Visual Studio to create an PowerPoint task pane add-in that:
Prerequisites
Visual Studio 2019, version 16.10.3 or earlier, or Visual Studio 2022 , with the
Office/SharePoint development workload installed.
) Important
Some versions of Visual Studio 2019 after 16.10.3 have a bug that prevents
this tutorial from being completed. Use an earlier version of Visual Studio
2019 or use Visual Studio 2022.
7 Note
If you've previously installed Visual Studio, use the Visual Studio Installer to
ensure that the Office/SharePoint development workload is installed.
7 Note
If you don't already have Office, you can join the Microsoft 365 developer
program to get a free, 90-day renewable Microsoft 365 subscription to use
during development.
2. Using the search box, enter add-in. Choose PowerPoint Web Add-in, then select
Next.
4. In the Create Office Add-in dialog window, choose Add new functionalities to
PowerPoint, and then choose Finish to create the project.
5. Visual Studio creates a solution and its two projects appear in Solution Explorer.
The Home.html file opens in Visual Studio.
6. The following NuGet packages must be installed. Install them using the NuGet
Package Manager in Visual Studio. See Visual Studio help for instructions. The
second of these may be installed automatically when you install the first.
Microsoft.AspNet.WebApi.WebHost
Microsoft.AspNet.WebApi.Core
) Important
When you're using the NuGet Package Manager to install these packages, do
not install the recommended update to jQuery. The jQuery version installed
with your Visual Studio solution matches the jQuery call within the solution
files.
Project Description
Add-in Contains only an XML manifest file, which contains all the settings that describe
project your add-in. These settings help the Office application determine when your add-
in should be activated and where the add-in should appear. Visual Studio
generates the contents of this file for you so that you can run the project and use
your add-in immediately. You change these settings any time by modifying the
XML file.
Web Contains the content pages of your add-in, including all the files and file
application references that you need to develop Office-aware HTML and JavaScript pages.
project While you develop your add-in, Visual Studio hosts the web application on your
local IIS server. When you're ready to publish the add-in, you'll need to deploy
this web application project to a web server.
Update code
Edit the add-in code as follows to create the framework that you'll use to implement
add-in functionality in subsequent steps of this tutorial.
1. Home.html specifies the HTML that will be rendered in the add-in's task pane. In
Home.html, find the div with id="content-main" , replace that entire div with the
following markup, and save the file.
HTML
JavaScript
(function () {
"use strict";
let messageBanner;
Office.onReady(function () {
$(document).ready(function () {
// Initialize the FabricUI notification mechanism and hide
it
const element = document.querySelector('.MessageBanner');
messageBanner = new components.MessageBanner(element);
messageBanner.hideBanner();
Insert an image
Complete the following steps to add code that retrieves the Bing photo of the day
and inserts that image into a slide.
2. Right-click the Controllers folder and select Add > New Scaffolded Item....
3. In the Add Scaffold dialog window, select Web API 2 Controller - Empty and
choose the Add button.
7 Note
5. Replace the entire contents of the PhotoController.cs file with the following code
that calls the Bing service to retrieve the photo of the day as a Base64 encoded
string. When you use the Office JavaScript API to insert an image into a document,
the image data must be specified as a Base64 encoded string.
C#
using System;
using System.IO;
using System.Net;
using System.Text;
using System.Web.Http;
using System.Xml;
namespace HelloWorldWeb.Controllers
{
public class PhotoController : ApiController
{
public string Get()
{
string url = "http://www.bing.com/HPImageArchive.aspx?
format=xml&idx=0&n=1";
6. In the Home.html file, replace TODO1 with the following markup. This markup
defines the Insert Image button that will appear within the add-in's task pane.
HTML
7. In the Home.js file, replace TODO1 with the following code to assign the event
handler for the Insert Image button.
JavaScript
$('#insert-image').click(insertImage);
8. In the Home.js file, replace TODO2 with the following code to define the
insertImage function. This function fetches the image from the Bing web service
and then calls the insertImageFromBase64String function to insert that image into
the document.
JavaScript
function insertImage() {
// Get image from from web service (as a Base64 encoded string).
$.ajax({
url: "/api/Photo/", success: function (result) {
insertImageFromBase64String(result);
}, error: function (xhr, status, error) {
showNotification("Error", "Oops, something went wrong.");
}
});
}
9. In the Home.js file, replace TODO3 with the following code to define the
insertImageFromBase64String function. This function uses the Office JavaScript API
JavaScript
function insertImageFromBase64String(image) {
// Call Office.js to insert the image into the document.
Office.context.document.setSelectedDataAsync(image, {
coercionType: Office.CoercionType.Image
},
function (asyncResult) {
if (asyncResult.status === Office.AsyncResultStatus.Failed)
{
showNotification("Error", asyncResult.error.message);
}
});
}
2. In PowerPoint, select the Show Taskpane button on the ribbon to open the add-in
task pane.
3. In the task pane, choose the Insert Image button to add the Bing photo of the day
to the current slide.
4. In Visual Studio, stop the add-in by pressing Shift + F5 or choosing the Stop
button. PowerPoint will automatically close when the add-in is stopped.
1. In the Home.html file, replace TODO2 with the following markup to add a header
section and title to the task pane. Note:
The styles that begin with ms- are defined by Fabric Core in Office Add-ins, a
JavaScript front-end framework for building user experiences for Office. The
Home.html file includes a reference to the Fabric Core stylesheet.
HTML
<div id="content-header">
<div class="ms-Grid ms-bgColor-neutralPrimary">
<div class="ms-Grid-row">
<div class="padding ms-Grid-col ms-u-sm12 ms-u-md12 ms-u-
lg12"> <div class="ms-font-xl ms-fontColor-white ms-fontWeight-
semibold">My PowerPoint add-in</div></div>
</div>
</div>
</div>
2. In the Home.html file, find the div with class="footer" and delete that entire div
to remove the footer section from the task pane.
2. In PowerPoint, select the Show Taskpane button on the ribbon to open the add-in
task pane.
3. Notice that the task pane now contains a header section and title, and no longer
contains a footer section.
4. In Visual Studio, stop the add-in by pressing Shift + F5 or choosing the Stop
button. PowerPoint will automatically close when the add-in is stopped.
Insert text
Complete the following steps to add code that inserts text into the title slide which
contains the Bing photo of the day.
1. In the Home.html file, replace TODO3 with the following markup. This markup
defines the Insert Text button that will appear within the add-in's task pane.
HTML
2. In the Home.js file, replace TODO4 with the following code to assign the event
handler for the Insert Text button.
JavaScript
$('#insert-text').click(insertText);
3. In the Home.js file, replace TODO5 with the following code to define the insertText
function. This function inserts text into the current slide.
JavaScript
function insertText() {
Office.context.document.setSelectedDataAsync('Hello World!',
function (asyncResult) {
if (asyncResult.status === Office.AsyncResultStatus.Failed)
{
showNotification("Error", asyncResult.error.message);
}
});
}
2. In PowerPoint, select the Show Taskpane button on the ribbon to open the add-in
task pane.
3. In the task pane, choose the Insert Image button to add the Bing photo of the day
to the current slide and choose a design for the slide that contains a text box for
the title.
4. Put your cursor in the text box on the title slide and then in the task pane, choose
the Insert Text button to add text to the slide.
5. In Visual Studio, stop the add-in by pressing Shift + F5 or choosing the Stop
button. PowerPoint will automatically close when the add-in is stopped.
1. In the Home.html file, replace TODO4 with the following markup. This markup
defines the Get Slide Metadata button that will appear within the add-in's task
pane.
HTML
2. In the Home.js file, replace TODO6 with the following code to assign the event
handler for the Get Slide Metadata button.
JavaScript
$('#get-slide-metadata').click(getSlideMetadata);
3. In the Home.js file, replace TODO7 with the following code to define the
getSlideMetadata function. This function retrieves metadata for the selected
slide(s) and writes it to a popup dialog window within the add-in task pane.
JavaScript
function getSlideMetadata() {
Office.context.document.getSelectedDataAsync(Office.CoercionType.SlideR
ange,
function (asyncResult) {
if (asyncResult.status === Office.AsyncResultStatus.Failed)
{
showNotification("Error", asyncResult.error.message);
} else {
showNotification("Metadata for selected slide(s):",
JSON.stringify(asyncResult.value), null, 2);
}
}
);
}
2. In PowerPoint, select the Show Taskpane button on the ribbon to open the add-in
task pane.
3. In the task pane, choose the Get Slide Metadata button to get the metadata for
the selected slide. The slide metadata is written to the popup dialog window at the
bottom of the task pane. In this case, the slides array within the JSON metadata
contains one object that specifies the id , title , and index of the selected slide. If
multiple slides had been selected when you retrieved slide metadata, the slides
array within the JSON metadata would contain one object for each selected slide.
4. In Visual Studio, stop the add-in by pressing Shift + F5 or choosing the Stop
button. PowerPoint will automatically close when the add-in is stopped.
1. In the Home.html file, replace TODO5 with the following markup. This markup
defines the four navigation buttons that will appear within the add-in's task pane.
HTML
2. In the Home.js file, replace TODO8 with the following code to assign the event
handlers for the four navigation buttons.
JavaScript
$('#go-to-first-slide').click(goToFirstSlide);
$('#go-to-next-slide').click(goToNextSlide);
$('#go-to-previous-slide').click(goToPreviousSlide);
$('#go-to-last-slide').click(goToLastSlide);
3. In the Home.js file, replace TODO9 with the following code to define the navigation
functions. Each of these functions uses the goToByIdAsync method to select a slide
based upon its position in the document (first, last, previous, and next).
JavaScript
function goToFirstSlide() {
Office.context.document.goToByIdAsync(Office.Index.First,
Office.GoToType.Index,
function (asyncResult) {
if (asyncResult.status == "failed") {
showNotification("Error", asyncResult.error.message);
}
});
}
function goToLastSlide() {
Office.context.document.goToByIdAsync(Office.Index.Last,
Office.GoToType.Index,
function (asyncResult) {
if (asyncResult.status == "failed") {
showNotification("Error", asyncResult.error.message);
}
});
}
function goToPreviousSlide() {
Office.context.document.goToByIdAsync(Office.Index.Previous,
Office.GoToType.Index,
function (asyncResult) {
if (asyncResult.status == "failed") {
showNotification("Error", asyncResult.error.message);
}
});
}
function goToNextSlide() {
Office.context.document.goToByIdAsync(Office.Index.Next,
Office.GoToType.Index,
function (asyncResult) {
if (asyncResult.status == "failed") {
showNotification("Error", asyncResult.error.message);
}
});
}
2. In PowerPoint, select the Show Taskpane button on the ribbon to open the add-in
task pane.
3. Use the New Slide button on the ribbon of the Home tab to add two new slides to
the document.
4. In the task pane, choose the Go to First Slide button. The first slide in the
document is selected and displayed.
5. In the task pane, choose the Go to Next Slide button. The next slide in the
document is selected and displayed.
6. In the task pane, choose the Go to Previous Slide button. The previous slide in the
document is selected and displayed.
7. In the task pane, choose the Go to Last Slide button. The last slide in the
document is selected and displayed.
8. In Visual Studio, stop the add-in by pressing Shift + F5 or choosing the Stop
button. PowerPoint will automatically close when the add-in is stopped.
Next steps
In this tutorial, you've created a PowerPoint add-in that inserts an image, inserts text,
gets slide metadata, and navigates between slides. To learn more about building
PowerPoint add-ins, continue to the following article.
See also
Office Add-ins platform overview
Develop Office Add-ins
JavaScript API for PowerPoint
Article • 05/02/2023
A PowerPoint add-in interacts with objects in PowerPoint by using the Office JavaScript
API, which includes two JavaScript object models:
Common APIs: Introduced with Office 2013, the Common API can be used to
access features such as UI, dialogs, and client settings that are common across
multiple types of Office applications.
For detailed information about the PowerPoint JavaScript API object model, see the
PowerPoint JavaScript API reference documentation.
See also
PowerPoint add-ins documentation
PowerPoint add-ins overview
PowerPoint JavaScript API reference
Office client application and platform availability for Office Add-ins
API Reference documentation
powerpoint package
Reference
Classes
PowerPoint.Application
PowerPoint.Presentation
Interfaces
PowerPoint.Interfaces.Bullet An interface describing the data returned by calling
FormatData bulletFormat.toJSON() .
PowerPoint.Interfaces.PresentationLoadOptions
PowerPoint.Interfaces.Shape An interface for updating data on the ShapeFill object, for use in
FillUpdateData shapeFill.set({ ... }) .
PowerPoint.Interfaces.Shape An interface for updating data on the ShapeFont object, for use
FontUpdateData in shapeFont.set({ ... }) .
PowerPoint.Interfaces.Shape An interface for updating data on the Shape object, for use in
UpdateData shape.set({ ... }) .
PowerPoint.Interfaces.Tag An interface for updating data on the Tag object, for use in
UpdateData tag.set({ ... }) .
PowerPoint.Interfaces.Text An interface for updating data on the TextFrame object, for use
FrameUpdateData in textFrame.set({ ... }) .
PowerPoint.Interfaces.Text An interface for updating data on the TextRange object, for use
RangeUpdateData in textRange.set({ ... }) .
Enums
PowerPoint.ErrorCodes
Functions
PowerPoint.create Creates and opens a new presentation. Optionally, the
Presentation(base64File) presentation can be pre-populated with a base64-encoded .pptx
file.
PowerPoint.run(object, batch) Executes a batch script that performs actions on the PowerPoint
object model, using the RequestContext of a previously-created
API object. When the promise is resolved, any tracked objects
that were automatically allocated during execution will be
released.
PowerPoint.run(objects, batch) Executes a batch script that performs actions on the PowerPoint
object model, using the RequestContext of previously-created
API objects.
Function Details
PowerPoint.createPresentation(base64File)
Creates and opens a new presentation. Optionally, the presentation can be pre-
populated with a base64-encoded .pptx file.
TypeScript
Parameters
base64File string
Optional. The base64-encoded .pptx file. The default value is null.
Returns
Promise<void>
Examples
TypeScript
PowerPoint.createPresentation(copyBase64);
};
PowerPoint.run(batch)
Executes a batch script that performs actions on the PowerPoint object model, using
a new RequestContext. When the promise is resolved, any tracked objects that were
automatically allocated during execution will be released.
TypeScript
Parameters
batch (context: PowerPoint.RequestContext) => OfficeExtension.IPromise<T>
A function that takes in a RequestContext and returns a promise (typically, just the
result of "context.sync()"). The context parameter facilitates requests to the
PowerPoint application. Since the Office add-in and the PowerPoint application run
in two different processes, the RequestContext is required to get access to the
PowerPoint object model from the add-in.
Returns
OfficeExtension.IPromise<T>
PowerPoint.run(object, batch)
Executes a batch script that performs actions on the PowerPoint object model, using
the RequestContext of a previously-created API object. When the promise is
resolved, any tracked objects that were automatically allocated during execution will
be released.
TypeScript
export function run<T>(object: OfficeExtension.ClientObject, batch:
(context: PowerPoint.RequestContext) => OfficeExtension.IPromise<T>):
OfficeExtension.IPromise<T>;
Parameters
object OfficeExtension.ClientObject
A previously-created API object. The batch will use the same RequestContext as the
passed-in object, which means that any changes applied to the object will be picked
up by "context.sync()".
Returns
OfficeExtension.IPromise<T>
PowerPoint.run(objects, batch)
Executes a batch script that performs actions on the PowerPoint object model, using
the RequestContext of previously-created API objects.
TypeScript
Parameters
objects OfficeExtension.ClientObject[]
An array of previously-created API objects. The array will be validated to make sure
that all of the objects share the same context. The batch will use this shared
RequestContext, which means that any changes applied to these objects will be
picked up by "context.sync()".
batch (context: PowerPoint.RequestContext) => OfficeExtension.IPromise<T>
A function that takes in a RequestContext and returns a promise (typically, just the
result of "context.sync()"). The context parameter facilitates requests to the
PowerPoint application. Since the Office add-in and the PowerPoint application run
in two different processes, the RequestContext is required to get access to the
PowerPoint object model from the add-in.
Returns
OfficeExtension.IPromise<T>
Add and delete slides in PowerPoint
Article • 07/21/2022
A PowerPoint add-in can add slides to the presentation and optionally specify which
slide master, and which layout of the master, is used for the new slide. The add-in can
also delete slides.
The APIs for adding slides are primarily used in scenarios where the IDs of the slide
masters and layouts in the presentation are known at coding time or can be found in a
data source at runtime. In such a scenario, either you or the customer must create and
maintain a data source that correlates the selection criterion (such as the names or
images of slide masters and layouts) with the IDs of the slide masters and layouts. The
APIs can also be used in scenarios where the user can insert slides that use the default
slide master and the master's default layout, and in scenarios where the user can select
an existing slide and create a new one with the same slide master and layout (but not
the same content). See Selecting which slide master and layout to use for more
information about this.
JavaScript
await context.sync();
});
}
JavaScript
await context.sync();
});
}
There is no practical way that users can discover the ID or creation ID of a slide master
or layout. For this reason, you can really only use the AddSlideOptions parameter when
either you know the IDs at coding time or your add-in can discover them at runtime.
Because users can't be expected to memorize the IDs, you also need a way to enable the
user to select slides, perhaps by name or by an image, and then correlate each title or
image with the slide's ID.
1. Create a function to get the index of the selected slide. The following is an
example. About this code, note:
JavaScript
function getSelectedSlideIndex() {
return new OfficeExtension.Promise<number>(function(resolve,
reject) {
Office.context.document.getSelectedDataAsync(Office.CoercionType.SlideR
ange, function(asyncResult) {
try {
if (asyncResult.status ===
Office.AsyncResultStatus.Failed) {
reject(console.error(asyncResult.error.message));
} else {
resolve(asyncResult.value.slides[0].index);
}
}
catch (error) {
reject(console.log(error));
}
});
});
}
2. Call your new function inside the PowerPoint.run() of the main function that adds
the slide. The following is an example.
JavaScript
await context.sync();
context.presentation.slides.add({
slideMasterId: selectedSlide.slideMaster.id,
layoutId: selectedSlide.layout.id
});
await context.sync();
});
}
Delete slides
Delete a slide by getting a reference to the Slide object that represents the slide and call
the Slide.delete method. The following is an example in which the 4th slide is deleted.
JavaScript
await context.sync();
});
}
Insert slides in a PowerPoint
presentation
Article • 09/20/2022
A PowerPoint add-in can insert slides from one presentation into the current
presentation by using PowerPoint's application-specific JavaScript library. You can
control whether the inserted slides keep the formatting of the source presentation or
the formatting of the target presentation.
The slide insertion APIs are primarily used in presentation template scenarios: There are
a small number of known presentations which serve as pools of slides that can be
inserted by the add-in. In such a scenario, either you or the customer must create and
maintain a data source that correlates the selection criterion (such as slide titles or
images) with slide IDs. The APIs can also be used in scenarios where the user can insert
slides from any arbitrary presentation, but in that scenario the user is effectively limited
to inserting all the slides from the source presentation. See Selecting which slides to
insert for more information about this.
There are two steps to inserting slides from one presentation into another.
1. Begin by getting a reference to the source PowerPoint file. In this example, we will
use an <input> control of type file to prompt the user to choose a file. Add the
following markup to the add-in page.
HTML
<section>
<p>Select a PowerPoint presentation from which to insert slides</p>
<form>
<input type="file" id="file" />
</form>
</section>
7 Note
There are many other ways to get a PowerPoint file. For example, if the file is
stored on OneDrive or SharePoint, you can use Microsoft Graph to download
it. For more information, see Working with files in Microsoft Graph and
Access Files with Microsoft Graph.
2. Add the following code to the add-in's JavaScript to assign a function to the input
control's change event. (You create the storeFileAsBase64 function in the next
step.)
JavaScript
$("#file").change(storeFileAsBase64);
3. Add the following code. Note the following about this code.
JavaScript
let chosenFileBase64;
chosenFileBase64 = copyBase64;
};
JavaScript
You can control some aspects of the insertion result, including where the slides are
inserted and whether they get the source or target formatting , by passing an
InsertSlideOptions object as a second parameter to insertSlidesFromBase64 . The
following is an example. About this code, note:
There are two possible values for the formatting property: "UseDestinationTheme"
and "KeepSourceFormatting". Optionally, you can use the InsertSlideFormatting
enum, (e.g., PowerPoint.InsertSlideFormatting.useDestinationTheme ).
The function will insert the slides from the source presentation immediately after
the slide specified by the targetSlideId property. The value of this property is a
string of one of three possible forms: nnn#, #mmmmmmmmm, or
nnn#mmmmmmmmm, where nnn is the slide's ID (typically 3 digits) and
mmmmmmmmm is the slide's creation ID (typically 9 digits). Some examples are
267#763315295 , 267# , and #763315295 .
JavaScript
Of course, you typically won't know at coding time the ID or creation ID of the target
slide. More commonly, an add-in will ask users to select the target slide. The following
steps show how to get the nnn# ID of the currently selected slide and use it as the
target slide.
1. Create a function that gets the ID of the currently selected slide by using the
Office.context.document.getSelectedDataAsync method of the Common JavaScript
APIs. The following is an example. Note that the call to getSelectedDataAsync is
embedded in a Promise-returning function. For more information about why and
how to do this, see Wrap Common-APIs in promise-returning functions.
JavaScript
function getSelectedSlideID() {
return new OfficeExtension.Promise<string>(function (resolve, reject)
{
Office.context.document.getSelectedDataAsync(Office.CoercionType.SlideR
ange, function (asyncResult) {
try {
if (asyncResult.status === Office.AsyncResultStatus.Failed) {
reject(console.error(asyncResult.error.message));
} else {
resolve(asyncResult.value.slides[0].id);
}
}
catch (error) {
reject(console.log(error));
}
});
})
}
2. Call your new function inside the PowerPoint.run() of the main function and pass
the ID that it returns (concatenated with the "#" symbol) as the value of the
targetSlideId property of the InsertSlideOptions parameter. The following is an
example.
JavaScript
context.presentation.insertSlidesFromBase64(chosenFileBase64, {
formatting: "UseDestinationTheme",
targetSlideId: selectedSlideID + "#"
});
await context.sync();
});
}
JavaScript
await context.sync();
});
}
7 Note
The slides will be inserted in the same relative order in which they appear in the
source presentation, regardless of the order in which they appear in the array.
There is no practical way that users can discover the ID or creation ID of a slide in the
source presentation. For this reason, you can really only use the sourceSlideIds
property when either you know the source IDs at coding time or your add-in can
retrieve them at runtime from some data source. Because users cannot be expected to
memorize slide IDs, you also need a way to enable the user to select slides, perhaps by
title or by an image, and then correlate each title or image with the slide's ID.
You can create an Office Add-in to send or publish a Word document or PowerPoint
presentation to a remote location. This article demonstrates how to build a simple task
pane add-in for PowerPoint or Word that gets all of the presentation or document as a
data object and sends that data to a web server via an HTTP request.
On a shared network folder or on a web server, you need the following files.
An HTML file (GetDoc_App.html) that contains the user interface plus links to
the JavaScript files (including Office.js and application-specific .js files) and
Cascading Style Sheet (CSS) files.
A CSS file (Program.css) to contain the styles and formatting for the add-in.
Alternatively, you can create an add-in for your Office application using one of the
following options. You won't have to create new files as the equivalent of each required
file will be available for you to update. For example, the Yeoman generator options
include ./src/taskpane/taskpane.html, ./src/taskpane/taskpane.js,
./src/taskpane/taskpane.css, and ./manifest.xml.
PowerPoint
Visual Studio
Yeoman generator for Office Add-ins
Word
Visual Studio
Yeoman generator for Office Add-ins
XML
Use the following procedure to create a simple user interface for the add-in that
includes a heading and a single button.
1. In a new file in the text editor, add the HTML for your selected Office application.
PowerPoint
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge"/>
<title>Publish presentation</title>
<link rel="stylesheet" type="text/css" href="Program.css"
/>
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-
1.9.0.min.js" type="text/javascript"></script>
<script
src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js"
type="text/javascript"></script>
<script src="GetDoc_App.js"></script>
</head>
<body>
<form>
<h1>Publish presentation</h1>
<br />
<div><input id='submit' type="button" value="Submit" />
</div>
<br />
<div><h2>Status</h2>
<div id="status"></div>
</div>
</form>
</body>
</html>
Be sure that the head tags of the add-in contains a script tag with a valid link
to the Office.js file.
3. We'll use some CSS to give the add-in a simple yet modern and professional
appearance. Use the following CSS to define the style of the add-in.
css
body
{
font-family: "Segoe UI Light","Segoe UI",Tahoma,sans-serif;
}
h1,h2
{
text-decoration-color:#4ec724;
}
input [type="submit"], input[type="button"]
{
height:24px;
padding-left:1em;
padding-right:1em;
background-color:white;
border:1px solid grey;
border-color: #dedfe0 #b9b9b9 #b9b9b9 #dedfe0;
cursor:pointer;
}
4. Save the file as Program.css using UTF-8 encoding to the network location or to
the web server where the GetDoc_App.html file is located.
The following code example shows the event handler for the Office.initialize event
along with a helper function, updateStatus , for writing to the status div.
JavaScript
// The initialize or onReady function is required for all add-ins.
Office.initialize = function (reason) {
// Checks for the DOM to load using the jQuery ready method.
$(document).ready(function () {
// Update status.
updateStatus("Ready to send file.");
});
}
When you choose the Submit button in the UI, the add-in calls the sendFile function,
which contains a call to the Document.getFileAsync method. The getFileAsync method
uses the asynchronous pattern, similar to other methods in the Office JavaScript API. It
has one required parameter, fileType, and two optional parameters, options and callback.
The fileType parameter expects one of three constants from the FileType enumeration:
Office.FileType.Compressed ("compressed"), Office.FileType.PDF ("pdf"), or
Office.FileType.Text ("text"). The current file type support for each platform is listed
under the Document.getFileType remarks. When you pass in Compressed for the
fileType parameter, the getFileAsync method returns the current document as a
PowerPoint presentation file (*.pptx) or Word document file (*.docx) by creating a
temporary copy of the file on the local computer.
The getFileAsync method returns a reference to the file as a File object. The File
object exposes the following four members.
size property
sliceCount property
getSliceAsync method
closeAsync method
The size property returns the number of bytes in the file. The sliceCount returns the
number of Slice objects (discussed later in this article) in the file.
Use the following code to get the current PowerPoint or Word document as a File
object using the Document.getFileAsync method and then make a call to the locally
defined getSlice function. Note that the File object, a counter variable, and the total
number of slices in the file are passed along in the call to getSlice in an anonymous
object.
JavaScript
The local function getSlice makes a call to the File.getSliceAsync method to retrieve
a slice from the File object. The getSliceAsync method returns a Slice object from
the collection of slices. It has two required parameters, sliceIndex and callback. The
sliceIndex parameter takes an integer as an indexer into the collection of slices. Like
other methods in the Office JavaScript API, the getSliceAsync method also takes a
callback function as a parameter to handle the results from the method call.
The Slice object gives you access to the data contained in the file. Unless otherwise
specified in the options parameter of the getFileAsync method, the Slice object is 4
MB in size. The Slice object exposes three properties: size, data, and index. The size
property gets the size, in bytes, of the slice. The index property gets an integer that
represents the slice's position in the collection of slices.
JavaScript
// Get a slice from the file and then call sendSlice.
function getSlice(state) {
state.file.getSliceAsync(state.counter, function (result) {
if (result.status == Office.AsyncResultStatus.Succeeded) {
updateStatus("Sending piece " + (state.counter + 1) + " of " +
state.sliceCount);
sendSlice(result.value, state);
} else {
updateStatus(result.status);
}
});
}
The Slice.data property returns the raw data of the file as a byte array. If the data is in
text format (that is, XML or plain text), the slice contains the raw text. If you pass in
Office.FileType.Compressed for the fileType parameter of Document.getFileAsync , the
slice contains the binary data of the file as a byte array. In the case of a PowerPoint or
Word file, the slices contain byte arrays.
You must implement your own function (or use an available library) to convert byte array
data to a Base64-encoded string. For information about Base64 encoding with
JavaScript, see Base64 encoding and decoding .
Once you've converted the data to Base64, you can then transmit it to a web server in
several ways, including as the body of an HTTP POST request.
7 Note
This code sends a PowerPoint or Word file to the web server in multiple slices. The
web server or service must append each individual slice into a single file, and then
save it as a .pptx or .docx file before you can perform any manipulations on it.
JavaScript
As the name implies, the File.closeAsync method closes the connection to the
document and frees up resources. Although the Office Add-ins sandbox garbage
collects out-of-scope references to files, it's still a best practice to explicitly close files
once your code is done with them. The closeAsync method has a single parameter,
callback, that specifies the function to call on the completion of the call.
JavaScript
function closeFile(state) {
// Close the file when you're done with it.
state.file.closeAsync(function (result) {
JavaScript
/*
* Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
the MIT license.
* See LICENSE in the project root for license information.
*/
// Checks for the DOM to load using the jQuery ready method.
$(document).ready(function () {
// Update status.
updateStatus("Ready to send file.");
});
}
function closeFile(state) {
// Close the file when you're done with it.
state.file.closeAsync(function (result) {
An add-in can attach custom metadata, in the form of key-value pairs, called "tags", to
presentations, specific slides, and specific shapes on a slide.
When applied to a slide or a shape, a tag enables the object to be categorized for
batch processing. For example, suppose a presentation has some slides that should
be included in presentations to the East region but not the West region. Similarly,
there are alternative slides that should be shown only to the West. Your add-in can
create a tag with the key REGION and the value East and apply it to the slides that
should only be used in the East. The tag's value is set to West for the slides that
should only be shown to the West region. Just before a presentation to the East, a
button in the add-in runs code that loops through all the slides checking the value
of the REGION tag. Slides where the region is West are deleted. The user then
closes the add-in and starts the slide show.
When applied to a presentation, a tag is effectively a custom property in the
presentation document (similar to a CustomProperty in Word).
The first parameter of the add method is the key in the key-value pair.
The second parameter is the value.
The key is in uppercase letters. This isn't strictly mandatory for the add method;
however, the key is always stored by PowerPoint as uppercase, and some tag-
related methods do require that the key be expressed in uppercase, so we
recommend as a best practice that you always use uppercase in your code for a
tag key.
JavaScript
await context.sync();
});
}
The add method is also used to update a tag. The following code changes the value of
the PLANET tag.
JavaScript
await context.sync();
});
}
To delete a tag, call the delete method on it's parent TagsCollection object and pass
the key of the tag as the parameter. For an example, see Set custom metadata on the
presentation.
1. Create a function that tags the currently selected slide as intended for Premium
customers. About this code, note:
The getSelectedSlideIndex function is defined in the next step. It returns the
1-based index of the currently selected slide.
The value returned by the getSelectedSlideIndex function has to be
decremented because the SlideCollection.getItemAt method is 0-based.
JavaScript
await context.sync();
});
}
2. The following code creates a method to get the index of the selected slide. About
this code, note:
selected. In this scenario, the user has selected just one, so the code gets the
first (0th) slide, which is the only one selected.
The index value of the slide is the 1-based value the user sees beside the
slide in the PowerPoint UI thumbnails pane.
JavaScript
function getSelectedSlideIndex() {
return new OfficeExtension.Promise<number>(function(resolve,
reject) {
Office.context.document.getSelectedDataAsync(Office.CoercionType.SlideR
ange, function(asyncResult) {
try {
if (asyncResult.status ===
Office.AsyncResultStatus.Failed) {
reject(console.error(asyncResult.error.message));
} else {
resolve(asyncResult.value.slides[0].index);
}
}
catch (error) {
reject(console.log(error));
}
});
});
}
3. The following code creates a function to delete slides that are tagged for premium
customers. About this code, note:
Because the key and value properties of the tags are going to be read after
the context.sync , they must be loaded first.
JavaScript
await context.sync();
await context.sync();
});
}
await context.sync();
});
}
The following code is an example of deleting a tag from a presentation. Note that the
key of the tag is passed to the delete method of the parent TagsCollection object.
JavaScript
await context.sync();
});
}
Use document themes in your
PowerPoint add-ins
Article • 03/22/2022
An Office theme consists, in part, of a visually coordinated set of fonts and colors that
you can apply to presentations, documents, worksheets, and emails. To apply or
customize the theme of a presentation in PowerPoint, you use the Themes and Variants
groups on Design tab of the ribbon. PowerPoint assigns a new blank presentation with
the default Office Theme, but you can choose other themes available on the Design tab,
download additional themes from Office.com, or create and customize your own theme.
Using OfficeThemes.css, design add-ins that are coordinated with PowerPoint in two
ways.
In task pane add-ins for PowerPoint. Use the Office UI theme classes of
OfficeThemes.css to specify the same fonts and background colors used in the UI
so that your task pane add-ins will match the colors of built-in task panes - and
those colors will dynamically update if a user changes the Office UI theme.
The first four colors are for text and backgrounds. Text that is created with the light
colors will always be legible over the dark colors, and text that is created with dark
colors will always be legible over the light colors. The next six are accent colors that are
always visible over the four potential background colors. The last two colors are for
hyperlinks and followed hyperlinks.
OfficeThemes.css includes classes that you can use in your task pane add-ins for
PowerPoint so they will use these same fonts and colors. This lets you design your task
pane add-ins that match the appearance of built-in task panes.
Use OfficeThemes.css
Using the OfficeThemes.css file with your content add-ins for PowerPoint lets you
coordinate the appearance of your add-in with the theme applied to the presentation
it's running with. Using the OfficeThemes.css file with your task pane add-ins for
PowerPoint lets you coordinate the appearance of your add-in with the fonts and colors
of the Office UI.
7 Note
The steps in this procedure only apply to Visual Studio 2015. If you are using Visual
Studio 2019, the OfficeThemes.css file is created automatically for any new
PowerPoint add-in projects that you create.
) Important
The style sheet must be named OfficeThemes, or the feature that dynamically
updates add-in fonts and colors when a user changes the theme won't work.
3. Delete the default body class ( body {} ) in the file, and copy and paste the
following CSS code into the file.
css
/* links */
.office-a { color: #0563c1; }
.office-a:visited { color: #954f72; }
/* Body Fonts */
.office-bodyFont-eastAsian { } /* East Asian name of the Font */
.office-bodyFont-latin { font-family:"Calibri"; } /* Latin name of the
Font */
.office-bodyFont-script { } /* Script name of the Font */
.office-bodyFont-localized { font-family:"Calibri"; } /* Localized name
of the Font. Corresponds to the default font of the culture currently
used in Office.*/
/* Headers Font */
.office-headerFont-eastAsian { }
.office-headerFont-latin { font-family:"Calibri Light"; }
.office-headerFont-script { }
.office-headerFont-localized { font-family:"Calibri Light"; }
/* The following classes define font and background colors for Office
UI themes. These classes should only be used in task pane add-ins */
4. If you are using a tool other than Visual Studio to create your add-in, copy the CSS
code from step 3 into a text file, making sure to save the file as OfficeThemes.css.
Reference OfficeThemes.css in your add-in's
HTML pages
To use the OfficeThemes.css file in your add-in project, add a <link> tag that references
the OfficeThemes.css file inside the <head> tag of the web pages (such as an .html, .aspx,
or .php file) that implement the UI of your add-in in this format.
HTML
2. Using the search box, enter add-in. Choose PowerPoint Web Add-in, then select
Next.
4. In the Create Office Add-in dialog window, choose Add new functionalities to
PowerPoint, and then choose Finish to create the project.
5. Visual Studio creates a solution and its two projects appear in Solution Explorer.
The Home.html file opens in Visual Studio.
6. In the HTML pages that implement the UI of your add-in, such as Home.html in the
default template, add the following <link> tag inside the <head> tag that
references the OfficeThemes.css file.
HTML
If you are creating your add-in with a tool other than Visual Studio, add a <link> tag
with the same format specifying a relative path to the copy of OfficeThemes.css that will
be deployed with your add-in.
HTML
<body>
<div id="themeSample" class="office-docTheme-primary-fontColor ">
<h1 class="office-headerFont-latin">Hello world!</h1>
<h1 class="office-headerFont-latin office-contentAccent1-
bgColor">Hello world!</h1>
<h1 class="office-headerFont-latin office-contentAccent2-
bgColor">Hello world!</h1>
<h1 class="office-headerFont-latin office-contentAccent3-
bgColor">Hello world!</h1>
<h1 class="office-headerFont-latin office-contentAccent4-
bgColor">Hello world!</h1>
<h1 class="office-headerFont-latin office-contentAccent5-
bgColor">Hello world!</h1>
<h1 class="office-headerFont-latin office-contentAccent6-
bgColor">Hello world!</h1>
<p class="office-bodyFont-latin office-docTheme-secondary-
fontColor">Hello world!</p>
</div>
</body>
At runtime, when inserted into a presentation that uses the default Office Theme, the
content add-in is rendered like this.
If you change the presentation to use another theme or customize the presentation's
theme, the fonts and colors specified with OfficeThemes.css classes will dynamically
update to correspond to the fonts and colors of the presentation's theme. Using the
same HTML example as above, if the presentation the add-in is inserted into uses the
Facet theme, the add-in rendering will look like this.
The following shows a simple example of HTML in a task pane add-in that uses
OfficeTheme.css classes to specify font color and background color. For details about
the OfficeThemes.css classes that correspond to fonts and colors of the Office UI theme,
see Theme classes for task pane add-ins.
HTML
<body>
<div id="content-header" class="office-officeTheme-primary-fontColor
office-officeTheme-primary-bgColor">
<div class="padding">
<h1>Welcome</h1>
</div>
</div>
<div id="content-main" class="office-officeTheme-secondary-fontColor
office-officeTheme-secondary-bgColor">
<div class="padding">
<p>Add home screen content here.</p>
<p>For example:</p>
<button id="get-data-from-selection">Get data from
selection</button>
<p><a target="_blank" class="office-a"
href="https://go.microsoft.com/fwlink/?LinkId=276812">Find more samples
online...</a></p>
</div>
</div>
</body>
When running in PowerPoint with File > Account > Office Theme set to White, the task
pane add-in is rendered like this.
If you change OfficeTheme to Dark Gray, the fonts and colors specified with
OfficeThemes.css classes will dynamically update to render like this.
OfficeTheme.css classes
The OfficeThemes.css file contains two sets of classes you can use with your content and
task pane add-ins for PowerPoint.
Class Description
office-bodyFont- Localized name of the body font. Specifies the default font name according
localized to the culture currently used in Office.
office- Localized name of the headers font. Specifies the default font name
headerFont- according to the culture currently used in Office.
localized
Class Description
The following screenshot shows examples of all of the theme color classes (except for
the two hyperlink colors) assigned to add-in text when using the default Office theme.
Theme classes for task pane add-ins
The OfficeThemes.css file provides classes that correspond to the 4 colors assigned to
fonts and backgrounds used by the Office application UI theme. These classes are
appropriate to use with task add-ins for PowerPoint so that your add-in's colors will be
coordinated with the other built-in task panes in Office.
Class Description
See also
Create content and task pane add-ins for PowerPoint
Work with shapes using the PowerPoint
JavaScript API
Article • 03/16/2023
This article describes how to use geometric shapes, lines, and text boxes in conjunction
with the Shape and ShapeCollection APIs.
Create shapes
Shapes are created through and stored in a slide's shape collection ( slide.shapes ).
ShapeCollection has several .add* methods for this purpose. All shapes have names
and IDs generated for them when they are added to the collection. These are the name
and id properties, respectively. name can be set by your add-in.
Geometric shapes
A geometric shape is created with one of the overloads of
ShapeCollection.addGeometricShape . The first parameter is either a GeometricShapeType
enum or the string equivalent of one of the enum's values. There is an optional second
parameter of type ShapeAddOptions that can specify the initial size of the shape and its
position relative to the top and left sides of the slide, measured in points. Or these
properties can be set after the shape is created.
The following code sample creates a rectangle named "Square" that is positioned 100
points from the top and left sides of the slide. The method returns a Shape object.
JavaScript
// This sample creates a rectangle positioned 100 points from the top and
left sides
// of the slide and is 150x150 points. The shape is put on the first slide.
await PowerPoint.run(async (context) => {
const shapes = context.presentation.slides.getItemAt(0).shapes;
const rectangle =
shapes.addGeometricShape(PowerPoint.GeometricShapeType.rectangle);
rectangle.left = 100;
rectangle.top = 100;
rectangle.height = 150;
rectangle.width = 150;
rectangle.name = "Square";
await context.sync();
});
Lines
A line is created with one of the overloads of ShapeCollection.addLine . The first
parameter is either a ConnectorType enum or the string equivalent of one of the enum's
values to specify how the line contorts between endpoints. There is an optional second
parameter of type ShapeAddOptions that can specify the start and end points of the
line. Or these properties can be set after the shape is created. The method returns a
Shape object.
7 Note
When the shape is a line, the top and left properties of the Shape and
ShapeAddOptions objects specify the starting point of the line relative to the top and
left edges of the slide. The height and width properties specify the endpoint of the
line relative to the start point. So, the end point relative to the top and left edges of
the slide is ( top + height ) by ( left + width ). The unit of measure for all properties
is points and negative values are allowed.
JavaScript
Text boxes
A text box is created with the addTextBox method. The first parameter is the text that
should appear in the box initially. There is an optional second parameter of type
ShapeAddOptions that can specify the initial size of the text box and its position relative
to the top and left sides of the slide. Or these properties can be set after the shape is
created.
The following code sample shows how to create a text box on the first slide.
JavaScript
// This sample creates a text box with the text "Hello!" and sizes it
appropriately.
await PowerPoint.run(async (context) => {
const shapes = context.presentation.slides.getItemAt(0).shapes;
const textbox = shapes.addTextBox("Hello!");
textbox.left = 100;
textbox.top = 100;
textbox.height = 300;
textbox.width = 450;
textbox.name = "Textbox";
await context.sync();
});
height and width properties. Your code can move or resize the shape by resetting these
properties. (These properties have a slightly different meaning when the shape is a line.
See Lines.)
Text in shapes
Geometric shapes can contain text. Shapes have a textFrame property of type
TextFrame. The TextFrame object manages the text display options (such as margins and
text overflow). TextFrame.textRange is a TextRange object with the text content and font
settings.
The following code sample creates a geometric shape named "Braces" with the text
"Shape text". It also adjusts the shape and text colors, as well as sets the text's vertical
alignment to the center.
JavaScript
// This sample creates a light blue rectangle with braces ("{}") on the left
and right ends
// and adds the purple text "Shape text" to the center.
await PowerPoint.run(async (context) => {
const shapes = context.presentation.slides.getItemAt(0).shapes;
const braces =
shapes.addGeometricShape(PowerPoint.GeometricShapeType.bracePair);
braces.left = 100;
braces.top = 400;
braces.height = 50;
braces.width = 150;
braces.name = "Braces";
braces.fill.setSolidColor("lightblue");
braces.textFrame.textRange.text = "Shape text";
braces.textFrame.textRange.font.color = "purple";
braces.textFrame.verticalAlignment =
PowerPoint.TextVerticalAlignment.middleCentered;
await context.sync();
});
Delete shapes
Shapes are removed from the slide with the Shape object's delete method.
JavaScript
shapes.items.forEach(function (shape) {
shape.delete();
});
await context.sync();
});
Project add-ins documentation
With Project add-ins, you can use familiar web technologies such as HTML, CSS, and
JavaScript to build a solution that can run in Project on Windows. Learn how to build,
test, debug, and publish Project add-ins.
e OVERVIEW
f QUICKSTART
c HOW-TO GUIDE
e OVERVIEW
b GET STARTED
Resources
i REFERENCE
Ask questions
Request features
Report issues
Project Standard 2013 and Project Professional 2013 (version 15.1 or higher) both
include support for task pane add-ins. You can run general task pane add-ins that are
developed for Word or Excel. You can also develop custom add-ins that handle selection
events in Project and integrate task, resource, view, and other cell-level data in a project
with SharePoint lists, SharePoint Add-ins, Web Parts, web services, and enterprise
applications.
7 Note
The Project 2013 SDK download includes sample add-ins that show how to use
the add-in object model for Project, and how to use the OData service for reporting
data in Project Server 2013. When you extract and install the SDK, see the
\Samples\Apps\ subdirectory.
7 Note
With Project Professional 2013, you can develop task pane add-ins that access
Project on the web, on-premises installations of Project Server 2013, and on-
premises or online SharePoint 2013. Project Standard 2013 does not support direct
integration with Project Server data or SharePoint task lists that are synchronized
with Project Server.
Resource management View the complete resource pool in Project Server 2013 or
a subset based on specified skills, including cost data and resource availability, to
help select appropriate resources.
Statusing and approvals Use a web application in a task pane add-in to update or
view data from an external enterprise resource planning (ERP) application,
timesheet system, or accounting application. Or, create a custom status approval
Web Part that can be used within both Project Web App and Project Professional
2013.
Work packages Search for specified kinds of project templates within SharePoint
libraries and online template collections. For example, find templates for
construction projects and add them to your Project template collection.
Related items View metadata, documents, and messages that are related to
specific tasks in a project plan. For example, you can use Project Professional 2013
to manage a project that was imported from a SharePoint task list, and still
synchronize the task list with changes in the project. A task pane add-in can show
additional fields or metadata that Project did not import for tasks in the SharePoint
list.
Use the Project Server object models Use the GUID of a selected task with
methods in the Project Server Interface (PSI) or the client-side object model
(CSOM) of Project Server. For example, the web application for an add-in can read
and update the statusing data of a selected task and resource, or integrate with an
external timesheet application.
Get reporting data Use Representational State Transfer (REST), JavaScript, or LINQ
queries to find related information for a selected task or resource in the OData
service for reporting tables in Project Web App. Queries that use the OData service
can be done with an online or an on-premises installation of Project Server 2013.
For example, see Create a Project add-in that uses REST with an on-premises
Project Server OData service.
To create an add-in, you can use a simple text editor to create an HTML webpage and
related JavaScript files, CSS files, and REST queries. In addition to an HTML page or a
web application, an add-in requires an XML manifest file for configuration. Project can
use a manifest file that includes a type attribute that is specified as TaskPaneExtension.
The manifest file can be used by multiple Office 2013 client applications, or you can
create a manifest file that is specific for Project 2013. For more information, see the
Development basics section in Office Add-ins platform overview.
When you install the Project 2013 SDK download, the \Samples\Apps\ subdirectory
includes the following sample add-ins.
Bing Search: The BingSearch.xml manifest file points to the Bing search page for
mobile devices. Because the Bing web app already exists on the Internet, the Bing
Search add-in does not use other source code files or the add-in object model for
Project.
XML
(Optional) Add <Override> elements that have values for other locales. For
example, the following manifest provides <Override> elements for French values
of <DisplayName>, <Description>, <IconUrl>, and <SourceLocation>.
XML
There can be multiple add-in manifest XML files and subdirectories in a file share. You
can add or remove manifest directory locations and catalogs by using the Trusted Add-
in Catalogs tab in the Trust Center dialog box in Project 2013. To show an add-in in
Project, the <SourceLocation> element in a manifest must point to an existing website
or HTML source file.
7 Note
In Procedure 2, the Bing Search add-in is installed on the local computer where Project
2013 is installed. However, because the add-in infrastructure does not directly use local
file paths such as C:\Project\AppManifests , you can create a network share on the local
computer. If you prefer, you can create a file share on a remote computer.
4. In Project 2013, open the Project Options dialog box, choose Trust Center, and
then choose Trust Center Settings.
5. In the Trust Center dialog box, in the left pane, choose Trusted Add-in Catalogs.
6. In the Trusted Add-in Catalogs pane (see Figure 1), add the
\\ServerName\AppManifests path in the Catalog Url text box, choose Add Catalog,
7 Note
Figure 1 shows two file shares and one hypothetical URL for a private catalog
in the Trusted Catalog Address list. Only one file share can be the default file
share and only one catalog URL can be the default catalog. For example, if
you set \\Server2\AppManifests as the default, Project clears the Default
check box for \\ServerName\AppManifests .If you change the default selection,
you can choose Clear to remove installed add-ins, and then restart Project. If
you add an add-in to the default file share or SharePoint catalog while Project
is open, you should restart Project.
The Bing Search add-in shows in a task pane, as in Figure 3. You can manually
resize the task pane, and use the Bing Search add-in.
See also
Office Add-ins platform overview
Learn about the Microsoft 365 Developer Program
Developing Office Add-ins
Create your first task pane add-in for Project 2013 by using a text editor
Create a Project add-in that uses REST with an on-premises Project Server OData
service
Project 2013 SDK download
Build your first Project task pane add-in
Article • 05/02/2023
In this article, you'll walk through the process of building a Project task pane add-in.
Prerequisites
7 Note
If you aren't familiar with Node.js or npm, you should start by setting up your
development environment.
The latest version of Yeoman and the Yeoman generator for Office Add-ins. To
install these tools globally, run the following command via the command prompt.
command line
7 Note
command line
yo office
7 Note
When you run the yo office command, you may receive prompts about the data
collection policies of Yeoman and the Office Add-in CLI tools. Use the information
that's provided to respond to the prompts as you see fit.
When prompted, provide the following information to create your add-in project.
After you complete the wizard, the generator creates the project and installs supporting
Node components.
Tip
You can ignore the next steps guidance that the Yeoman generator provides after
the add-in project's been created. The step-by-step instructions within this article
provide all of the guidance you'll need to complete this tutorial.
The ./manifest.xml file in the root directory of the project defines the settings and
capabilities of the add-in.
The ./src/taskpane/taskpane.html file contains the HTML markup for the task
pane.
The ./src/taskpane/taskpane.css file contains the CSS that's applied to content in
the task pane.
The ./src/taskpane/taskpane.js file contains the Office JavaScript API code that
facilitates interaction between the task pane and the Office client application. In
this quick start, the code sets the Name field and Notes field of the selected task of
a project.
Try it out
1. Navigate to the root folder of the project.
command line
7 Note
Office Add-ins should use HTTPS, not HTTP, even when you are developing. If
you are prompted to install a certificate after you run one of the following
commands, accept the prompt to install the certificate that the Yeoman
generator provides. You may also have to run your command prompt or
terminal as an administrator for the changes to be made.
Run the following command in the root directory of your project. When you run
this command, the local web server will start.
command line
4. Load your add-in in Project by following the instructions in Sideload Office Add-ins
on Windows.
Next steps
Congratulations, you've successfully created a Project task pane add-in! Next, learn
more about the capabilities of a Project add-in and explore common scenarios.
Project add-ins
See also
Develop Office Add-ins
Core concepts for Office Add-ins
Using Visual Studio Code to publish
JavaScript API for Project
Article • 05/02/2023
Project supports add-ins made with the JavaScript API, but there's currently no
JavaScript API designed specifically for interacting with Project. You can use the
Common API to create Project add-ins. For information about the Common API, see
Office JavaScript API object model.
See also
Project add-ins documentation
Project add-ins overview
API Reference documentation
Office client application and platform availability for Office Add-ins
Create a Project add-in that uses REST
with an on-premises Project Server
OData service
Article • 07/21/2022
This article describes how to build a task pane add-in for Project Professional 2013 that
compares cost and work data in the active project with the averages for all projects in
the current Project Web App instance. The add-in uses REST with the jQuery library to
access the ProjectData OData reporting service in Project Server 2013.
The code in this article is based on a sample developed by Saurabh Sanghvi and Arvind
Iyer, Microsoft Corporation.
Prerequisites
The following are the prerequisites for creating a Project task pane add-in that reads the
ProjectData service of a Project Web App instance in an on-premises installation of
Project Server 2013.
Ensure that you have installed the most recent service packs and Windows updates
on your local development computer. The operating system can be Windows 7,
Windows 8, Windows Server 2008, or Windows Server 2012.
Project Professional 2013 is required to connect with Project Web App. The
development computer must have Project Professional 2013 installed to enable F5
debugging with Visual Studio.
7 Note
Project Standard 2013 can also host task pane add-ins, but cannot sign in to
Project Web App.
Visual Studio 2015 with Office Developer Tools for Visual Studio includes templates
for creating Office and SharePoint Add-ins. Ensure that you have installed the most
recent version of Office Developer Tools; see the Tools section of the Office Add-ins
and SharePoint downloads.
The procedures and code examples in this article access the ProjectData service of
Project Server 2013 in a local domain. The jQuery methods in this article do not
work with Project on the web.
Verify that the ProjectData service is accessible from your development computer.
2. Query the ProjectData service by using your browser with the following URL:
http://ServerName /ProjectServerName /_api/ProjectData. For example, if the
Project Web App instance is http://MyServer/pwa , the browser shows the following
results.
XML
3. You may have to provide your network credentials to see the results. If the browser
shows "Error 403, Access Denied," either you do not have logon permission for
that Project Web App instance, or there is a network problem that requires
administrative help.
The add-in project takes the name of the solution. It includes the XML manifest file
for the add-in and targets the .NET Framework 4.5. Procedure 3 shows the steps to
modify the manifest for the HelloProjectOData add-in.
2. In the New Project dialog box, expand the Templates, Visual C#, and
Office/SharePoint nodes, and then select Office Add-ins. Select .NET Framework
4.5.2 in the target framework drop-down list at the top of the center pane, and
then select Office Add-in (see the next screenshot).
3. To place both of the Visual Studio projects in the same directory, select Create
directory for solution, and then browse to the location you want.
The AddIn folder (see the next screenshot) contains the App.css file for custom CSS
styles. In the Home subfolder , the Home.html file contains references to the CSS files
and the JavaScript files that the add-in uses, and the HTML5 content for the add-in.
Also, the Home.js file is for your custom JavaScript code. The Scripts folder includes the
jQuery library files. The Office subfolder includes the JavaScript libraries such as office.js
and project-15.js, plus the language libraries for standard strings in the Office Add-ins.
In the Content folder, the Office.css file contains the default styles for all of the Office
Add-ins.
For more information about the manifest, see Office Add-ins manifest and Schema
reference for Office Add-ins manifests.
2. The default display name is the name of the Visual Studio project
("HelloProjectOData"). For example, change the default value of the
<DisplayName> element to"Hello ProjectData".
3. The default description is also "HelloProjectOData". For example, change the
default value of the Description element to "Test REST queries of the ProjectData
service".
4. Add an icon to show in the Office Add-ins drop-down list on the PROJECT tab of
the ribbon. You can add an icon file in the Visual Studio solution or use a URL for
an icon.
The following steps show how to add an icon file to the Visual Studio solution.
Alternately, use your own 32 x 32 icon; or, copy the following image to a file
named NewIcon.png, and then add that file to the HelloProjectODataWeb\Images
folder.
manifest file now contains the following (your <Id> value will be different):
XML
The task pane shows the add-in display name at the top, which is the value of the
<DisplayName> element in the manifest. The body element in the
HelloProjectOData.html file contains the other UI elements, as follows:
The Get ProjectData Endpoint button calls the setOdataUrl function to get the
endpoint of the ProjectData service, and display it in a text box. If Project is not
connected with Project Web App, the add-in calls an error handler to display a
pop-up error message.
The Compare All Projects button is disabled until the add-in gets a valid OData
endpoint. When you select the button, it calls the retrieveOData function, which
uses a REST query to get project cost and work data from the ProjectData service.
A table displays the average values for project cost, actual cost, work, and percent
complete. The table also compares the current active project values with the
average. If the current value is greater than the average for all projects, the value is
displayed as red. If the current value is less than the average, the value is displayed
as green. If the current value is not available, the table displays a blue NA.
In this example, cost and work data for the active project are derived from the
published values. If you change values in Project, the ProjectData service does
not have the changes until the project is published.
2. Add any additional script elements for JavaScript libraries that your add-in uses.
The project template includes links for the jQuery- [version].js, office.js, and
MicrosoftAjax.js files in the Scripts folder.
7 Note
Before you deploy the add-in, change the office.js reference and the jQuery
reference to the content delivery network (CDN) reference. The CDN reference
provides the most recent version and better performance.
The HelloProjectOData add-in also uses the SurfaceErrors.js file, which displays
errors in a pop-up message. You can copy the code from the Robust Programming
section of Create your first task pane add-in for Project 2013 by using a text editor,
and then add a SurfaceErrors.js file in the Scripts\Office folder of the
HelloProjectODataWeb project.
Following is the updated HTML code for the head element, with the additional line
for the SurfaceErrors.js file.
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<title>Test ProjectData Service</title>
<!-- Use the CDN reference to the mini-version of jQuery when deploying
your add-in. -->
<!--<script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-
1.9.0.min.js"></script> -->
<script src="../Scripts/jquery-1.7.1.js"></script>
<!-- Use the CDN reference to office.js when deploying your add-in. -->
<!--<script
src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js">
</script>-->
<!-- Use the local script references for Office.js to enable offline
debugging -->
<script src="../Scripts/Office/1.0/MicrosoftAjax.js"></script>
<script src="../Scripts/Office/1.0/Office.js"></script>
3. In the body element, delete the existing code from the template, and then add the
code for the user interface. If an element is to be filled with data or manipulated by
a jQuery statement, the element must include a unique id attribute. In the
following code, the id attributes for the button, span, and td (table cell definition)
elements that jQuery functions use are shown in bold font.
The following HTML adds a graphic image, which could be a company logo. You
can use a logo of your choice, or copy the NewLogo.png file from the Project 2013
SDK download, and then use Solution Explorer to add the file to the
HelloProjectODataWeb\Images folder.
HTML
<body>
<div id="SectionContent">
<div id="odataQueries">
ODATA REST QUERY
</div>
<div id="odataInfo">
<button class="button-wide" onclick="setOdataUrl()">Get
ProjectData Endpoint</button>
<br /><br />
<span class="rest" id="projectDataEndPoint">Endpoint of the
<strong>ProjectData</strong> service</span>
<br />
</div>
<div id="compareProjectData">
<button class="button-wide" disabled="disabled"
id="compareProjects"
onclick="retrieveOData()">Compare All Projects</button>
<br />
</div>
</div>
<div id="corpInfo">
<table class="infoTable" aria-readonly="True" style="width:
100%;">
<tr>
<td class="heading_leftCol"></td>
<td class="heading_midCol"><strong>Average</strong>
</td>
<td class="heading_rightCol"><strong>Current</strong>
</td>
</tr>
<tr>
<td class="row_leftCol"><strong>Project Cost</strong>
</td>
<td class="row_midCol"
id="AverageProjectCost">&nbsp;</td>
<td class="row_rightCol"
id="CurrentProjectCost">&nbsp;</td>
</tr>
<tr>
<td class="row_leftCol"><strong>Project Actual
Cost</strong></td>
<td class="row_midCol"
id="AverageProjectActualCost">&nbsp;</td>
<td class="row_rightCol"
id="CurrentProjectActualCost">&nbsp;</td>
</tr>
<tr>
<td class="row_leftCol"><strong>Project Work</strong>
</td>
<td class="row_midCol"
id="AverageProjectWork">&nbsp;</td>
<td class="row_rightCol"
id="CurrentProjectWork">&nbsp;</td>
</tr>
<tr>
<td class="row_leftCol"><strong>Project %
Complete</strong></td>
<td class="row_midCol"
id="AverageProjectPercentComplete">&nbsp;</td>
<td class="row_rightCol"
id="CurrentProjectPercentComplete">&nbsp;</td>
</tr>
</table>
</div>
<img alt="Corporation" class="logo" src="../../images/NewLogo.png"
/>
<br />
<textarea id="odataText" rows="12" cols="40"></textarea>
</body>
The JavaScript includes global constants for the REST query and global variables that are
used in several functions. The Get ProjectData Endpoint button calls the setOdataUrl
function, which initializes the global variables and determines whether Project is
connected with Project Web App.
The remainder of the HelloProjectOData.js file includes two functions: the retrieveOData
function is called when the user selects Compare All Projects; and the parseODataResult
function calculates averages and then populates the comparison table with values that
are formatted for color and units.
JavaScript
7 Note
If you run Visual Studio on the Project Server computer, to use F5 debugging,
uncomment the code after the line that initializes the _pwa global variable. To
enable using the jQuery ajax method when debugging on the Project Server
computer, you must set the localhost value for the PWA URL.If you run Visual
Studio on a remote computer, the localhost URL is not required. Before you
deploy the add-in, comment out that code.
JavaScript
function setOdataUrl() {
Office.context.document.getProjectFieldAsync(
Office.ProjectProjectFields.ProjectServerUrl,
function (asyncResult) {
if (asyncResult.status ==
Office.AsyncResultStatus.Succeeded) {
_pwa = String(asyncResult.value.fieldValue);
if (_pwa.substring(0, 4) == "http") {
_odataUrl = _pwa + PROJDATA;
$("#compareProjects").removeAttr("disabled");
getProjectGuid();
}
else {
_odataUrl = "No connection!";
throwError(_odataUrl, "You are not connected to
Project Web App.");
}
getDocumentUrl();
$("#projectDataEndPoint").text(_odataUrl);
}
else {
throwError(asyncResult.error.name,
asyncResult.error.message);
}
}
);
}
// Get the path of the project in Project web app, which is in the form
<>\ProjectName .
function getDocumentUrl() {
_docUrl = "Document path:\r\n" + Office.context.document.url;
}
3. Add the retrieveOData function, which concatenates values for the REST query
and then calls the ajax function in jQuery to get the requested data from the
ProjectData service. The support.cors variable enables cross-origin resource
sharing (CORS) with the ajax function. If the support.cors statement is missing or
is set to false , the ajax function returns a No transport error.
7 Note
In the ajax call, you can use either the headers parameter or the beforeSend
parameter. The complete parameter is an anonymous function so that it is in the
same scope as the variables in retrieveOData . The function for the complete
parameter displays results in the odataText control and also calls the
parseODataResult method to parse and display the JSON response. The error
parameter specifies the named getProjectDataErrorHandler function, which writes
an error message to the odataText control and also uses the throwError function
to display a pop-up message.
JavaScript
$.ajax({
url: restUrl,
type: "GET",
contentType: "application/json",
data: "", // Empty string for the optional data.
//headers: { "Accept": accept },
beforeSend: function (xhr) {
xhr.setRequestHeader("ACCEPT", accept);
},
complete: function (xhr, textStatus) {
// Create a message to display in the text box.
var message = "\r\ntextStatus: " + textStatus +
"\r\nContentType: " + xhr.getResponseHeader("Content-
Type") +
"\r\nStatus: " + xhr.status +
"\r\nResponseText:\r\n" + xhr.responseText;
4. Add the parseODataResult function, which deserializes and processes the JSON
response from the OData service. The parseODataResult function calculates
average values of the cost and work data to an accuracy of one or two decimal
places, formats values with the correct color and adds a unit ( $, hrs, or %), and
then displays the values in specified table cells.
If the GUID of the active project matches the ProjectId value, the myProjectIndex
variable is set to the project index. If myProjectIndex indicates the active project is
published on Project Server, the parseODataResult method formats and displays
cost and work data for that project. If the active project is not published, values for
the active project are displayed as a blue NA.
JavaScript
// Calculate the average values of actual cost, cost, work, and percent
complete
// for all projects, and compare with the values for the current
project.
function parseODataResult(oDataResult, currentProjectGuid) {
// Deserialize the JSON string into a JavaScript object.
var res =
Sys.Serialization.JavaScriptSerializer.deserialize(oDataResult);
var len = res.d.results.length;
var projActualCost = 0;
var projCost = 0;
var projWork = 0;
var projPercentCompleted = 0;
var myProjectIndex = -1;
for (i = 0; i < len; i++) {
// If the current project GUID matches the GUID from the OData
query,
// store the project index.
if (currentProjectGuid.toLocaleLowerCase() ==
res.d.results[i].ProjectId) {
myProjectIndex = i;
}
projCost += Number(res.d.results[i].ProjectCost);
projWork += Number(res.d.results[i].ProjectWork);
projActualCost += Number(res.d.results[i].ProjectActualCost);
projPercentCompleted +=
Number(res.d.results[i].ProjectPercentCompleted);
}
var avgProjCost = projCost / len;
var avgProjWork = projWork / len;
var avgProjActualCost = projActualCost / len;
var avgProjPercentCompleted = projPercentCompleted / len;
// Round off cost to two decimal places, and round off other values
to one decimal place.
avgProjCost = avgProjCost.toFixed(2);
avgProjWork = avgProjWork.toFixed(1);
avgProjActualCost = avgProjActualCost.toFixed(2);
avgProjPercentCompleted = avgProjPercentCompleted.toFixed(1);
myProjCost = myProjCost.toFixed(2);
myProjWork = myProjWork.toFixed(1);
myProjActualCost = myProjActualCost.toFixed(2);
myProjPercentCompleted = myProjPercentCompleted.toFixed(1);
document.getElementById("CurrentProjectCost").innerHTML = "$" +
myProjCost;
document.getElementById("CurrentProjectActualCost").innerHTML =
"$" + myProjActualCost;
document.getElementById("CurrentProjectActualCost").style.color =
"green"
}
else {
document.getElementById("CurrentProjectActualCost").style.color = "red"
}
document.getElementById("CurrentProjectWork").innerHTML =
myProjWork + " hrs";
document.getElementById("CurrentProjectPercentComplete").innerHTML =
myProjPercentCompleted + "%";
if (Number(myProjPercentCompleted) <=
Number(avgProjPercentCompleted)) {
document.getElementById("CurrentProjectPercentComplete").style.color =
"red"
}
else {
document.getElementById("CurrentProjectPercentComplete").style.color =
"green"
}
}
else {
document.getElementById("CurrentProjectCost").innerHTML = "NA";
document.getElementById("CurrentProjectCost").style.color =
"blue"
document.getElementById("CurrentProjectActualCost").innerHTML =
"NA";
document.getElementById("CurrentProjectActualCost").style.color
= "blue"
document.getElementById("CurrentProjectWork").innerHTML = "NA";
document.getElementById("CurrentProjectWork").style.color =
"blue"
document.getElementById("CurrentProjectPercentComplete").innerHTML =
"NA";
document.getElementById("CurrentProjectPercentComplete").style.color =
"blue"
}
}
1. On the File tab, choose the Info tab in the Backstage view, and then choose
Manage Accounts.
2. In the Project web app Accounts dialog box, the Available accounts list can have
multiple Project Web App accounts in addition to the local Computer account. In
the When starting section, select Choose an account.
3. Close Project so that Visual Studio can start it for debugging the add-in.
Run the add-in again, where you choose the local computer profile in the Login
dialog box when Project starts. Open a local .mpp file, and then test the add-in.
Verify that the add-in displays an error message when you try to get the
ProjectData endpoint.
Run the add-in again, where you create a project that has tasks with cost and work
data. You can save the project to Project Web App, but don't publish it. Verify that
the add-in displays data from Project Server, but NA for the current project.
2. In Visual Studio, press F5. Log on to Project Web App, and then open the project
that you created in the previous step. You can open the project in read-only mode
or in edit mode.
3. On the PROJECT tab of the ribbon, in the Office Add-ins drop-down list, select
Hello ProjectData (see Figure 5). The Compare All Projects button should be
disabled.
5. Select Compare All Projects. The add-in may pause while it retrieves data from the
ProjectData service, and then it should display the formatted average and current
values in the table.
Following is an example of the output with line breaks and spaces added to the
text for clarity, for three projects in a Project Web App instance.
JSON
REST query:
http://sphvm-37189/pwa/_api/ProjectData/Projects?$filter=ProjectName ne
'Timesheet Administrative Work Items'
&$select=ProjectId, ProjectName, ProjectCost, ProjectWork,
ProjectPercentCompleted, ProjectActualCost
textStatus: success
ContentType: application/json;odata=verbose;charset=utf-8
Status: 200
ResponseText:
{"d":{"results":[
{"__metadata":
{"id":"http://sphvm-
37189/pwa/_api/ProjectData/Projects(guid'ce3d0d65-3904-e211-96cd-
00155d157123')",
"uri":"http://sphvm-
37189/pwa/_api/ProjectData/Projects(guid'ce3d0d65-3904-e211-96cd-
00155d157123')",
"type":"ReportingData.Project"},
"ProjectId":"ce3d0d65-3904-e211-96cd-00155d157123",
"ProjectActualCost":"0.000000",
"ProjectCost":"0.000000",
"ProjectName":"Task list created in PWA",
"ProjectPercentCompleted":0,
"ProjectWork":"16.000000"},
{"__metadata":
{"id":"http://sphvm-
37189/pwa/_api/ProjectData/Projects(guid'c31023fc-1404-e211-86b2-
3c075433b7bd')",
"uri":"http://sphvm-
37189/pwa/_api/ProjectData/Projects(guid'c31023fc-1404-e211-86b2-
3c075433b7bd')",
"type":"ReportingData.Project"},
"ProjectId":"c31023fc-1404-e211-86b2-3c075433b7bd",
"ProjectActualCost":"700.000000",
"ProjectCost":"2400.000000",
"ProjectName":"WinProj test 2",
"ProjectPercentCompleted":29,
"ProjectWork":"48.000000"},
{"__metadata":
{"id":"http://sphvm-
37189/pwa/_api/ProjectData/Projects(guid'dc81fbb2-b801-e211-9d2a-
3c075433b7bd')",
"uri":"http://sphvm-
37189/pwa/_api/ProjectData/Projects(guid'dc81fbb2-b801-e211-9d2a-
3c075433b7bd')",
"type":"ReportingData.Project"},
"ProjectId":"dc81fbb2-b801-e211-9d2a-3c075433b7bd",
"ProjectActualCost":"1900.000000",
"ProjectCost":"5200.000000",
"ProjectName":"WinProj test1",
"ProjectPercentCompleted":37,
"ProjectWork":"104.000000"}
]}}
7. Stop debugging (press Shift + F5), and then press F5 again to run a new instance
of Project. In the Login dialog box, choose the local Computer profile, not Project
Web App. Create or open a local project .mpp file, open the Hello ProjectData task
pane, and then select Get ProjectData Endpoint. The add-in should show a No
connection! error (see Figure 7), and the Compare All Projects button should
remain disabled.
8. Stop debugging, and then press F5 again. Log on to Project Web App, and then
create a project that contains cost and work data. You can save the project, but
don't publish it.
In the Hello ProjectData task pane, when you select Compare All Projects, you
should see a blue NA for fields in the Current column (see Figure 8).
Figure 8. Compare an unpublished project with other projects
Even if your add-in is working correctly in the previous tests, there are other tests that
should be run. For example:
Open a project from Project Web App that has no cost or work data for the tasks.
You should see values of zero in the fields in the Current column.
If you modify the add-in and publish it, you should run similar tests again with the
published add-in. For other considerations, see Next steps.
7 Note
There are limits to the amount of data that can be returned in one query of the
ProjectData service; the amount of data varies by entity. For example, the Projects
entity set has a default limit of 100 projects per query, but the Risks entity set has
a default limit of 200. For a production installation, the code in the
HelloProjectOData example should be modified to enable queries of more than
100 projects. For more information, see Next steps and Querying OData feeds for
Project reporting data.
HelloProjectOData.html file
The following code is in the Pages\HelloProjectOData.html file of the
HelloProjectODataWeb project.
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<title>Test ProjectData Service</title>
<!-- Use the CDN reference to Office.js when deploying your add-in -
->
<!--<script
src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js"></script>--
>
<!-- Use the local script references for Office.js to enable offline
debugging -->
<script src="../Scripts/Office/1.0/MicrosoftAjax.js"></script>
<script src="../Scripts/Office/1.0/Office.js"></script>
HelloProjectOData.js file
The following code is in the Scripts\Office\HelloProjectOData.js file of the
HelloProjectODataWeb project.
JavaScript
/* File: HelloProjectOData.js
* JavaScript functions for the HelloProjectOData example task pane app.
* October 2, 2012
*/
// Set the global variables, enable the Compare All Projects button,
// and display the URL of the ProjectData service.
// Display an error if Project is not connected with Project Web App.
function setOdataUrl() {
Office.context.document.getProjectFieldAsync(
Office.ProjectProjectFields.ProjectServerUrl,
function (asyncResult) {
if (asyncResult.status == Office.AsyncResultStatus.Succeeded) {
_pwa = String(asyncResult.value.fieldValue);
// If you debug with Visual Studio on a local Project Server
computer,
// uncomment the following lines to use the localhost URL.
//var localhost = location.host.split(":", 1);
//var pwaStartPosition = _pwa.lastIndexOf("/");
//var pwaLength = _pwa.length - pwaStartPosition;
//var pwaName = _pwa.substr(pwaStartPosition, pwaLength);
//_pwa = location.protocol + "//" + localhost + pwaName;
if (_pwa.substring(0, 4) == "http") {
_odataUrl = _pwa + PROJDATA;
$("#compareProjects").removeAttr("disabled");
getProjectGuid();
}
else {
_odataUrl = "No connection!";
throwError(_odataUrl, "You are not connected to Project
Web App.");
}
getDocumentUrl();
$("#projectDataEndPoint").text(_odataUrl);
}
else {
throwError(asyncResult.error.name,
asyncResult.error.message);
}
}
);
}
// Get the path of the project in Project web app, which is in the form
<>\ProjectName .
function getDocumentUrl() {
_docUrl = "Document path:\r\n" + Office.context.document.url;
}
$.ajax({
url: restUrl,
type: "GET",
contentType: "application/json",
data: "", // Empty string for the optional data.
//headers: { "Accept": accept },
beforeSend: function (xhr) {
xhr.setRequestHeader("ACCEPT", accept);
},
complete: function (xhr, textStatus) {
// Create a message to display in the text box.
var message = "\r\ntextStatus: " + textStatus +
"\r\nContentType: " + xhr.getResponseHeader("Content-Type")
+
"\r\nStatus: " + xhr.status +
"\r\nResponseText:\r\n" + xhr.responseText;
}
var avgProjCost = projCost / len;
var avgProjWork = projWork / len;
var avgProjActualCost = projActualCost / len;
var avgProjPercentCompleted = projPercentCompleted / len;
// Round off cost to two decimal places, and round off other values to
one decimal place.
avgProjCost = avgProjCost.toFixed(2);
avgProjWork = avgProjWork.toFixed(1);
avgProjActualCost = avgProjActualCost.toFixed(2);
avgProjPercentCompleted = avgProjPercentCompleted.toFixed(1);
myProjCost = myProjCost.toFixed(2);
myProjWork = myProjWork.toFixed(1);
myProjActualCost = myProjActualCost.toFixed(2);
myProjPercentCompleted = myProjPercentCompleted.toFixed(1);
document.getElementById("CurrentProjectCost").innerHTML = "$" +
myProjCost;
document.getElementById("CurrentProjectActualCost").innerHTML = "$"
+ myProjActualCost;
document.getElementById("CurrentProjectWork").innerHTML = myProjWork
+ " hrs";
document.getElementById("CurrentProjectPercentComplete").innerHTML =
myProjPercentCompleted + "%";
if (Number(myProjPercentCompleted) <=
Number(avgProjPercentCompleted)) {
document.getElementById("CurrentProjectPercentComplete").style.color = "red"
}
else {
document.getElementById("CurrentProjectPercentComplete").style.color =
"green"
}
}
else { // The current project is not published.
document.getElementById("CurrentProjectCost").innerHTML = "NA";
document.getElementById("CurrentProjectCost").style.color = "blue"
document.getElementById("CurrentProjectActualCost").innerHTML =
"NA";
document.getElementById("CurrentProjectActualCost").style.color =
"blue"
document.getElementById("CurrentProjectWork").innerHTML = "NA";
document.getElementById("CurrentProjectWork").style.color = "blue"
document.getElementById("CurrentProjectPercentComplete").innerHTML =
"NA";
document.getElementById("CurrentProjectPercentComplete").style.color
= "blue"
}
}
App.css file
The following code is in the Content\App.css file of the HelloProjectODataWeb project.
css
/*
* File: App.css for the HelloProjectOData app.
* Updated: 10/2/2012
*/
body
{
font-size: 11pt;
}
h1
{
font-size: 22pt;
}
h2
{
font-size: 16pt;
}
/******************************************************************
Code label class
******************************************************************/
.rest
{
font-family: 'Courier New';
font-size: 0.9em;
}
/******************************************************************
Button classes
******************************************************************/
.button-wide {
width: 210px;
margin-top: 2px;
}
.button-narrow
{
width: 80px;
margin-top: 2px;
}
/******************************************************************
Table styles
******************************************************************/
.infoTable
{
text-align: center;
vertical-align: middle
}
.heading_leftCol
{
width: 20px;
height: 20px;
}
.heading_midCol
{
width: 100px;
height: 20px;
font-size: medium;
font-weight: bold;
}
.heading_rightCol
{
width: 101px;
height: 20px;
font-size: medium;
font-weight: bold;
}
.row_leftCol
{
width: 20px;
font-size: small;
font-weight: bold;
}
.row_midCol
{
width: 100px;
}
.row_rightCol
{
width: 101px;
}
.logo
{
width: 135px;
height: 53px;
}
SurfaceErrors.js file
You can copy code for the SurfaceErrors.js file from the Robust Programming section of
Create your first task pane add-in for Project 2013 by using a text editor.
Next steps
If HelloProjectOData were a production add-in to be sold in AppSource or distributed
in a SharePoint app catalog, it would be designed differently. For example, there would
be no debug output in a text box, and probably no button to get the ProjectData
endpoint. You would also have to rewrite the retrieveOData function to handle Project
Web App instances that have more than 100 projects.
The add-in should contain additional error checks, plus logic to catch and explain or
show edge cases. For example, if a Project Web App instance has 1000 projects with an
average duration of five days and average cost of $2400, and the active project is the
only one that has a duration longer than 20 days, the cost and work comparison would
be skewed. That could be shown with a frequency graph. You could add options to
display duration, compare similar length projects, or compare projects from the same or
different departments. Or, add a way for the user to select from a list of fields to display.
For other queries of the ProjectData service, there are limits to the length of the query
string, which affects the number of steps that a query can take from a parent collection
to an object in a child collection. For example, a two-step query of Projects to Tasks to
task item works, but a three-step query such as Projects to Tasks to Assignments to
assignment item may exceed the default maximum URL length. For more information,
see Query OData feeds for Project reporting data.
If you modify the HelloProjectOData add-in for production use, do the following steps.
In the HelloProjectOData.html file, for better performance, change the office.js
reference from the local project to the CDN reference:
HTML
<script
src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js">
</script>
Rewrite the retrieveOData function to enable queries of more than 100 projects.
For example, you could get the number of projects with a
~/ProjectData/Projects()/$count query, and use the $skip operator and $top
operator in the REST query for project data. Run multiple queries in a loop, and
then average the data from each query. Each query for project data would be of
the form:
~/ProjectData/Projects()?skip= [numSkipped]&$top=100&$filter=
[filter]&$select=[field1,field2, ???????]
For more information, see OData system query options using the REST endpoint.
You can also use the Set-SPProjectOdataConfiguration command in Windows
PowerShell to override the default page size for a query of the Projects entity set
(or any of the 33 entity sets). See ProjectData - Project OData service reference.
See also
Task pane add-ins for Project
Create your first task pane add-in for Project 2013 by using a text editor
ProjectData - Project OData service reference
Office Add-ins manifest
Publish your Office Add-in
Create your first task pane add-in for
Microsoft Project
Article • 04/11/2023
You can create a task pane add-in for Project Standard 2013, Project Professional 2013,
or later versions using the Yeoman generator for Office Add-ins. This article describes
how to create a simple add-in that uses an XML manifest that points to an HTML file on
a file share. The Project OM Test sample add-in tests some JavaScript functions that use
the object model for add-ins. After you use the Trust Center in Project to register the file
share that contains the manifest file, you can open the task pane add-in from the
Project tab on the ribbon. (The sample code in this article is based on a test application
by Arvind Iyer, Microsoft Corporation.)
Project uses the same add-in manifest schema that other Office clients use, and much of
the same JavaScript API. The complete code for the add-in that is described in this
article is available in the Samples\Apps subdirectory of the Project 2013 SDK download.
The Project OM Test sample add-in can get the GUID of a task and properties of the
application and the active project. If Project Professional 2013 opens a project that is in
a SharePoint library, the add-in can show the URL of the project.
The Project 2013 SDK download includes the complete source code. When you extract
and install the SDK and samples that are in the Project2013SDK.msi file, see the
\Samples\Apps\Copy_to_AppManifests_FileShare subdirectory for the manifest file and
The JSOMCall.html sample uses JavaScript functions in the office.js file and project-15.js
file, which are included. You can use the corresponding debug files (office.debug.js and
project-15.debug.js) to examine the functions.
For an introduction to using JavaScript in Office Add-ins, see Understanding the Office
JavaScript API.
For Project, the OfficeApp element must include the xsi:type="TaskPaneApp" attribute
value. The Id element is a GUID. The SourceLocation value must be a file share path or
a SharePoint URL for the add-in HTML source file or the web application that runs in the
task pane. For an explanation of the other elements in manifest file, see Task pane add-
ins for Project.
Procedure 2 shows how to create the HTML file that the JSOM_SimpleOMCalls.xml
manifest specifies for the Project test add-in. Buttons that are specified in the HTML file
call related JavaScript functions. You can add the JavaScript functions within the HTML
file, or put them in a separate .js file.
The JSOMCall.html file uses the common MicrosoftAjax.js file for AJAX functionality
and the Office.js file for the add-in functionality in Office 2013 applications.
HTML
<!DOCTYPE html>
<html>
<head>
<title>Project OM Sample Code</title>
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<script type="text/javascript" src="MicrosoftAjax.js"></script>
The textarea element specifies a text box that shows results of the JavaScript
functions.
7 Note
For the Project OM Test sample to work, copy the following files from the
Project 2013 SDK download to the same directory as the JSOMCall.html file:
Office.js, Project-15.js, and MicrosoftAjax.js.
Step 2 adds the JSOM_Sample.js file for specific functions that the Project OM Test
sample add-in uses. In later steps, you will add other HTML elements for buttons
that call JavaScript functions.
The following code gets the application context and document information by
using methods in the Office.js file. The text object is the ID of the textarea
control in the HTML file.
JavaScript
/*
* JavaScript functions for the Project OM Test example app
* in the Project 2013 SDK.
*/
var _projDoc;
var _app;
var taskGuid;
var resourceGuid;
function logError(errorText) {
text.value = "Error in " + errorText;
}
function logEventError(erroneousEvent) {
logError("event " + erroneousEvent);
}
function getContextValues() {
getDocumentUrl();
getDocumentMode();
getApplicationContentLanguage();
getApplicationDisplayLanguage();
}
function getDocumentUrl() {
text.value ="Document URL:\n" +_projDoc.url;
}
function getDocumentMode() {
var docMode = _projDoc.mode;
text.value = text.value + "\n\nDocument mode: " + docMode;
}
function getApplicationContentLanguage() {
text.value = text.value + "\nApp language: " +
_app.contentLanguage;
}
function getApplicationDisplayLanguage() {
text.value = text.value + "\nDisplay language: " +
_app.displayLanguage;
}
For information about the functions in the Office.debug.js file, see Office JavaScript
API. For example, the getDocumentUrl function gets the URL or file path of the
open project.
3. Add JavaScript functions that call asynchronous methods in Office.js and Project-
15.js to get selected data:
For example, getSelectedDataAsync is a general method in Office.js that gets
unformatted text for the selected data. For more information, see Document
object.
The getTaskAsync function gets the task name and the names of the assigned
resources. If the task is in a synchronized SharePoint task list, getTaskAsync
gets the task ID in the SharePoint list; otherwise, the SharePoint task ID is 0.
7 Note
valid task GUID and then select a different task, the getTaskAsync
function gets data for the most recent task that was operated on by the
getSelectedTaskAsync function.
view.
7 Note
To get the SharePoint URL and name of the tasks list, we recommend
that you use the getProjectFieldAsync method with the WSSUrl and
WSSList constants in the ProjectProjectFields enumeration.
Each of the functions in the following code includes an anonymous function that is
specified by function (asyncResult) , which is a callback that gets the
asynchronous result. Instead of anonymous functions, you could use named
functions, which can help with maintainability of complex add-ins.
JavaScript
// Get the data in the selected cells of the grid in the active view.
function getSelectedDataAsync() {
_projDoc.getSelectedDataAsync(
Office.CoercionType.Text,
{ ValueFormat: "Formatted" },
function (asyncResult) {
if (asyncResult.status ==
Office.AsyncResultStatus.Succeeded)
text.value = asyncResult.value;
else
logMethodError("getSelectedDataAsync",
asyncResult.error.name,
asyncResult.error.message);
}
);
}
_projDoc. getTaskFieldAsync(taskGuid,
Office.ProjectTaskFields.Name,
function (asyncResult) {
if (asyncResult.status ==
Office.AsyncResultStatus.Succeeded) {
text.value = text.value + "Name: "
+ asyncResult.value.fieldValue + "\n";
}
else {
logMethodError("getTaskFieldAsync",
asyncResult.error.name,
asyncResult.error.message);
}
}
);
_projDoc.getTaskFieldAsync(taskGuid, Office.ProjectTaskFields.ID,
function (asyncResult) {
if (asyncResult.status ==
Office.AsyncResultStatus.Succeeded) {
text.value = text.value + "ID: "
+ asyncResult.value.fieldValue + "\n";
}
else {
logMethodError("getTaskFieldAsync",
asyncResult.error.name,
asyncResult.error.message);
}
}
);
_projDoc.getTaskFieldAsync(taskGuid,
Office.ProjectTaskFields.Start,
function (asyncResult) {
if (asyncResult.status ==
Office.AsyncResultStatus.Succeeded) {
text.value = text.value + "Start: "
+ asyncResult.value.fieldValue + "\n";
}
else {
logMethodError("getTaskFieldAsync",
asyncResult.error.name,
asyncResult.error.message);
}
}
);
_projDoc.getTaskFieldAsync(taskGuid,
Office.ProjectTaskFields.Duration,
function (asyncResult) {
if (asyncResult.status ==
Office.AsyncResultStatus.Succeeded) {
text.value = text.value + "Duration: "
+ asyncResult.value.fieldValue + "\n";
}
else {
logMethodError("getTaskFieldAsync",
asyncResult.error.name,
asyncResult.error.message);
}
}
);
_projDoc.getTaskFieldAsync(taskGuid,
Office.ProjectTaskFields.Priority,
function (asyncResult) {
if (asyncResult.status ==
Office.AsyncResultStatus.Succeeded) {
text.value = text.value + "Priority: "
+ asyncResult.value.fieldValue + "\n";
}
else {
logMethodError("getTaskFieldAsync",
asyncResult.error.name,
asyncResult.error.message);
}
}
);
_projDoc.getTaskFieldAsync(taskGuid,
Office.ProjectTaskFields.Notes,
function (asyncResult) {
if (asyncResult.status ==
Office.AsyncResultStatus.Succeeded) {
text.value = text.value + "Notes: "
+ asyncResult.value.fieldValue + "\n";
}
else {
logMethodError("getTaskFieldAsync",
asyncResult.error.name,
asyncResult.error.message);
}
}
);
}
_projDoc.getResourceFieldAsync(resourceGuid,
Office.ProjectResourceFields.Name,
function (asyncResult) {
if (asyncResult.status ==
Office.AsyncResultStatus.Succeeded) {
text.value = text.value + "Resource name: " +
asyncResult.value.fieldValue + "\n";
}
else {
logMethodError("getResourceFieldAsync",
asyncResult.error.name,
asyncResult.error.message);
}
}
);
_projDoc.getResourceFieldAsync(resourceGuid,
Office.ProjectResourceFields.Cost,
function (asyncResult) {
if (asyncResult.status ==
Office.AsyncResultStatus.Succeeded) {
text.value = text.value + "Cost: " +
asyncResult.value.fieldValue + "\n";
}
else {
logMethodError("getResourceFieldAsync",
asyncResult.error.name,
asyncResult.error.message);
}
}
);
_projDoc.getResourceFieldAsync(resourceGuid,
Office.ProjectResourceFields.StandardRate,
function (asyncResult) {
if (asyncResult.status ==
Office.AsyncResultStatus.Succeeded) {
text.value = text.value + "Standard Rate: " +
asyncResult.value.fieldValue + "\n";
}
else {
logMethodError("getResourceFieldAsync",
asyncResult.error.name, asyncResult.error.message);
}
}
);
_projDoc.getResourceFieldAsync(resourceGuid,
Office.ProjectResourceFields.ActualCost,
function (asyncResult) {
if (asyncResult.status ==
Office.AsyncResultStatus.Succeeded) {
text.value = text.value + "Actual Cost: " +
asyncResult.value.fieldValue + "\n";
}
else {
logMethodError("getResourceFieldAsync",
asyncResult.error.name, asyncResult.error.message);
}
}
);
_projDoc.getResourceFieldAsync(resourceGuid,
Office.ProjectResourceFields.ActualWork,
function (asyncResult) {
if (asyncResult.status ==
Office.AsyncResultStatus.Succeeded) {
text.value = text.value + "Actual Work: " +
asyncResult.value.fieldValue + "\n";
}
else {
logMethodError("getResourceFieldAsync",
asyncResult.error.name,
asyncResult.error.message);
}
}
);
_projDoc.getResourceFieldAsync(resourceGuid,
Office.ProjectResourceFields.Units,
function (asyncResult) {
if (asyncResult.status ==
Office.AsyncResultStatus.Succeeded) {
text.value = text.value + "Units: " +
asyncResult.value.fieldValue + "\n";
}
else {
logMethodError("getResourceFieldAsync",
asyncResult.error.name,
asyncResult.error.message);
}
}
);
}
// Get the URL and list name of the synchronized SharePoint task list.
// Recommended: use getProjectField instead.
function getWSSUrlAsync() {
_projDoc.getWSSUrlAsync(function (asyncResult) {
if (asyncResult.status == Office.AsyncResultStatus.Succeeded) {
text.value = "SharePoint URL:\n" +
asyncResult.value.serverUrl
+ "\nList name: " + asyncResult.value.listName;
}
else {
logMethodError("getWSSUrlAsync", asyncResult.error.name,
asyncResult.error.message);
}
});
}
_projDoc.getProjectFieldAsync(Office.ProjectProjectFields.GUID,
function (asyncResult) {
if (asyncResult.status ==
Office.AsyncResultStatus.Succeeded) {
text.value = text.value + "Project GUID: " +
asyncResult.value.fieldValue + "\n";
}
else {
logMethodError("getProjectFieldAsync",
asyncResult.error.name, asyncResult.error.message);
}
}
);
_projDoc.getProjectFieldAsync(Office.ProjectProjectFields.Start,
function (asyncResult) {
if (asyncResult.status ==
Office.AsyncResultStatus.Succeeded) {
text.value = text.value + "\nStart: " +
asyncResult.value.fieldValue + "\n";
}
else {
logMethodError("getProjectFieldAsync",
asyncResult.error.name, asyncResult.error.message);
}
}
);
_projDoc.getProjectFieldAsync(Office.ProjectProjectFields.Finish,
function (asyncResult) {
if (asyncResult.status ==
Office.AsyncResultStatus.Succeeded) {
text.value = text.value + "\nFinish: " +
asyncResult.value.fieldValue + "\n";
}
else {
logMethodError("getProject " + errorText);
}
}
);
_projDoc.getProjectFieldAsync(Office.ProjectProjectFields.CurrencyDigit
s,
function (asyncResult) {
if (asyncResult.status ==
Office.AsyncResultStatus.Succeeded) {
text.value = text.value + "\nCurrency digits: " +
asyncResult.value.fieldValue + "\n";
}
else {
logMethodError("getProjectFieldAsync",
asyncResult.error.name, asyncResult.error.message);
}
}
);
_projDoc.getProjectFieldAsync(Office.ProjectProjectFields.CurrencySymbo
l,
function (asyncResult) {
if (asyncResult.status ==
Office.AsyncResultStatus.Succeeded) {
text.value = text.value + "Currency symbol: " +
asyncResult.value.fieldValue + "\n";
}
else {
logMethodError("getProjectFieldAsync",
asyncResult.error.name, asyncResult.error.message);
}
}
);
_projDoc.getProjectFieldAsync(Office.ProjectProjectFields.CurrencySymbo
lPosition,
function (asyncResult) {
if (asyncResult.status ==
Office.AsyncResultStatus.Succeeded) {
text.value = text.value + "\nSymbol position: " +
asyncResult.value.fieldValue + "\n";
}
else {
logMethodError("getProjectFieldAsync",
asyncResult.error.name, asyncResult.error.message);
}
}
);
_projDoc.getProjectFieldAsync(Office.ProjectProjectFields.ProjectServer
Url,
function (asyncResult) {
if (asyncResult.status ==
Office.AsyncResultStatus.Succeeded) {
text.value = text.value + "\nProject web app URL:\n "
+ asyncResult.value.fieldValue + "\n";
}
else {
logMethodError("getProjectFieldAsync",
asyncResult.error.name, asyncResult.error.message);
}
}
);
_projDoc.getProjectFieldAsync(Office.ProjectProjectFields.WSSUrl,
function (asyncResult) {
if (asyncResult.status ==
Office.AsyncResultStatus.Succeeded) {
text.value = text.value + "\nSharePoint URL:\n " +
asyncResult.value.fieldValue + "\n";
}
else {
logMethodError("getProjectFieldAsync",
asyncResult.error.name, asyncResult.error.message);
}
}
);
_projDoc.getProjectFieldAsync(Office.ProjectProjectFields.WSSList,
function (asyncResult) {
if (asyncResult.status ==
Office.AsyncResultStatus.Succeeded) {
text.value = text.value + "\nSharePoint list: " +
asyncResult.value.fieldValue + "\n";
}
else {
logMethodError("getProjectFieldAsync",
asyncResult.error.name, asyncResult.error.message);
}
}
);
}
4. Add JavaScript event handler callbacks and functions to register the task selection,
resource selection, and view selection change event handlers and to unregister the
event handlers. The manageEventHandlerAsync function adds or removes the
specified event handler, depending on the operation parameter. The operation can
be addHandlerAsync or removeHandlerAsync .
JavaScript
5. For the body of the HTML document, add buttons that call the JavaScript functions
for testing. For example, in the div element for the common JSOM API, add an
input button that calls the general getSelectedDataAsync function.
HTML
<body>
<div id="Common_JSOM_API">
OBJECT MODEL TESTS
<br /><br />
<strong>General function:</strong>
<br />
<input id="Button5" class="button-wide" type="button"
onclick="getSelectedDataAsync()"
value="getSelectedDataAsync" />
</div>
<!-- more code . . . -->
6. Add a div section with buttons for project-specific task functions and for the
TaskSelectionChanged event.
HTML
<div id="ProjectSpecificTask">
<br />
<strong>Project-specific task methods:</strong><br />
<button class="button-wide"
onclick="getSelectedTaskAsync()">getSelectedTaskAsync</button><br />
<button class="button-wide"
onclick="getTaskAsync()">getTaskAsync</button><br />
<button class="button-wide" onclick="getTaskFields()">Get Task
Fields</button><br />
<button class="button-wide"
onclick="getWSSUrlAsync()">getWSSUrlAsync</button>
<strong>Task selection changed:</strong>
<button class="button-narrow"
onclick="manageTaskEventHandler('addHandlerAsync')">Add</button>
<button class="button-narrow"
onclick="manageTaskEventHandler('removeHandlerAsync')">Remove</button>
</div>
7. Add div sections with buttons for the resource methods and events, view
methods and events, project properties, and context properties
HTML
<div id="ResourceMethods">
<br />
<strong>Resource methods:</strong>
<button class="button-wide"
onclick="getSelectedResourceAsync()">getSelectedResourceAsync</button>
<br />
<button class="button-wide" onclick="getResourceFields()">Get
Resource Fields</button><br />
<strong>Resource selection changed:</strong>
<button class="button-narrow"
onclick="manageResourceEventHandler('addHandlerAsync')">Add</button>
<button class="button-narrow"
onclick="manageResourceEventHandler('removeHandlerAsync')">Remove</butt
on>
</div>
<div id="ViewMethods">
<br />
<strong>View method:</strong>
<button class="button-wide"
onclick="getSelectedViewAsync()">getSelectedViewAsync</button><br />
<strong>View selection changed:</strong>
<button class="button-narrow"
onclick="manageViewEventHandler('addHandlerAsync')">Add</button>
<button class="button-narrow"
onclick="manageViewEventHandler('removeHandlerAsync')">Remove</button>
</div>
<div id="ProjectMethods">
<br />
<strong>Project properties:</strong>
<button class="button-wide" onclick="getProjectFields()">Get Project
Fields</button><br />
</div>
<div id="ContextVariables">
<br />
<strong>Context properties:</strong>
<button class="button-wide" onclick="getContextValues()">Get Context
Values</button>
</div>
8. To format the button elements, add a CSS style element. For example, add the
following as a child of the head element.
HTML
<style type="text/css">
.button-wide
{
width: 210px;
margin-top: 2px;
}
.button-narrow
{
width: 80px;
margin-top: 2px;
}
</style>
Procedure 3 shows how to install and use the Project OM Test add-in features.
command.
2. Create a file share for the directory that contains the HTML and JavaScript files for
the Project OM Test add-in. Ensure the file share path matches the path that is
specified in the JSOM_SimpleOMCalls.xml manifest. For example, if the files are in
the C:\Project\AppSource directory on the local computer, run the following
command.
3. In Project, open the Project Options dialog box, choose Trust Center, and then
choose Trust Center Settings.
The procedure for registering an add-in is also described in Task pane add-ins for
Project, with additional information.
4. In the Trust Center dialog box, in the left pane, choose Trusted Add-in Catalogs.
5. If you have already added the \\ServerName\AppManifests path for the Bing Search
add-in, skip this step. Otherwise, in the Trusted Add-in Catalogs pane, add the
\\ServerName\AppManifests path in the Catalog Url text box, choose Add catalog,
enable the network share as a default source (see Figure 1), and then choose OK.
8. Select the cell in the Duration column for the first task, and then choose the
getSelectedDataAsync button in the Project OM Test add-in. The
getSelectedDataAsync function sets the text box value to show 2 days .
9. Select the three Duration cells for all three tasks. The getSelectedDataAsync
function returns semicolon-separated text values for cells selected in different
rows, for example, 2 days;4 days;0 days .
The Indicators column and the Resource Names column are both empty, so the
text array shows empty values for those columns. The <NA> value is for the Add
New Column cell.
10. Select any cell in the row for task T2, or the entire row for task T2, and then choose
getSelectedTaskAsync. The text box shows the task GUID value, for example,
{25D3E03B-9A7D-E111-92FC-00155D3BA208} . Project stores that value in the global
11. Select getTaskAsync . If the taskGuid variable contains the GUID for task T2, the
text box displays the task information. The ResourceNames value is empty.
Create two local resources R1 andR2, assign them to task T2 at 50% each, and
choose getTaskAsync again. The results in the text box include the resource
information. If the task is in a synchronized SharePoint task list, the results also
include the SharePoint task ID.
Task name: T2
GUID: {25D3E03B-9A7D-E111-92FC-00155D3BA208}
WSS Id: 0
ResourceNames: R1[50%],R2[50%]
12. Select the Get Task Fields button. The getTaskFields function calls the
getTaskFieldAsync method multiple times for the task name, index, start date,
duration, priority, and task notes.
Name: T2
ID: 2
Start: Thu 6/14/12
Duration: 4d
Priority: 500
Notes: This is a note for task T2. It is only a test note. If it had been a real
note, there would be some real information.
13. Select the getWSSUrlAsync button. If the project is one of the following kinds, the
results show the task list URL and name.
If the project is a local project, or if you use Project Professional to open a project
that is managed by Project Server, the getWSSUrlAsync method shows an
undefined error.
14. Select the Add button in the TaskSelectionChanged event section, which calls the
manageTaskEventHandler function to register a task selection changed event and
15. To use the resource methods, first select a view such as Resource Sheet, Resource
Usage, or Resource Form, and then select a resource in that view. Choose
getSelectedResourceAsync to initialize the resourceGuid variable, and then
choose Get Resource Fields to call getResourceFieldAsync multiple times for the
resource properties. You can also add or remove the resource selection changed
event handler.
Resource name: R1
Cost: $800.00
Standard Rate: $50.00/h
Actual Cost: $0.00
Actual Work: 0h
Units: 100%
16. Select getSelectedViewAsync to show the type and name of the active view. You
can also add or remove the view selection changed event handler. For example, if
Resource Form is the active view, the getSelectedViewAsync function shows the
following in the text box.
View type: 6
Name: Resource Form
17. Select Get Project Fields to call the getProjectFieldAsync function multiple times
for different properties of the active project. If the project is opened from Project
Web App, the getProjectFieldAsync function can get the URL of the Project Web
App instance.
18. Select the Get Context Values button get properties of the document and the
application in which the add-in is running, by getting properties of the
Office.Context.document object and the Office.context.application object. For
example, if the Project1.mpp file is on the local computer desktop, the document
URL is C:\Users\UserAlias\Desktop\Project1.mpp . If the .mpp file is in a SharePoint
library, the value is the URL of the document. If you use Project Professional 2013
to open a project named Project1 from Project Web App, the document URL is
<>\Project1 .
19. You can refresh the add-in after you edit the source code by closing and restarting
Project. In the Project ribbon, the Office Add-ins drop-down list maintains the list
of recently used add-ins.
Example
The Project 2013 SDK download contains the complete code in the JSOMCall.html file,
the JSOM_Sample.js file, and the related Office.js, Office.debug.js, Project-15.js, and
Project-15.debug.js files. Following is the code in the JSOMCall.html file.
HTML
<!DOCTYPE html>
<html>
<head>
<title>Project OM Sample Code</title>
<meta http-equiv="X-UA-Compatible" content="IE=Edge"/>
<!-- Use the CDN reference to office.js when deploying your add-in.
-->
<!-- <script
src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js"></script> -
->
<script type="text/javascript" src="office.js"></script>
<script type="text/javascript" src="JSOM_Sample.js"></script>
<style type="text/css">
.button-wide {
width: 210px;
margin-top: 2px;
}
.button-narrow
{
width: 80px;
margin-top: 2px;
}
</style>
</head>
<body>
<div id="Common_JSOM_API">
OBJECT MODEL TESTS
<br /><br />
<strong>General method:</strong>
<br />
<input id="Button5" class="button-wide" type="button"
onclick="getSelectedDataAsync()"
value="getSelectedDataAsync" />
</div>
<div id="ProjectSpecificTask">
<br />
<strong>Project-specific task methods:</strong><br />
<button class="button-wide"
onclick="getSelectedTaskAsync()">getSelectedTaskAsync</button><br />
<button class="button-wide"
onclick="getTaskAsync()">getTaskAsync</button><br />
<button class="button-wide" onclick="getTaskFields()">Get Task
Fields</button><br />
<button class="button-wide"
onclick="getWSSUrlAsync()">getWSSUrlAsync</button>
<strong>Task selection changed:</strong>
<button class="button-narrow"
onclick="manageTaskEventHandler('addHandlerAsync')">Add</button>
<button class="button-narrow"
onclick="manageTaskEventHandler('removeHandlerAsync')">Remove</button>
</div>
<div id="ResourceMethods">
<br />
<strong>Resource methods:</strong>
<button class="button-wide"
onclick="getSelectedResourceAsync()">getSelectedResourceAsync</button><br />
<button class="button-wide" onclick="getResourceFields()">Get
Resource Fields</button><br />
<strong>Resource selection changed:</strong>
<button class="button-narrow"
onclick="manageResourceEventHandler('addHandlerAsync')">Add</button>
<button class="button-narrow"
onclick="manageResourceEventHandler('removeHandlerAsync')">Remove</button>
</div>
<div id="ViewMethods">
<br />
<strong>View method:</strong>
<button class="button-wide"
onclick="getSelectedViewAsync()">getSelectedViewAsync</button><br />
<strong>View selection changed:</strong>
<button class="button-narrow"
onclick="manageViewEventHandler('addHandlerAsync')">Add</button>
<button class="button-narrow"
onclick="manageViewEventHandler('removeHandlerAsync')">Remove</button>
</div>
<div id="ProjectMethods">
<br />
<strong>Project properties:</strong>
<button class="button-wide" onclick="getProjectFields()">Get
Project Fields</button><br />
</div>
<div id="ContextVariables">
<br />
<strong>Context properties:</strong>
<button class="button-wide" onclick="getContextValues()">Get
Context Values</button>
</div>
<br />
<textarea id="text" rows="10" cols="25">This is the text result.
</textarea>
</body>
</html
Robust programming
The Project OM Test add-in is an example that shows the use of some JavaScript
functions for Project 2013 in the Project-15.js and Office.js files. The example is for
testing only and does not include robust error checks. For example, if you do not select
a resource and run the getSelectedResourceAsync function, the resourceGuid variable is
not initialized, and calls to getResourceFieldAsync return an error. For a production add-
in, you should check for specific errors and ignore the results, hide functionality that
does not apply, or notify the user to choose a view and make a valid selection before
using a function.
For a simple example, the error output in the following code includes th actionMessage
variable that specifies the action to take to avoid an error in the
getSelectedResourceAsync function.
JavaScript
function logError(errorText) {
text.value = "Error in " + errorText;
}
The HelloProject_OData sample in the Project 2013 SDK download includes the
SurfaceErrors.js file that uses the JQuery library to display a pop-up error message.
Figure 4 shows the error message in a "toast" notification.
The following code in the SurfaceErrors.js file includes th throwError function that
creates a Toast object.
JavaScript
/*
* Show error messages in a "toast" notification.
*/
// Throws a custom defined error.
function throwError(errTitle, errMessage) {
try {
// Define and throw a custom error.
var customError = { name: errTitle, message: errMessage }
throw customError;
}
catch (err) {
// Catch the error and display it to the user.
Toast.showToast(err.name, err.message);
}
}
Toast: "divToast",
Close: "btnClose",
Notice: "lblNotice",
Output: "lblOutput",
if (document.getElementById(this.Toast) == null) {
this.createToast();
}
document.getElementById(this.Notice).innerText = title;
document.getElementById(this.Output).innerText = message;
$("#" + this.Toast).hide();
$("#" + this.Toast).show("slow");
},
btnClose = document.createElement("span");
btnClose.setAttribute("style", "cursor:pointer;");
btnClose.setAttribute("onclick", "Toast.close()");
btnClose.innerText = "X";
lblClose.appendChild(btnClose);
lblNotice = document.createElement("span");
lblNotice.setAttribute("id", this.Notice);
var labelStyle = "font-weight:bold;margin-top:0px;";
lblNotice.setAttribute("style", labelStyle);
lblOutput = document.createElement("span");
lblOutput.setAttribute("id", this.Output);
To use the throwError function, include the JQuery library and the SurfaceErrors.js script
in the JSOMCall.html file, and then add a call to throwError in other JavaScript functions
such as logMethodError .
7 Note
Before you deploy the add-in, change the office.js reference and the jQuery
reference to the content delivery network (CDN) reference. The CDN reference
provides the most recent version and better performance.
HTML
<!DOCTYPE html>
<html>
<head>
<title>Project OM Sample Code</title>
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<!-- Use the CDN reference to Office.js and jQuery when deploying your
add-in. -->
<!-- <script
src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js"></script> -
->
<script type="text/javascript" src="office.js"></script>
<script type="text/javascript"
src="http://ajax.microsoft.com/ajax/jQuery/jquery-1.9.0.min.js"></script>
JavaScript
e OVERVIEW
b GET STARTED
Create a script that displays the shape text of the selected shape
i REFERENCE
Resources
i REFERENCE
Ask questions
Request features
Report issues
You can use the Visio JavaScript APIs to embed Visio diagrams in classic SharePoint
pages in SharePoint Online. (This extensibility feature is not supported in on-premise
SharePoint or on SharePoint Framework pages.)
EmbeddedSession
The EmbeddedSession object initializes communication between the developer frame
and the Visio frame in the browser.
JavaScript
The batch commands include definitions of local JavaScript proxy objects and sync()
methods that synchronize the state between local and Visio objects and promise
resolution. The advantage of batching requests in Visio.run() is that when the promise
is resolved, any tracked page objects that were allocated during the execution will be
automatically released.
The run function takes in session and RequestContext object and returns a promise
(typically, just the result of context.sync() ). It is possible to run the batch operation
outside of the Visio.run() . However, in such a scenario, any page object references
needs to be manually tracked and managed.
RequestContext
The RequestContext object facilitates requests to the Visio application. Because the
developer frame and the Visio web client run in two different iframes, the
RequestContext object (context in next example) is required to get access to Visio and
related objects such as pages and shapes, from the developer frame.
JavaScript
function hideToolbars() {
Visio.run(session, function(context){
const app = context.document.application;
app.showToolbars = false;
return context.sync().then(function () {
window.console.log("Toolbars Hidden");
});
}).catch(function(error)
{
window.console.log("Error: " + error);
});
};
Proxy objects
The Visio JavaScript objects declared and used in an embedded session are proxy
objects for the real objects in a Visio document. All actions taken on proxy objects are
not realized in Visio, and the state of the Visio document is not realized in the proxy
objects until the document state has been synchronized. The document state is
synchronized when context.sync() is run.
For example, the local JavaScript object getActivePage is declared to reference the
selected page. This can be used to queue the setting of its properties and invoking
methods. The actions on such objects are not realized until the sync() method is run.
JavaScript
sync()
The sync() method synchronizes the state between JavaScript proxy objects and real
objects in Visio by executing instructions queued on the context and retrieving
properties of loaded Office objects for use in your code. This method returns a promise,
which is resolved when synchronization is complete.
load()
The load() method is used to fill in the proxy objects created in the JavaScript layer.
When trying to retrieve an object such as a document, a local proxy object is created
first in the JavaScript layer. Such an object can be used to queue the setting of its
properties and invoking methods. However, for reading object properties or relations,
the load() and sync() methods need to be invoked first. The load() method takes in
the properties and relations that need to be loaded when the sync() method is called.
JavaScript
2. loadOption specifies an object that describes the selection, expansion, top, and
skip options. See object load options for details.
All these commands are queued and run when context.sync() is called. The sync()
method returns a promise that can be used to chain it with other operations.
JavaScript
error.code error.message
Get started
You can use the example in this section to get started. This example shows you how to
programmatically display the shape text of the selected shape in a Visio diagram. To
begin, create a classic page in SharePoint Online or edit an existing page. Add a script
editor webpart on the page and copy-paste the following code.
HTML
<script src='https://appsforoffice.microsoft.com/embedded/1.0/visio-web-
embedded.js' type='text/javascript'></script>
let session; // Global variable to store the session and pass it afterwards
in Visio.run()
let textArea;
// Loads the Visio application and Initializes communication between
developer frame and Visio online frame
function initEmbeddedFrame() {
textArea = document.getElementById('ResultOutput');
let url = document.getElementById('fileUrl').value;
if (!url) {
window.alert("File URL should not be empty");
}
// APIs are enabled for EmbedView action only.
url = url.replace("action=view","action=embedview");
url = url.replace("action=interactivepreview","action=embedview");
url = url.replace("action=default","action=embedview");
url = url.replace("action=edit","action=embedview");
// Code for getting selected Shape Text using the shapes collection object
function getSelectedShapeText() {
Visio.run(session, function (context) {
const page = context.document.getActivePage();
const shapes = page.shapes;
shapes.load();
return context.sync().then(function () {
textArea.value = "Please select a Shape in the Diagram";
for(let i=0; i<shapes.items.length;i++) {
let shape = shapes.items[i];
if ( shape.select == true) {
textArea.value = shape.text;
return;
}
}
});
}).catch(function(error) {
textArea.value = "Error: ";
if (error instanceof OfficeExtension.Error) {
textArea.value += "Debug info: " +
JSON.stringify(error.debugInfo);
}
});
}
</script>
After that, all you need is the URL of a Visio diagram that you want to work with. Just
upload the Visio diagram to SharePoint Online and open it in Visio on the web. From
there, open the Embed dialog and use the Embed URL in the above example.
If you are using Visio on the web in Edit mode, open the Embed dialog by choosing File
> Share > Embed. If you are using Visio on the web in View mode, open the Embed
dialog by choosing '...' and then Embed.
Classes
Visio.Application Represents the Application.
Interfaces
Visio.BoundingBox Represents the BoundingBox of the shape.
Visio.Interfaces.Application An interface for updating data on the Application object, for use
UpdateData in application.set({ ... }) .
Visio.Interfaces.Comment An interface for updating data on the Comment object, for use
UpdateData in comment.set({ ... }) .
Visio.Interfaces.Document An interface for updating data on the Document object, for use
UpdateData in document.set({ ... }) .
Visio.Interfaces.PageUpdate An interface for updating data on the Page object, for use in
Data page.set({ ... }) .
Visio.Interfaces.PageView An interface for updating data on the PageView object, for use in
UpdateData pageView.set({ ... }) .
Visio.Interfaces.ShapeUpdate An interface for updating data on the Shape object, for use in
Data shape.set({ ... }) .
Visio.Interfaces.ShapeView An interface for updating data on the ShapeView object, for use
UpdateData in shapeView.set({ ... }) .
Visio.SelectionChangedEvent Provides information about the shape collection that raised the
Args SelectionChanged event.
Enums
Visio.ColumnType Represents the type of column values.
Visio.ErrorCodes
Functions
Visio.run(batch) Executes a batch script that performs actions on the Visio object
model, using a new request context. When the promise is
resolved, any tracked objects that were automatically allocated
during execution will be released.
Visio.run(object, batch) Executes a batch script that performs actions on the Visio object
model, using the request context of a previously-created API
object.
Visio.run(objects, batch) Executes a batch script that performs actions on the Visio object
model, using the request context of previously-created API
objects.
Visio.run(contextObject, Executes a batch script that performs actions on the Visio object
batch) model, using the RequestContext of a previously-created object.
When the promise is resolved, any tracked objects that were
automatically allocated during execution will be released.
Function Details
Visio.run(batch)
Executes a batch script that performs actions on the Visio object model, using a new
request context. When the promise is resolved, any tracked objects that were
automatically allocated during execution will be released.
TypeScript
Parameters
batch (context: Visio.RequestContext) => Promise<T>
A function that takes in an Visio.RequestContext and returns a promise (typically, just
the result of "context.sync()"). The context parameter facilitates requests to the Visio
application. Since the Office add-in and the Visio application run in two different
processes, the request context is required to get access to the Visio object model
from the add-in.
Returns
Promise<T>
Visio.run(object, batch)
Executes a batch script that performs actions on the Visio object model, using the
request context of a previously-created API object.
TypeScript
Parameters
object OfficeExtension.ClientObject | OfficeExtension.EmbeddedSession
A previously-created API object. The batch will use the same request context as the
passed-in object, which means that any changes applied to the object will be picked
up by "context.sync()".
Returns
Promise<T>
Visio.run(objects, batch)
Executes a batch script that performs actions on the Visio object model, using the
request context of previously-created API objects.
TypeScript
Parameters
objects OfficeExtension.ClientObject[]
An array of previously-created API objects. The array will be validated to make sure
that all of the objects share the same context. The batch will use this shared request
context, which means that any changes applied to these objects will be picked up by
"context.sync()".
batch (context: Visio.RequestContext) => Promise<T>
A function that takes in a Visio.RequestContext and returns a promise (typically, just
the result of "context.sync()"). When the promise is resolved, any tracked objects that
were automatically allocated during execution will be released.
Returns
Promise<T>
Visio.run(contextObject, batch)
Executes a batch script that performs actions on the Visio object model, using the
RequestContext of a previously-created object. When the promise is resolved, any
tracked objects that were automatically allocated during execution will be released.
TypeScript
Parameters
contextObject OfficeExtension.ClientRequestContext
A previously-created Visio.RequestContext. This context will get re-used by the batch
function (instead of having a new context created). This means that the batch will be
able to pick up changes made to existing API objects, if those objects were derived
from this same context.
Returns
Promise<T>
Remarks
In addition to this signature, the method also has the following signatures:
e OVERVIEW
f QUICKSTART
c HOW-TO GUIDE
Use the Word JavaScript API to interact with document content and metadata
e OVERVIEW
p CONCEPT
Resources
i REFERENCE
Ask questions
Request features
Report issues
Do you want to create a solution that extends the functionality of Word? For example,
one that involves automated document assembly? Or a solution that binds to and
accesses data in a Word document from other data sources? You can use the Office
Add-ins platform, which includes the Word JavaScript API and the Office JavaScript API,
to extend Word clients running on a Windows desktop, on a Mac, or in the cloud.
Word add-ins are one of the many development options that you have on the Office
Add-ins platform. You can use add-in commands to extend the Word UI and launch task
panes that run JavaScript that interacts with the content in a Word document. Any code
that you can run in a browser can run in a Word add-in. Add-ins that interact with
content in a Word document create requests to act on Word objects and synchronize
object state.
7 Note
If you plan to publish your add-in to AppSource and make it available within the
Office experience, make sure that you conform to the Commercial marketplace
certification policies. For example, to pass validation, your add-in must work across
all platforms that support the methods that you define (for more information, see
section 1120.3 and the Office Add-in application and availability page).
The following figure shows an example of a Word add-in that runs in a task pane.
For example, the following code shows how to append a new sentence to that
paragraph.
JavaScript
You can use any web server technology to host your Word add-in, such as ASP.NET,
NodeJS, or Python. Use your favorite client-side framework -- Ember, Backbone,
Angular, React -- or stick with vanilla or plain JavaScript to develop your solution. You
can also use services like Azure to authenticate and host your application.
The Word JavaScript APIs give your application access to the objects and metadata
found in a Word document. You can use these APIs to create add-ins that target:
Write your add-in once, and it will run in all versions of Word across multiple platforms.
For details, see Office client application and platform availability for Office Add-ins.
The second is the Word JavaScript API. This is an application-specific API model that was
introduced with Word 2016. It's a strongly-typed object model that you can use to
create Word add-ins that target Word 2016 and later on Mac and on Windows. This
object model uses promises and provides access to Word-specific objects like body,
content controls, inline pictures, and paragraphs. The Word JavaScript API includes
TypeScript definitions and vsdoc files so that you can get code hints in your IDE.
Currently, all Word clients support the shared Office JavaScript API, and most clients
support the Word JavaScript API. For details about supported clients, see Office client
application and platform availability for Office Add-ins.
We recommend that you start with the Word JavaScript API because the object model is
easier to use. Use the Word JavaScript API if you need to do the following:
Use the shared Office JavaScript API when you need to do any of the following:
To learn more about how to design a world-class Word add-in that creates a compelling
experience for your users, see Design guidelines and Best practices.
After you develop your add-in, you can publish it to a network share, an app catalog, or
AppSource.
See also
Developing Office Add-ins
Learn about the Microsoft 365 Developer Program
Office Add-ins platform overview
Word JavaScript API reference
Build your first Word task pane add-in
Article • 04/17/2023
In this article, you'll walk through the process of building a Word task pane add-in.
Yeoman generator
Prerequisites
7 Note
If you aren't familiar with Node.js or npm, you should start by setting up your
development environment.
The latest version of Yeoman and the Yeoman generator for Office Add-ins.
To install these tools globally, run the following command via the command
prompt.
command line
7 Note
command line
yo office
7 Note
When you run the yo office command, you may receive prompts about the
data collection policies of Yeoman and the Office Add-in CLI tools. Use the
information that's provided to respond to the prompts as you see fit.
When prompted, provide the following information to create your add-in project.
After you complete the wizard, the generator creates the project and installs
supporting Node components.
Tip
You can ignore the next steps guidance that the Yeoman generator provides
after the add-in project's been created. The step-by-step instructions within
this article provide all of the guidance you'll need to complete this tutorial.
The ./manifest.xml file in the root directory of the project defines the settings
and capabilities of the add-in. To learn more about the manifest.xml file, see
Office Add-ins XML manifest.
The ./src/taskpane/taskpane.html file contains the HTML markup for the task
pane.
The ./src/taskpane/taskpane.css file contains the CSS that's applied to
content in the task pane.
The ./src/taskpane/taskpane.js file contains the Office JavaScript API code
that facilitates interaction between the task pane and the Office client
application.
Try it out
1. Navigate to the root folder of the project.
command line
2. Complete the following steps to start the local web server and sideload your
add-in.
7 Note
Office Add-ins should use HTTPS, not HTTP, even while you're
developing. If you're prompted to install a certificate after you run one of
the following commands, accept the prompt to install the certificate that
the Yeoman generator provides. You may also have to run your command
prompt or terminal as an administrator for the changes to be made.
Tip
If you're testing your add-in on Mac, run the following command before
proceeding. When you run this command, the local web server starts.
command line
To test your add-in in Word, run the following command in the root
directory of your project. This starts the local web server (if it's not
already running) and opens Word with your add-in loaded.
command line
npm start
7 Note
command line
https://contoso.sharepoint.com/:t:/g/EZGxP7ksiE5DuxvY638G798Bpuhwl
uxCMfF1WZQj3VYhYQ?e=F4QM1R
npm run start:web -- --document
https://1drv.ms/x/s!jkcH7spkM4EGgcZUgqthk4IK3NOypVw?e=Z6G1qp
npm run start:web -- --document https://contoso-my.sharepoint-
df.com/:t:/p/user/EQda453DNTpFnl1bFPhOVR0BwlrzetbXvnaRYii2lDr_oQ?
e=RSccmNP
If your add-in doesn't sideload in the document, manually sideload it by
following the instructions in Manually sideload add-ins to Office on the
web.
3. In Word, if the "My Office Add-in" task pane isn't already open, open a new
document, choose the Home tab, and then choose the Show Taskpane button
on the ribbon to open the add-in task pane.
4. At the bottom of the task pane, choose the Run link to add the text "Hello
World" to the document in blue font.
Next steps
Congratulations, you've successfully created a Word task pane add-in! Next, learn
more about the capabilities of a Word add-in and build a more complex add-in by
following along with the Word add-in tutorial.
Code samples
Word "Hello world" add-in : Learn how to build a simple Office Add-in with only
a manifest, HTML web page, and a logo.
See also
Office Add-ins platform overview
Develop Office Add-ins
Word add-ins overview
Word add-in code samples
Word JavaScript API reference
Using Visual Studio Code to publish
Tutorial: Create a Word task pane add-in
Article • 03/14/2023
Tip
If you've already completed the Build your first Word task pane add-in quick start,
and want to use that project as a starting point for this tutorial, go directly to the
Insert a range of text section to start this tutorial.
Prerequisites
Node.js (the latest LTS version).
The latest version of Yeoman and the Yeoman generator for Office Add-ins. To
install these tools globally, run the following command via the command prompt.
command line
7 Note
7 Note
If you don't already have Office, you can join the Microsoft 365 developer
program to get a free, 90-day renewable Microsoft 365 subscription to use
during development.
command line
yo office
7 Note
When you run the yo office command, you may receive prompts about the data
collection policies of Yeoman and the Office Add-in CLI tools. Use the information
that's provided to respond to the prompts as you see fit.
When prompted, provide the following information to create your add-in project.
After you complete the wizard, the generator creates the project and installs supporting
Node components.
Tip
You can ignore the next steps guidance that the Yeoman generator provides after
the add-in project's been created. The step-by-step instructions within this article
provide all of the guidance you'll need to complete this tutorial.
2. Open the file ./src/taskpane/taskpane.html. This file contains the HTML markup
for the task pane.
3. Locate the <main> element and delete all lines that appear after the opening
<main> tag and before the closing </main> tag.
4. Add the following markup immediately after the opening <main> tag.
HTML
5. Open the file ./src/taskpane/taskpane.js. This file contains the Office JavaScript API
code that facilitates interaction between the task pane and the Office client
application.
6. Remove all references to the run button and the run() function by doing the
following:
7. Within the Office.onReady function call, locate the line if (info.host ===
Office.HostType.Word) { and add the following code immediately after that line.
Note:
JavaScript
Your Word.js business logic will be added to the function passed to Word.run .
This logic doesn't execute immediately. Instead, it's added to a queue of
pending commands.
The tryCatch function will be used by all the functions interacting with the
workbook from the task pane. Catching Office JavaScript errors in this fashion
is a convenient way to generically handle uncaught errors.
JavaScript
await context.sync();
});
}
The first parameter to the insertParagraph method is the text for the new
paragraph.
The second parameter is the location within the body where the paragraph
will be inserted. Other options for insert paragraph, when the parent object is
the body, are "End" and "Replace".
JavaScript
7 Note
Office Add-ins should use HTTPS, not HTTP, even while you're developing. If
you're prompted to install a certificate after you run one of the following
commands, accept the prompt to install the certificate that the Yeoman
generator provides. You may also have to run your command prompt or
terminal as an administrator for the changes to be made.
Tip
If you're testing your add-in on Mac, run the following command in the root
directory of your project before proceeding. When you run this command, the
local web server starts.
command line
command line
npm start
To test your add-in in Word on the web, run the following command in the
root directory of your project. When you run this command, the local web
server starts. Replace "{url}" with the URL of a Word document on your
OneDrive or a SharePoint library to which you have permissions.
7 Note
command line
https://contoso.sharepoint.com/:t:/g/EZGxP7ksiE5DuxvY638G798BpuhwluxCM
fF1WZQj3VYhYQ?e=F4QM1R
https://1drv.ms/x/s!jkcH7spkM4EGgcZUgqthk4IK3NOypVw?e=Z6G1qp
npm run start:web -- --document https://contoso-my.sharepoint-
df.com/:t:/p/user/EQda453DNTpFnl1bFPhOVR0BwlrzetbXvnaRYii2lDr_oQ?
e=RSccmNP
2. In Word, if the "My Office Add-in" task pane isn't already open, choose the Home
tab, and then choose the Show Taskpane button on the ribbon to open the add-in
task pane.
3. In the task pane, choose the Insert Paragraph button.
5. Choose the Insert Paragraph button again. Note that the new paragraph appears
above the previous one because the insertParagraph method is inserting at the
start of the document's body.
Format text
In this step of the tutorial, you'll apply a built-in style to text, apply a custom style to
text, and change the font of text.
HTML
4. Within the Office.onReady function call, locate the line that assigns a click handler
to the insert-paragraph button, and add the following code after that line.
JavaScript
document.getElementById("apply-style").onclick = () =>
tryCatch(applyStyle);
JavaScript
await context.sync();
});
}
6. Within the applyStyle() function, replace TODO1 with the following code. Note
that the code applies a style to a paragraph, but styles can also be applied to
ranges of text.
JavaScript
HTML
4. Within the Office.onReady function call, locate the line that assigns a click handler
to the apply-style button, and add the following code after that line.
JavaScript
document.getElementById("apply-custom-style").onclick = () =>
tryCatch(applyCustomStyle);
JavaScript
await context.sync();
});
}
6. Within the applyCustomStyle() function, replace TODO1 with the following code.
Note that the code applies a custom style that does not exist yet. You'll create a
style with the name MyCustomStyle in the Test the add-in step.
JavaScript
HTML
4. Within the Office.onReady function call, locate the line that assigns a click handler
to the apply-custom-style button, and add the following code after that line.
JavaScript
document.getElementById("change-font").onclick = () =>
tryCatch(changeFont);
JavaScript
await context.sync();
});
}
6. Within the changeFont() function, replace TODO1 with the following code. Note
that the code gets a reference to the second paragraph by using the
ParagraphCollection.getFirst method chained to the Paragraph.getNext method.
JavaScript
const secondParagraph =
context.document.body.paragraphs.getFirst().getNext();
secondParagraph.font.set({
name: "Courier New",
bold: true,
size: 18
});
To test your add-in in Word, run the following command in the root directory
of your project. This starts the local web server (if it isn't already running) and
opens Word with your add-in loaded.
command line
npm start
To test your add-in in Word on the web, run the following command in the
root directory of your project. When you run this command, the local web
server starts. Replace "{url}" with the URL of a Word document on your
OneDrive or a SharePoint library to which you have permissions.
7 Note
command line
fF1WZQj3VYhYQ?e=F4QM1R
e=RSccmNP
3. Be sure there are at least three paragraphs in the document. You can choose the
Insert Paragraph button three times. Check carefully that there's no blank
paragraph at the end of the document. If there is, delete it.
5. Choose the Apply Style button. The first paragraph will be styled with the built-in
style Intense Reference.
6. Choose the Apply Custom Style button. The last paragraph will be styled with your
custom style. (If nothing seems to happen, the last paragraph might be blank. If so,
add some text to it.)
7. Choose the Change Font button. The font of the second paragraph changes to 18
pt., bold, Courier New.
2. Locate the <button> element for the change-font button, and add the following
markup after that line.
HTML
<button class="ms-Button" id="insert-text-into-range">Insert
Abbreviation</button><br/><br/>
4. Within the Office.onReady function call, locate the line that assigns a click handler
to the change-font button, and add the following code after that line.
JavaScript
document.getElementById("insert-text-into-range").onclick = () =>
tryCatch(insertTextIntoRange);
JavaScript
// TODO2: Load the text of the range and sync so that the
// current range text can be read.
await context.sync();
});
}
6. Within the insertTextIntoRange() function, replace TODO1 with the following code.
Note:
The function is intended to insert the abbreviation ["(M365)"] into the end of
the Range whose text is "Microsoft 365". It makes a simplifying assumption
that the string is present and the user has selected it.
The second parameter specifies where in the range the additional text should
be inserted. Besides "End", the other possible options are "Start", "Before",
"After", and "Replace".
The difference between "End" and "After" is that "End" inserts the new text
inside the end of the existing range, but "After" creates a new range with the
string and inserts the new range after the existing range. Similarly, "Start"
inserts text inside the beginning of the existing range and "Before" inserts a
new range. "Replace" replaces the text of the existing range with the string in
the first parameter.
You saw in an earlier stage of the tutorial that the insert* methods of the
body object don't have the "Before" and "After" options. This is because you
can't put content outside of the document's body.
JavaScript
7. We'll skip over TODO2 until the next section. Within the insertTextIntoRange()
function, replace TODO3 with the following code. This code is similar to the code
you created in the first stage of the tutorial, except that now you are inserting a
new paragraph at the end of the document instead of at the start. This new
paragraph will demonstrate that the new text is now part of the original range.
JavaScript
2. Call the context object's sync method to send the queued command to the
document for execution and return the requested information.
3. Because the sync method is asynchronous, ensure that it has completed before
your code calls the properties that were fetched.
The following step must be completed whenever your code needs to read information
from the Office document.
1. Within the insertTextIntoRange() function, replace TODO2 with the following code.
JavaScript
originalRange.load("text");
await context.sync();
When you're done, the entire function should look like the following:
JavaScript
originalRange.load("text");
await context.sync();
await context.sync();
});
}
2. Locate the <button> element for the insert-text-into-range button, and add the
following markup after that line.
HTML
4. Within the Office.onReady function call, locate the line that assigns a click handler
to the insert-text-into-range button, and add the following code after that line.
JavaScript
document.getElementById("insert-text-outside-range").onclick = () =>
tryCatch(insertTextBeforeRange);
JavaScript
// TODO2: Load the text of the original range and sync so that
the
// range text can be read and inserted.
});
}
The function is intended to add a range whose text is "Office 2019, " before
the range with text "Microsoft 365". It makes an assumption that the string is
present and the user has selected it.
The second parameter specifies where in the range the additional text should
be inserted. For more details about the location options, see the previous
discussion of the insertTextIntoRange function.
JavaScript
const doc = context.document;
const originalRange = doc.getSelection();
originalRange.insertText("Office 2019, ", Word.InsertLocation.before);
JavaScript
originalRange.load("text");
await context.sync();
8. Replace TODO3 with the following code. This new paragraph will demonstrate the
fact that the new text is not part of the original selected range. The original range
still has only the text it had when it was selected.
JavaScript
JavaScript
await context.sync();
2. Locate the <button> element for the insert-text-outside-range button, and add
the following markup after that line.
HTML
4. Within the Office.onReady function call, locate the line that assigns a click handler
to the insert-text-outside-range button, and add the following code after that
line.
JavaScript
document.getElementById("replace-text").onclick = () =>
tryCatch(replaceText);
JavaScript
await context.sync();
});
}
6. Within the replaceText() function, replace TODO1 with the following code. Note
that the function is intended to replace the string "several" with the string "many".
It makes a simplifying assumption that the string is present and the user has
selected it.
JavaScript
command line
npm start
To test your add-in in Word on the web, run the following command in the
root directory of your project. When you run this command, the local web
server starts. Replace "{url}" with the URL of a Word document on your
OneDrive or a SharePoint library to which you have permissions.
7 Note
command line
https://contoso.sharepoint.com/:t:/g/EZGxP7ksiE5DuxvY638G798BpuhwluxCM
fF1WZQj3VYhYQ?e=F4QM1R
https://1drv.ms/x/s!jkcH7spkM4EGgcZUgqthk4IK3NOypVw?e=Z6G1qp
npm run start:web -- --document https://contoso-my.sharepoint-
df.com/:t:/p/user/EQda453DNTpFnl1bFPhOVR0BwlrzetbXvnaRYii2lDr_oQ?
e=RSccmNP
2. If the add-in task pane isn't already open in Word, go to the Home tab and choose
the Show Taskpane button on the ribbon to open it.
3. In the task pane, choose the Insert Paragraph button to ensure that there's a
paragraph at the start of the document.
4. Within the document, select the phrase "Microsoft 365 subscription". Be careful not
to include the preceding space or following comma in the selection.
5. Choose the Insert Abbreviation button. Note that " (M365)" is added. Note also
that at the bottom of the document a new paragraph is added with the entire
expanded text because the new string was added to the existing range.
6. Within the document, select the phrase "Microsoft 365". Be careful not to include
the preceding or following space in the selection.
7. Choose the Add Version Info button. Note that "Office 2019, " is inserted between
"Office 2016" and "Microsoft 365". Note also that at the bottom of the document a
new paragraph is added but it contains only the originally selected text because
the new string became a new range rather than being added to the original range.
8. Within the document, select the word "several". Be careful not to include the
preceding or following space in the selection.
9. Choose the Change Quantity Term button. Note that "many" replaces the selected
text.
Define an image
Complete the following steps to define the image that you'll insert into the document in
the next part of this tutorial.
JavaScript
"iVBORw0KGgoAAAANSUhEUgAAAZAAAAEFCAIAAABCdiZrAAAACXBIWXMAAAsSAAALEgHS3X
78AAAgAElEQVR42u2dzW9bV3rGn0w5wLBTRpSACAUDmDRowGoj1DdAtBA6suksZmtmV3Qj+
i8w3XUB00X3pv8CX68Gswq96aKLhI5bCKiM+gpVphIa1qQBcQbyQB/hTJlpOHUXlyEvD885
vLxfvCSfH7KIJVuUrnif+z7nPOd933v37h0IIWQe+BEvASGEgkUIIRQsQggFixBCKFiEEEL
BIoRQsAghhIJFCCEULEIIBYsQQihYhBBCwSKEULAIIYSCRQghFCxCCAWLEEIoWIQQQsEihC
wQCV4CEgDdJvYM9C77f9x8gkyJV4UEznvs6U780rvAfgGdg5EPbr9CyuC1IbSEJGa8KopqB
WC/gI7Fa0MoWCROHJZw/lxWdl3isITeBa8QoWCRyOk2JR9sVdF+qvwnnQPsF+SaRSEjFCwS
Cr0LNCo4rYkfb5s4vj/h33YOcFSWy59VlIsgIRQs4pHTGvYMdJvIjupOx5Ir0Tjtp5K/mTK
wXsSLq2hUWG0R93CXkKg9oL0+ldnFpil+yhlicIM06NA2cXgXySyuV7Fe5CUnFCziyQO2qm
g8BIDUDWzVkUiPfHY8xOCGT77EWkH84FEZbx4DwOotbJpI5nj5CQWLTOMBj8votuRqBWDP8
KJWABIr2KpLwlmHpeHKff4BsmXxFQmhYBGlBxzoy7YlljxOcfFAMottS6JH+4Xh69IhEgoW
cesBNdVQozLyd7whrdrGbSYdIqFgkQkecMD4epO9QB4I46v4tmbtGeK3QYdIKFhE7gEHjO/
odSzsfRzkS1+5h42q+MGOhf2CuPlIh0goWPSAogcccP2RJHI1riP+kQYdVK9Fh0goWPSAk8
2a5xCDG4zPJaWTxnvSIVKwKFj0gEq1go8QgxtUQQeNZtEhUrB4FZbaA9pIN+98hhhcatbNp
qRoGgRKpdAhUrDIMnpAjVrpJSNApK/uRi7pEClYZIk84KDGGQ+IBhhicMP6HRg1ycedgVI6
RELBWl4POFCr8VWkszpe3o76G1aFs9ws+dMhUrDIInvAAeMB0ZBCDG6QBh2kgVI6RAoWWRY
PqBEI9+oQEtKgg3sNpUOkYJGF8oADxgOioUauXKIKOkxV99EhUrDIgnhAG+mCUQQhBpeaNb
4JgOn3AegQKVhkvj2gjXRLLrIQgxtUQYdpNYsOkYJF5tUDarQg4hCDS1u3VZd83IOw0iFSs
MiceUCNWp3WYH0Wx59R6ls9W1c6RAoWmQ8PaCNdz55hiMEN4zsDNhMDpXSIFCwylx5Qo1a9
C3yVi69a2ajCWZ43NOkQKVgkph5wwHi+KQ4hBs9SC9+RMTpEChaJlwfUFylWEafP5uMKqII
OPv0sHSIFi8TFAzpLiXxF/KCbdetEGutFUSa6TXQsdKypv42UgZQhfrWOhbO6q8nPqqCD/z
U4OkQKFpm9B7SRbrTpQwzJHNaL/VHyiRVF0dfC2xpOzMnKlUgjW0amhGRW/ZM+w5sqzuqTN
Wtb9nKBZDLoEClYZGYe0EYaENWHGDaquHJv5CPnz/H9BToWkjmsFkTdOX0GS22p1ovYNEdU
r9vCeR3dJlIG1gojn2o8RKPiRX+D0iw6RAoWmYEH1HioiQZqq47VW32dalUlfi1fQf7ByEd
UQpMpYfOJ46UPcFweKaMSaWyaWL8z/Mibxzgqe3G4CC6pT4dIwSLReUCNWrkJMdjh8sMSuk
1d3bReRGb3hy97iS/SEl+5bQ0LqM4B9gvytaptC6kbwz++vD3ZG0r3EBDoWUg6RAoWCd0D9
isXReTKTYghZbhdUB/UYlKV2TSHitZtYc9QrqynDGy/GnGg+4XJr779ShJ0gNdAKR3i/PAj
XoIZe8BGBS+uhqtWAF4VXUWu3G//ORVqdVRiEumhWgFoVHT7gB1LnFAvVaJxYZJ+qx/XRuo
1X0+RFqzPsF/QFZuEgrVcHnDPCGbFylnajN/wAZZvqgpR8IzO275tTvjnwl/4sORC6C9xWJ
LoYCKNrbpuR3Jazp/jxdUJmksoWIvvAfcLsD4LuLfn5hOJhWlVQ+lyNZDFcUl636GY5/Wpy
zo3FRZ+WBeT1JhpGDVlIMMbjYfYM3Ba4zuXgkUPGBD5B5Kl6LaJ4/uh/CCDTvDjW4ROxZm4
gj7+dwZLY24067AkF9OtesCaRYdIwaIHDIzMrmSzv2NNTgl4fLlSXw6kjs8pWN+FfHu3n8p
/xpSBjWrwL0eHSMGiB/TL+h1JnNJ+xTA6MawXh1ogTWA5S5tvLS8vMVUM6s1j+TKZEASjQ6
RgkVl6wH4pcUM+zs8qBq9WyRyMGozP+5J0/nzygrrLSkS4ONPmNg/vyr1npiQG9+kQKVhkB
h5woFbSI8EuQwxTkS1j2xoG0zsHeBVcRsl/RNMqyoMOG9WRjAUd4pzD4GhoHjDsMIEqchX4
8JuUgU1zJN+kSa4D+LnjHfXiqqsa5Oejb8J/fs9TAZjFtiXXvgADpaqXZsqUFRY94NRq1ag
ErFbrRWzVR9Tq9JlOrWy75NncCf982n+o+sYCDJTSIVKw6AGnRhoQbZsBv3S+MlyxAtC7xP
F9WMUJDsi5M+gmVCWImpvolorOgXzTMPBAKR0iBWvuPWB4+4CiWj2Rz3MPcFSXHb90Nmawb
WDLRVZAc2pHZTkF2fWDKugQRqBUCvcQKVj0gI6qRxYQtfvGBIUdvHQ2fmk/VR7fk5Q5jr+2
fmfygrpTfM+fu8qa6lEFHcIIlGocolWkQwwcLrr79oBB9YRxg7SDXbDjJISue71LHJWnrno
+vRh+BX2Xq2QOO6+Hf3TTXsYl43M3BhVcZFNjEyvIluUNvAgrrIX1gINqRdpvM0C1EhatbB
vowaM5neOVe/L2VX176/jip88CUysAhyV5SRheoFRSfV+i8RAvckH+XKyweBW8qNWeEelEP
1XkKqgQw3j/T3sxyNv6cSKNm02xA3KrOvLV1gq4Xh1u3vUusWcE7KESK7jZlHvSoDqU+q/4
CAUrItomWtUoRvup1KpRCWxb0KiNqFXvcoreWCem/ETh+ILRYJnvJzlxz+7wrt/l9qkuHUI
IrMk9bxaZEjIltl2mYMWDjoVWFae1sAouVeQq2LUYZwfRaVG1dR9PnKp802EpxG016TCOgZ
sOb6tk9RayZVZVFKwZ8cff4b/+Htcq8sd17wInJt5UA17SUqnVWR0vbwf5Qn5KgPO6bo0mU
0K2LJetbgtvqjgxQw8uqcbthDH+OrHS/5FV19MuJDXreoSCFQC9C3yxisQK8hVk1dteZ3W8
qQY2VFm68OF/emj0JNJ430DKQCKN3gU6FrrNSHf9VaMrfI68F+ynXVKpkhxndRyX0TlQzv4
hFKyABWuwMPGROWxiJ6kdmmibaJu+7gTpPRbgDbZsqJa9/T8AMrvIlnWx/m4Tx+XhY4yC5R
XGGjzRbeHlbd3ZsWQO+Qp2mth84nFtSBoQtS0M1cobqqCD50BpMovrj/Dpufyk1OBXZueKg
yq6KVjEI/bZMf3ef6aErTp2XiOzO8UtIe0gCuCoHMWm5MLWyJfK09HTdihdvwPjc+w0J4wv
bJv4KhfF2VIKFnHLm8f4KjfhkF0yh00TN5vYfDJ510wVED0qR7ENv7Sa5SZQmlhB/gF2XsO
oTdj+O6tjz8Dh3Tlbaow9XMNy/153rGGpDIJ+Ycv5bm6bcvVR5YaiPFCy8Kze6s+4lj4VpI
HS1Vv4sORqa09YrlL5fa5hUbBmLFiDd/am6Soi0LtAqzqyMK9Sq8BDDEQVdMBooDSxgvXih
AV14RfqxgBSsChYcREsmyv3lImtcU5raJs4q8sjV/MYYpgLrj9SxlP2C/iuiXxFl1EYL4GP
ym5/TRQsCla8BKu/3qFNbLl80a9yVKuwUIWzpmKQrnIPBcsrXHQPT+AucXzf70l91lahclT
2FV7tNmEV8fI2t24jI8FLEC52Ysv9wpbAtsVLGNNy2+VyFWGFNX+4SWyReYHpKgrWUuAmsU
XiDNNVFKwlsxJBLGyRGVh7LlfFAq5hzeTd38LL27oo0ABpnykSIG766pzWYH3GS0XBWvJr7
yLg8/1F1J18l4pk1lXuhM1CaQkJPixN/jvXKlGMpVpa8u7CvSkj9CGshIIV92e7tOvxeBXG
hGFIrN6Sp0ZPa5Jw1gfsdEzBWmbGb4BuE4d3JbdKtszHe1jllZTjsqTBvJtymFCwFpbxpRM
77nAouzE+MnnBAiazK++rYZ9Flw4B4mODgrWkpG5I1nHf1gDFrPa1gveRNmQc+5jnOL2L/p
DqzoGkN2mArpChFgrWXD3eS5J38KDJjDTKsMG4aaDlrXTjr1UdJkJPTLpCChYBAEmzSqcHO
X8utySZXV65AFBFGezjgULBS1dIwaIflDzehVVeVZHFiIN/VFEGoZtVtyUxbtwrpGDNDb3f
heUH26Z4Nq3bkhw5TKT9dtciqihDtynpWN2mK6RgzS/vemH5QemU9kZF0tohX6Er8VteSTm
WPQlOZa5w4gwRQsFaZD/Yu5APLOhdyvs6XOfqu+faVhFlOKsrfwXjRRZHzFOwlumeKbkqr2
xaVUmOdL3IiEPA5ZXmhPn4b2edy1gUrOVh/O2uaY/Vu2TEITi1eiCPMrRNnD9XC9Yz0Zgnc
3SFFKxl9YPd5oT+Su2nkgQjIw7TklhR7ldMbOBzQldIwVpOxu+Z8SWScY7K8iKLEQf3bFTl
UYZWdZjXVT4zTLrCGD16eAlm6QfdCJZ9WEdYLbYjDmG3FU/mRqoJD90EV3+Ga//o5aUPS77
m2QiFrbQm6l24+ok6B+g2R0pj2xWy9SgFa6HV6o74kO9Ykx/vNsdlyficfGVkanRIgpV/4E
uw3v/E4xZBMheYYKn2VZ0HcfS0quK6YaaE4/t8U9MSLlN55X4aRedAXouxVZab54Q0ytBtT
nH933KvkIJFwdIEGsaRVjeZEiMOHsurRmWKyTfdlrj1wb1CCtZy+cHT2nSjorotuWbFvMj6
w6/xhxN81xL/G/zsvY7ks384wfdBDHBURRmkB3EmukIBHpOaBVzDmlF55Wa5ffyeyZZF4Vs
rILM79e0XGb/5JX7zS8nHt+r92rDz79gvhPPWVkcZpF0S9cgTpHf51maFtQSCpTqOo0d1WC
fPQRUyVFGGs7ouKaq5+IJmJdJYv8PLTMFaDj/ojcZDyd5ZMkd7IqKKMsDHqEcGsihYS+oHT
0zvX016v3FQhYBqrV1/EGeCKxw7pkPBomAtGokV8W3dbXq/Z6A4rMNpYE5Wb8mjDPA9SZuu
cOb3Ey9B6OVVUH5wwFEZW3Xxg5kSTkxfUmjj/MrCdz7+ovpvclxYo2HTVKqVz5xtqyo6zfW
il+VIQsGaGz/4xnevBelhHQD5Cl7eDqA88fCpcX6cns0Fv3JPHmUQWrZ7Y/yYDvcKaQkX2Q
+6P46j5+uS5IN2xCEO9C7xrTWbC36toiyOpgq+KS25SVfICmtpyqsTM5ivbA/7HN8Iy1emj
qQKOGu0lIHrj+SfEhD+5mFJ0t85AlQDJrrNwA6Kt01xuZCukIK1sILlIS+qolGRLJDZEQc/
N6dmxqfmU85dufbTANbpPKCa3wXfa+3Co6JjIWX4coWzWt2jJSRT+EGftc/4nSNdlMmWo86
R5ivDg3XdlryBVwR8ZCrVIdiTACdjrnBaJx7g24CCRcIqrwKvO1pVifNKpCPtoZwyRlrQfD
0jM6iJMgQuoEyQUrAWX7B6F8ELVu8S38jMTqYUXS8BZ4ag8VBnGyP7NgQb6z/qMX7ZhV/le
pGnoyhYMeP/vouRHxzw5rG80V0008CcZrBzEORS0VSoogxQDBz0D6fpULAWSrAi8IPDukYm
E2uF0LfbBTPooQVCIGiiDG0zrEbG7ac8pkPBWiCEwEG3GeLOd/up3IiFXWQ5Xdjx/ZntfKm
iDEC4FR9dIQVrQUhmxQXgsLf5pXem0JE9PDN4/jyAELnnS62JMoTa8P7EpCukYC0EH4QZv5
JiH9YZJ6SIg9MM9i5nZgY1VWQgB3EmXnNh9ZCCRcGaSz4cvYE7VhQjoaSHdUKKODjNYIDzu
KZl9ZZSI76pRJF1oiukYC2CH3TGoBHccRw99mGdcQKPODjN4Omz2YTabVRa3G3izeMovoHx
c+wssihYc+8H30Z1Szcq8tBmgKvv8TGDmV3xweC8DtEwPk2HgkXBmm8/eFoLd+lXuH+kCzc
BRhycZtAqzibUDiCxoiyvzuqRjuQQyuf1Ilu/UrDm2Q9G7Jikh3WCKrKcZvDN41BC7X/+Nz
Bq+Nk3yurJZnx6UPTllap8/oBFFgVrfv1gxILVu5QfnUvmcOWe3y8+CBB0DuRHgvyI1F//C
p9+i7/6Bdbv4E/zuv5/yayyH3QYB3EmVrXCr/jDEu8DCtZ8+sG2OYNz+e2n8m27a76ngQ3+
eYDtrlZv9UXqp3+BRMrVP9FUi1/PQiwEwUoZdIUULPrBaZAeoAtqUEXj4SzbOWmiDG0zuuV
C4bcsyDddIQVrDhCO43iblhrMLfRMmSP1+fCP4ITz//4WHUuZ7dpQJ0VndfR6vHkDXSEFa/
4E68Sc5Tejuns/Mn3dmVY4tUOvg9//J379C/zbTdQ/wN7HcsHSRBla1dmUV3SFFKy5JHVD7
HAS9nEcPefP5YZ0rTDd8BtBBIMKtf/oJwDwP/+N869w/Hf44n3861/iP/4WFy+U/0QTZfB/
EGe9qOyo5bKkFa4MXWE4sKd7OOVVtxnFcRw9x2X5cs+miRdXXX2Fb62RwRMB5hga/4Df/2o
6+dNEGfwfxLle7ddEnqOwp7WRY9gfliJK27PCIh4f0YJDmTmqwzruIw69C5zVh/8FyG//aT
q10nRl8H8QJ1/pq1VmVzKIyCXCpaYrpGDNkx98W4vFN3ZUlucPrlXm7JhueE2vEukRKfS8k
do5EDdPPWsfoWBF6gfP6gEvAKcM5Cv9/zIl5a0rKZEu5bVeUBGHaFi9pbz5/R/E2aiOaHcy
611oTkwKVti89+7dO14Fd49QC3sfyz+183qkwjosBXacba2AfEVcJrdlSHUKR9SmFdxsyjX
uRW6WO2vu+eRL5USc/YKvaHvKwPYriZV+kfPy1ZJZ7Iz63D1DuZT5c953rLBi4gcDyYsmc9
g08cmXkk29xAryD3CzqbyNBXVTzbnyE3GIrnrdVf6YpzW/B3Gc247dVl++PRdZ3Za40qf5O
rM6N07Boh8U7yKfO1a2VO28njCeM7GCT750dWupDuv4iThEQ2JFZ119TsRZL478+F+Xhsth
nv2ysPSu6TbzLYc/U7BmgvCm9Bm/ShnYtiRS1TlA4yEaD3H+fEQQN5+46imq2q3fqMb62mb
Lyvld/g/iOM8k2mcDBl/Tc5ElFNfJXHQDIilYxIVa3Rm5o3wex0kZ2KqL+3ftp3hxFXsGGh
U0Ktgv4Is0Xt4eytaVe5MrAlXT95Qx9Zj1yNBEGXoXk+c5pwydZR5EGWzXPCjWfBZZvUvxi
cWldwrWbHjXm1xe+Vy92jRH1KpzgL2P5U3Tz+ojp2TyD5SVyADV9r+wTRYfNFGGVnWC706k
YdTwyZfYqktkS4gytKrDKzxw9EEVWexBSsGaDb3fTRYsP3lRofl65wD7BV1fBGFH302RJbW
rwt0bEzRRBjcHca79UECt3pLIllOju60RKXd+cW9F1umzkQV1ukIKVoz8oLME8Hkcx6l9vU
vsFyZvJDnv29XC5JdQFVlOfxSf8krFUXlCeZXMiWLnlC3BBY+30BqUb56LrBO6QgpWHAUr0
OV2Z49NVUJdoGMNb103iqNq+o7wx0RPV2yqowzd5uSMW7eJPUOymDiQLWc1NL6057/Icr9X
SChY8ypYmnUQvWYNcBPLUk3WEfb4Z0ggUYZuE1YR1meSWmxgBp1r7SrF8VZkdQ5Glh2Tubj
HRyhYS+cHO5bfXXan9LhPFTrvBDfHiVWHdRCbiIMmynBWn24T9rSGr3LKo9HfXygX9Z11nL
ciS7jIbOlHwYpXeeW/PcP3DpHSz4xRlVQu+x84N8WcxCHikFjR7QB4OOdsByBe3pYsLyaz2
H6FTVOuj4PX8lZkveVeIQUrzoI10cQl0hNaxDkrLDfbdon0yMKT+0Mqvcv4Rhw2qsqqx89B
nLM69gx5CZzZxc5ryev6LLKEGauJdGCjISlYxK8fnHgcZ72Im01dh1+MtsfL7E7OVW1UR/b
LT8wpvn/VYZ3ZRhxSN3S1jM+DOGuF4b6EcFoAwJV7uNkUk1+DqtlbkSUU3SyyKFhzU14Zn/
crF826eO9iZP9r09S1kcmWR+zb6bOpl/xVh3VmGHHQ7FT6b9k+qJJ6l3hVxJ4h7jYOjpQPt
KljDWs6D0UWE6QUrFiQWBl53gpCI7d7Pyyg6B/UDUer39Vb2KpLNCuRxkYV1x+NfHEPjX1V
h3Uwo4jD+h2lmvufiOM85m235ek2cVjCy9uizUysYPMJdn6QLT8rWcI0HbpCCtZ8lFdOd5C
6oSuy7LvIaZGcD/y1AjIlbFsjDY57l97HmqpM1kwiDvryymcDDLuNcrclbpKe1bFfwOFd8e
sns9h80k9s+SmyGMgKGjbwc81ZvT+Rwfh85J3npodcIo2bzb4rPH+O/cIEQRQOFWqe4frjO
xPZfCIvHAY/bDTkHyjlwE6BBjVAO5nTLd7lH8i+gdbQIx/endp6f3o+LJN7F/hitf//mq6E
hBVWkH7QqVbdpqutK2d4WjO7eFCyfZVD4+GEgz7+1QrqoMBaIbqIw8QoQ1BqBXXyw3adL65
KfpvOFT2fK1l0hRSsOfCD475m05zwdLXvnz0DL66i8VByx3YOsGcEMDJeOPo7UvVENahCE2
VwcxAnQLpN7Bfw8rZygd/DShb3CilYMRKsN67Xp3sXw/Upu1mopn2KfXzXqGHnNfIPROGwT
WVQM01VveGTuSgiDvoog+cpgT69/4scju8HU9kJx3TWi3M2ryhmcA1rmvexVcSnjntbM5ZC
xaY5YrXsjaSOhY6FRBopA8kcUoauIUnjod8tM0kxpVhC6l0o85ZBoVnKiXgdTeJV09iojvy
+vM2nEC6vPaOEa1gUrNAFq22OpNWPyl5GeAqa5Z7z52hUAh5oOkAY/DOgbeLwbmjl6h0Yak
/tcyJOYDWggY1qf9vUw6I7xqbpnNZgfUbBoiWM3A96a89wWJrabpw+w8vb2C+EpVZQr75nS
iFGHDRRhrYZC7Wy6+j9AqzPvKRzB3WZc7WRrpAVVhRc/AvSPxOfk37sxnoRawUkc0ikJR6w
28J5HWd1nNYiGgm1/Up+cigka3blnq4/xLzMTPT2wx6WkCmxwqJghcnvj/DTDXElItgVk/c
NAPjWms3QOjtbr6oKA/5h1eNdAbSqOL6/UG+exMrI6udpDYk0BYuCFSZ//B3+5M/6/9+7wF
e5IPNBMUG1sBJsehPA9Ue6iTgLeW2FvHHHcttEiDjgGpZrBmqFIKalxhPVYZ1gIw6a+V0I4
iBOPBEie1QrCtbM3nwLQ+dAua6cLQfWxeEjU/mpbhONh4t5bdtPOZ6egjULuk1f01Jjjqrp
eyLtfYC7k9VburWbwCNmfM5RsFheLbQcqyfrCJMTvaFpu9qxIj2IEz0nJu8eClb0tf2iv+1
Uh3Xgu1XWlXu6TqpH5QW/sOfPAztQRcEiruhYvqalzgW9S3yjsGZrBe/9BhIruKZ2fGf1uC
RFWZ5TsFjVzxlvHitrAc9FluawN3y3bGd5TsEiEt4uzRNStf6dzMkb3enRRxna5uLXrf0K/
SCApkAULOK2nl+k8yITaoGnyqOL2fLUp+E+Mr2II4t0QsHyJVhLhUpH7L4r7pkYZViex8BS
FekULApWpGgm60wVcdCom7N59JLQbXHp3TMJXgK3vOvBqKF3gY6FbhPdJr5rLn5p8HVppJe
Tk+tVV10c9ONjF/UgzshNtoKUgR+nkTKGbRqJJ3j42f8Ds4luEx2rr2XfX6BjLdRNqJqsA8
AqTgj967sydJt4cXWh3gypG8M2DKsFAGzJQMGaE2wzdV7v/3/vYl43wpJZbFty0ZmoOJr5X
Qiha02U1+QnOSRz/ZbWdmsgTWiDULDmkt5Fv93VfPlKje40KsrjykJr4HFBn23Lds9ujoaO
gkVfGWtfqXF2mvZVQgcogZi0bKebo2CRBfSVmo7G0gahmv6lsy2v6OYoWMuL7ewiftPPyle
qJutA1oJd1SFe9fcXz83ZD5vvmlPPXiUUrBBpm8Pooz1gZmAr7LtlYXylZiqXUDFldnVtZA
IfHTZbN6e67IkVZMvIllm+UbDiR6uKRkWuDs5HfTI39CPz6Cs10/QGa1L6KIOf4ayzdXNTF
baZXWxUKVUUrBhjh7bdJyHt289pW+LvKzUrU4OIgz7KoNlVjJub8ybxmV3kK9xJpGDNj2wd
lX3Fi2LuKzV7f0dlvK3pogzjW4rxdHOef3H5CvcWKVhzSLeJ43KQrd/j4yuTOeUqsl21ae7
YjoXT2tyUk1N51Y9MShUFa845q6NRCTdtNFtfGc9rjgiDIMks8hXuA1KwFojTGo7LUcfZZ+
srI3Nz3/3g6aKP2nITkIK1yLRNHJVnHF6fua/06eZsVYrDYaYr93CtQqmiYC00024jRkZMf
KUtSQM3B8RxLAU3ASlYSydb31Tw5vEcfKsh+cqZuznPV2OjyhHzFKylpNtEozKXzVXc+8p4
ujkPpG7gepWbgBSspSeCbcRoGA+LzkX3GDdmmZuAsXpc8hLMkrUC1uo4q+Pr0nINYpiLQjJ
b1kX2ySzgEIp4yNZOE5tPkMzyYsSlYLzZpFpRsIiaTAnbFvIPph75R4L8Lexi5/WEIdWEgk
UAIJFGvoKbTS+jlYlPVm9h5zU2TUYWKFhketnaeY3MLi9GRFL1yZfYqlOqKFjEK8kcNk1sv
+qHoUgoFzmLzSfYqjOyQMEiQZAysFXHJ19OMWaZuCpjV3D9EXbYv5iCRQJnrYBti9uIgUmV
vYzBIcUAAAIqSURBVAmYLfNiULBIaGRK2GlyG9HfNdzFtsVNQAoWiYrBNiJlayq4CUjBIjM
yNWnkK9i2uI3oVqq4CUjBIjPG3kbcec1tRPUlysL4nJuAFCwSJ9mytxEpWyNF6Ao2n2CnqZ
yXQShYZGasFbBV5zZiX6rsTUDmFShYJNbY24jXHy3venxmt39omZuAFCwyH2TLy7iNuH6nv
wlIqaJgkXmzRcu0jWhvAho1bgJSsMg8M9hGXL+zoD9gtp9X4CYgBYssjmwZtUXbRrQPLe80
KVUULLKI2NuIxudzv41obwJuW9wEpGCRRWe92O/FPKfr8VfucROQgkWWjExp/rYR7c7FG1V
KFQWLLB+DXszx30a0NwF5aJlQsChb/W3EeMpW6gY3AQkFi4xipx9itY1obwJuW5QqIj5keQ
kIEJuRrhxfSlhhkSlka4YjXTm+lFCwyNREP9KV40sJBYv4sGY/bCNeuRfuC63ewvYrbgISC
hYJQrY2qmFtIw46F6cMXmlCwSIBEfhIV44vJRQsEi6BjHTl+FJCwSLR4XmkK8eXEgoWmQ3T
jnTl+FJCwSIzZjDSVQPHl5JAee/du3e8CsQX3Sa6Y730pB8khIJFCKElJIQQChYhhFCwCCE
ULEIIoWARQggFixBCwSKEEAoWIYRQsAghFCxCCKFgEUIIBYsQQsEihBAKFiGEULAIIRQsQg
ihYBFCCAWLEELBIoQQChYhhILFS0AIoWARQkjA/D87uqZQTj7xTgAAAABJRU5ErkJggg=="
;
Insert an image
1. Open the file ./src/taskpane/taskpane.html.
2. Locate the <button> element for the replace-text button, and add the following
markup after that line.
HTML
4. Locate the Office.onReady function call near the top of the file and add the
following code immediately before that line. This code imports the variable that
you defined previously in the file ./base64Image.js.
JavaScript
5. Within the Office.onReady function call, locate the line that assigns a click handler
to the replace-text button, and add the following code after that line.
JavaScript
document.getElementById("insert-image").onclick = () =>
tryCatch(insertImage);
JavaScript
async function insertImage() {
await Word.run(async (context) => {
await context.sync();
});
}
7. Within the insertImage() function, replace TODO1 with the following code. Note
that this line inserts the Base64-encoded image at the end of the document. (The
Paragraph object also has an insertInlinePictureFromBase64 method and other
insert* methods. See the following "Insert HTML" section for an example.)
JavaScript
context.document.body.insertInlinePictureFromBase64(base64Image,
Word.InsertLocation.end);
Insert HTML
1. Open the file ./src/taskpane/taskpane.html.
2. Locate the <button> element for the insert-image button, and add the following
markup after that line.
HTML
4. Within the Office.onReady function call, locate the line that assigns a click handler
to the insert-image button, and add the following code after that line.
JavaScript
document.getElementById("insert-html").onclick = () =>
tryCatch(insertHTML);
JavaScript
async function insertHTML() {
await Word.run(async (context) => {
await context.sync();
});
}
6. Within the insertHTML() function, replace TODO1 with the following code. Note:
The first line adds a blank paragraph to the end of the document.
The second line inserts a string of HTML at the end of the paragraph;
specifically two paragraphs, one formatted with the Verdana font, the other
with the default styling of the Word document. (As you saw in the
insertImage method earlier, the context.document.body object also has the
insert* methods.)
JavaScript
const blankParagraph =
context.document.body.paragraphs.getLast().insertParagraph("",
Word.InsertLocation.after);
blankParagraph.insertHtml('<p style="font-family: verdana;">Inserted
HTML.</p><p>Another paragraph</p>', Word.InsertLocation.end);
Insert a table
1. Open the file ./src/taskpane/taskpane.html.
2. Locate the <button> element for the insert-html button, and add the following
markup after that line.
HTML
4. Within the Office.onReady function call, locate the line that assigns a click handler
to the insert-html button, and add the following code after that line.
JavaScript
document.getElementById("insert-table").onclick = () =>
tryCatch(insertTable);
JavaScript
await context.sync();
});
}
6. Within the insertTable() function, replace TODO1 with the following code. Note
that this line uses the ParagraphCollection.getFirst method to get a reference to
the first paragraph and then uses the Paragraph.getNext method to get a
reference to the second paragraph.
JavaScript
const secondParagraph =
context.document.body.paragraphs.getFirst().getNext();
7. Within the insertTable() function, replace TODO2 with the following code. Note:
The first two parameters of the insertTable method specify the number of
rows and columns.
The third parameter specifies where to insert the table, in this case after the
paragraph.
The fourth parameter is a two-dimensional array that sets the values of the
table cells.
The table will have plain default styling, but the insertTable method returns
a Table object with many members, some of which are used to style the
table.
JavaScript
const tableData = [
["Name", "ID", "Birth City"],
["Bob", "434", "Chicago"],
["Sue", "719", "Havana"],
];
secondParagraph.insertTable(3, 3, Word.InsertLocation.after,
tableData);
To test your add-in in Word, run the following command in the root directory
of your project. This starts the local web server (if it isn't already running) and
opens Word with your add-in loaded.
command line
npm start
To test your add-in in Word on the web, run the following command in the
root directory of your project. When you run this command, the local web
server starts. Replace "{url}" with the URL of a Word document on your
OneDrive or a SharePoint library to which you have permissions.
7 Note
command line
fF1WZQj3VYhYQ?e=F4QM1R
npm run start:web -- --document
https://1drv.ms/x/s!jkcH7spkM4EGgcZUgqthk4IK3NOypVw?e=Z6G1qp
e=RSccmNP
2. If the add-in task pane isn't already open in Word, go to the Home tab and choose
the Show Taskpane button on the ribbon to open it.
3. In the task pane, choose the Insert Paragraph button at least three times to ensure
that there are a few paragraphs in the document.
4. Choose the Insert Image button and note that an image is inserted at the end of
the document.
5. Choose the Insert HTML button and note that two paragraphs are inserted at the
end of the document, and that the first one has the Verdana font.
6. Choose the Insert Table button and note that a table is inserted after the second
paragraph.
Create and update content controls
In this step of the tutorial, you'll learn how to create Rich Text content controls in the
document, and then how to insert and replace content in the controls.
7 Note
There are several types of content controls that can be added to a Word document
through the UI, but currently only Rich Text content controls are supported by
Word.js.
Before you start this step of the tutorial, we recommend that you create and
manipulate Rich Text content controls through the Word UI, so you can be familiar
with the controls and their properties. For details, see Create forms that users
complete or print in Word .
2. Locate the <button> element for the insert-table button, and add the following
markup after that line.
HTML
4. Within the Office.onReady function call, locate the line that assigns a click handler
to the insert-table button, and add the following code after that line.
JavaScript
document.getElementById("create-content-control").onclick = () =>
tryCatch(createContentControl);
JavaScript
async function createContentControl() {
await Word.run(async (context) => {
await context.sync();
});
}
This code is intended to wrap the phrase "Microsoft 365" in a content control.
It makes a simplifying assumption that the string is present and the user has
selected it.
JavaScript
HTML
4. Within the Office.onReady function call, locate the line that assigns a click handler
to the create-content-control button, and add the following code after that line.
JavaScript
document.getElementById("replace-content-in-control").onclick = () =>
tryCatch(replaceContentInControl);
JavaScript
await context.sync();
});
}
JavaScript
const serviceNameContentControl =
context.document.contentControls.getByTag("serviceName").getFirst();
serviceNameContentControl.insertText("Fabrikam Online Productivity
Suite", Word.InsertLocation.replace);
To test your add-in in Word, run the following command in the root directory
of your project. This starts the local web server (if it isn't already running) and
opens Word with your add-in loaded.
command line
npm start
To test your add-in in Word on the web, run the following command in the
root directory of your project. When you run this command, the local web
server starts. Replace "{url}" with the URL of a Word document on your
OneDrive or a SharePoint library to which you have permissions.
7 Note
command line
https://contoso.sharepoint.com/:t:/g/EZGxP7ksiE5DuxvY638G798BpuhwluxCM
fF1WZQj3VYhYQ?e=F4QM1R
npm run start:web -- --document
https://1drv.ms/x/s!jkcH7spkM4EGgcZUgqthk4IK3NOypVw?e=Z6G1qp
npm run start:web -- --document https://contoso-my.sharepoint-
df.com/:t:/p/user/EQda453DNTpFnl1bFPhOVR0BwlrzetbXvnaRYii2lDr_oQ?
e=RSccmNP
2. If the add-in task pane isn't already open in Word, go to the Home tab and choose
the Show Taskpane button on the ribbon to open it.
3. In the task pane, choose the Insert Paragraph button to ensure that there's a
paragraph with "Microsoft 365" at the top of the document.
4. In the document, select the text "Microsoft 365" and then choose the Create
Content Control button. Note that the phrase is wrapped in tags labelled "Service
Name".
5. Choose the Rename Service button and note that the text of the content control
changes to "Fabrikam Online Productivity Suite".
Next steps
In this tutorial, you've created a Word task pane add-in that inserts and replaces text,
images, and other content in a Word document. To learn more about building Word
add-ins, continue to the following article.
A Word add-in interacts with objects in Word by using the Office JavaScript API, which
includes two JavaScript object models:
Word JavaScript API: These are the application-specific APIs for Word. Introduced
with Office 2016, the Word JavaScript API provides strongly-typed objects that you
can use to access objects and metadata in a Word document.
Common APIs: Introduced with Office 2013, the Common API can be used to
access features such as UI, dialogs, and client settings that are common across
multiple types of Office applications.
This section of the documentation focuses on the Word JavaScript API, which you'll use
to develop the majority of functionality in add-ins that target Word on the web, or Word
2016 and later. For information about the Common API, see Common JavaScript API
object model.
For hands-on experience using the Word JavaScript API to access objects in Word,
complete the Word add-in tutorial.
For detailed information about the Word JavaScript API object model, see the Word
JavaScript API reference documentation.
See also
Word add-ins documentation
Word add-ins overview
Word JavaScript API reference
Office client application and platform availability for Office Add-ins
word package
Reference
Classes
Word.Application Represents the application object.
Word.CommentContentRange
Interfaces
Word.CommentDetail A structure for the ID and reply IDs of this comment.
Word.ContentControlOptions Specifies the options that define which content controls are
returned.
Word.Interfaces.BodyUpdate An interface for updating data on the Body object, for use in
Data body.set({ ... }) .
Word.Interfaces.BorderUpdate An interface for updating data on the Border object, for use in
Data border.set({ ... }) .
Word.Interfaces.CommentContentRangeLoadOptions
Word.Interfaces.Comment An interface for updating data on the CommentContentRange
ContentRangeUpdateData object, for use in commentContentRange.set({ ... }) .
Word.Interfaces.Comment An interface for updating data on the Comment object, for use
UpdateData in comment.set({ ... }) .
Word.Interfaces.Document The Document object is the top level object. A Document object
LoadOptions contains one or more sections, content controls, and the body
that contains the contents of the document.
Word.Interfaces.Document An interface for updating data on the Document object, for use
UpdateData in document.set({ ... }) .
Word.Interfaces.FieldUpdate An interface for updating data on the Field object, for use in
Data field.set({ ... }) .
Word.Interfaces.FontUpdate An interface for updating data on the Font object, for use in
Data font.set({ ... }) .
Word.Interfaces.ListItem An interface for updating data on the ListItem object, for use in
UpdateData listItem.set({ ... }) .
Word.Interfaces.ListLevel An interface for updating data on the ListLevel object, for use in
UpdateData listLevel.set({ ... }) .
Word.Interfaces.NoteItem An interface for updating data on the NoteItem object, for use in
UpdateData noteItem.set({ ... }) .
Word.Interfaces.Paragraph An interface for updating data on the Paragraph object, for use
UpdateData in paragraph.set({ ... }) .
Word.Interfaces.RangeUpdate An interface for updating data on the Range object, for use in
Data range.set({ ... }) .
Word.Interfaces.Section An interface for updating data on the Section object, for use in
UpdateData section.set({ ... }) .
Word.Interfaces.SettingUpdate An interface for updating data on the Setting object, for use in
Data setting.set({ ... }) .
Word.Interfaces.Shading An interface for updating data on the Shading object, for use in
UpdateData shading.set({ ... }) .
Word.Interfaces.TableBorder An interface for updating data on the TableBorder object, for use
UpdateData in tableBorder.set({ ... }) .
Word.Interfaces.TableCell An interface for updating data on the TableCell object, for use in
UpdateData tableCell.set({ ... }) .
Word.Interfaces.TableRow An interface for updating data on the TableRow object, for use in
UpdateData tableRow.set({ ... }) .
Word.Interfaces.TableStyle An interface for updating data on the TableStyle object, for use
UpdateData in tableStyle.set({ ... }) .
Word.Interfaces.TableUpdate An interface for updating data on the Table object, for use in
Data table.set({ ... }) .
Enums
Word.Alignment
Word.BodyType
Word.BorderLocation
Word.BorderType
Word.CellPaddingLocation
Word.ChangeTrackingVersion Specify the current version or the original version of the text.
Word.DocumentPropertyType
Word.ErrorCodes
Word.FieldKind Represents the kind of field. Indicates how the field works in
relation to updating.
Word.HeaderFooterType
Word.ImageFormat
Word.ListBuiltInNumberStyle
Word.ListBullet
Word.ListLevelType
Word.ListNumbering
Word.LocationRelation
Word.NoteItemType Note item type
Word.RangeLocation
Word.SelectionMode This enum sets where the cursor (insertion point) in the
document is after a selection.
Word.TrailingCharacter Represents the character inserted after the list item mark.
Word.VerticalAlignment
Functions
Word.run(objects, batch) Executes a batch script that performs actions on the Word object
model, using the RequestContext of previously created API
objects.
Word.run(object, batch) Executes a batch script that performs actions on the Word object
model, using the RequestContext of a previously created API
object. When the promise is resolved, any tracked objects that
were automatically allocated during execution will be released.
Word.run(batch) Executes a batch script that performs actions on the Word object
model, using a new RequestContext. When the promise is
resolved, any tracked objects that were automatically allocated
during execution will be released.
Function Details
Word.run(objects, batch)
Executes a batch script that performs actions on the Word object model, using the
RequestContext of previously created API objects.
TypeScript
Parameters
objects OfficeExtension.ClientObject[]
An array of previously created API objects. The array will be validated to make sure
that all of the objects share the same context. The batch will use this shared
RequestContext, which means that any changes applied to these objects will be
picked up by "context.sync()".
Returns
Promise<T>
Word.run(object, batch)
Executes a batch script that performs actions on the Word object model, using the
RequestContext of a previously created API object. When the promise is resolved,
any tracked objects that were automatically allocated during execution will be
released.
TypeScript
Parameters
object OfficeExtension.ClientObject
A previously created API object. The batch will use the same RequestContext as the
passed-in object, which means that any changes applied to the object will be picked
up by "context.sync()".
Returns
Promise<T>
Word.run(batch)
Executes a batch script that performs actions on the Word object model, using a new
RequestContext. When the promise is resolved, any tracked objects that were
automatically allocated during execution will be released.
TypeScript
Parameters
batch (context: Word.RequestContext) => Promise<T>
A function that takes in a RequestContext and returns a promise (typically, just the
result of "context.sync()"). The context parameter facilitates requests to the Word
application. Since the Office add-in and the Word application run in two different
processes, the RequestContext is required to get access to the Word object model
from the add-in.
Returns
Promise<T>
Word JavaScript object model in Office
Add-ins
Article • 03/09/2023
This article describes concepts that are fundamental to using the Word JavaScript API to
build add-ins.
) Important
See Using the application-specific API model to learn about the asynchronous
nature of the Word APIs and how they work with the document.
Word JavaScript API: The Word JavaScript API provides strongly-typed objects that
work with the document, ranges, tables, lists, formatting, and more.
Common APIs: The Common API give access to features such as UI, dialogs, and
client settings that are common across multiple Office applications.
While you'll likely use the Word JavaScript API to develop the majority of functionality in
add-ins that target Word, you'll also use objects in the Common API. For example:
The Document contains the Sections, and document-level entities such as settings
and custom XML parts.
A Section contains a Body.
A Body gives access to Paragraphs, ContentControls, and Range objects, among
others.
A Range represents a contiguous area of content, including text, white space,
Tables, and images. It also contains most of the text manipulation methods.
A List represents text in a numbered or bulleted list.
See also
Word JavaScript API overview
Build your first Word add-in
Word add-in tutorial
Word JavaScript API reference
Learn about the Microsoft 365 Developer Program
Create a dictionary task pane add-in
Article • 06/13/2023
This article shows you an example of a task pane add-in with an accompanying web
service that provides dictionary definitions or thesaurus synonyms for the user's current
selection in a Word document.
A dictionary Office Add-in is based on the standard task pane add-in with additional
features to support querying and displaying definitions from a dictionary XML web
service in additional places in the Office application's UI.
In a typical dictionary task pane add-in, a user selects a word or phrase in their
document, and the JavaScript logic behind the add-in passes this selection to the
dictionary provider's XML web service. The dictionary provider's webpage then updates
to show the definitions for the selection to the user.
The XML web service component returns up to three definitions in the format defined
by the example OfficeDefinitions XML schema, which are then displayed to the user in
other places in the hosting Office application's UI.
Figure 1 shows the selection and display experience for a Bing-branded dictionary add-
in that is running in Word.
It's up to you to determine if selecting the See More link in the dictionary add-in's
HTML UI displays more information within the task pane or opens a separate window to
the full webpage for the selected word or phrase.
Figure 2 shows the Define command in the context menu that enables users to quickly
launch installed dictionaries. Figures 3 through 5 show the places in the Office UI where
the dictionary XML services are used to provide definitions in Word.
An XML web service that looks up definitions from a dictionary service, and then
returns those values in an XML format that can be consumed and displayed by the
dictionary add-in.
A task pane add-in that submits the user's current selection to the dictionary web
service, displays definitions, and can optionally insert those values into the
document.
Prerequisites
Visual Studio 2019 or later with the Office/SharePoint development workload
installed.
7 Note
If you've previously installed Visual Studio, use the Visual Studio Installer to
ensure that the Office/SharePoint development workload is installed.
7 Note
If you don't already have Office, you can join the Microsoft 365 developer
program to get a free, 90-day renewable Microsoft 365 subscription to use
during development.
2. Using the search box, enter add-in. Choose Word Web Add-in, then select Next.
4. Visual Studio creates a solution and its two projects appear in Solution Explorer.
The Home.html file opens in Visual Studio.
To learn more about the projects in a Word add-in solution, see the quick start.
XML
XML
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Xml;
using System.Text;
using System.IO;
using System.Net;
using System.Web.Script.Services;
/// <summary>
/// Summary description for _Default.
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
// To allow this web service to be called from script, using ASP.NET AJAX,
include the following line.
[ScriptService]
public class WebService : System.Web.Services.WebService {
public WebService () {
// You can replace this method entirely with your own method that gets
definitions
// from your data source and then formats it into the example
OfficeDefinitions XML format.
// If you need a reference for constructing the returned XML, you can
use this example as a basis.
[WebMethod]
public XmlDocument Define(string word)
{
writer.WriteStartElement("Result",
"http://schemas.microsoft.com/contoso/OfficeDefinitions");
writer.WriteStartElement("Definitions");
writer.WriteElementString("Definition", "Definition
1 of " + word);
writer.WriteElementString("Definition", "Definition
2 of " + word);
writer.WriteElementString("Definition", "Definition
3 of " + word);
writer.WriteEndDocument();
}
writer.Close();
XmlDocument doc = new XmlDocument();
doc.LoadXml(sb.ToString());
return doc;
}
}
1. In the Solution Explorer, select the DictionaryWebService.asmx file then open its
context menu and choose View Markup.
XML
XML
<webServices>
<protocols>
<add name="HttpGet" />
<add name="HttpPost" />
</protocols>
</webServices>
XML
The <Dictionary> element and its child elements specific to creating a dictionary add-
in's manifest file are described in the following sections. For information about the other
elements in the manifest file, see Office Add-ins XML manifest.
Dictionary element
Specifies settings for dictionary add-ins.
Parent element
<OfficeApp>
Child elements
Remarks
The <Dictionary> element and its child elements are added to the manifest of a task
pane add-in when you create a dictionary add-in.
TargetDialects element
Specifies the regional languages that this dictionary supports. Required for dictionary
add-ins.
Parent element
<Dictionary>
Child element
<TargetDialect>
Remarks
The <TargetDialects> element and its child elements specify the set of regional
languages your dictionary contains. For example, if your dictionary applies to both
Spanish (Mexico) and Spanish (Peru), but not Spanish (Spain), you can specify that in this
element. Do not specify more than one language (e.g., Spanish and English) in this
manifest. Publish separate languages as separate dictionaries.
Example
XML
<TargetDialects>
<TargetDialect>EN-AU</TargetDialect>
<TargetDialect>EN-BZ</TargetDialect>
<TargetDialect>EN-CA</TargetDialect>
<TargetDialect>EN-029</TargetDialect>
<TargetDialect>EN-HK</TargetDialect>
<TargetDialect>EN-IN</TargetDialect>
<TargetDialect>EN-ID</TargetDialect>
<TargetDialect>EN-IE</TargetDialect>
<TargetDialect>EN-JM</TargetDialect>
<TargetDialect>EN-MY</TargetDialect>
<TargetDialect>EN-NZ</TargetDialect>
<TargetDialect>EN-PH</TargetDialect>
<TargetDialect>EN-SG</TargetDialect>
<TargetDialect>EN-ZA</TargetDialect>
<TargetDialect>EN-TT</TargetDialect>
<TargetDialect>EN-GB</TargetDialect>
<TargetDialect>EN-US</TargetDialect>
<TargetDialect>EN-ZW</TargetDialect>
</TargetDialects>
TargetDialect element
Specifies a regional language that this dictionary supports. Required for dictionary add-
ins.
Parent element
<TargetDialects>
Remarks
Specify the value for a regional language in the RFC1766 language tag format, such as
EN-US.
Example
XML
<TargetDialect>EN-US</TargetDialect>
QueryUri element
Specifies the endpoint for the dictionary query service. Required for dictionary add-ins.
Parent element
<Dictionary>
Remarks
This is the URI of the XML web service for the dictionary provider. The properly escaped
query will be appended to this URI.
Example
XML
<QueryUri DefaultValue="http://msranlc-lingo1/proof.aspx?q="/>
CitationText element
Specifies the text to use in citations. Required for dictionary add-ins.
Parent element
<Dictionary>
Remarks
This element specifies the beginning of the citation text that will be displayed on a line
below the content that is returned from the web service (for example, "Results by: " or
"Powered by: ").
For this element, you can specify values for additional locales by using the <Override>
element. For example, if a user is running the Spanish SKU of Office, but using an
English dictionary, this allows the citation line to read "Resultados por: Bing" rather than
"Results by: Bing". For more information about how to specify values for additional
locales, see Localization.
Example
XML
DictionaryName element
Specifies the name of this dictionary. Required for dictionary add-ins.
Parent element
<Dictionary>
Remarks
This element specifies the link text in the citation text. Citation text is displayed on a line
below the content that is returned from the web service.
For this element, you can specify values for additional locales.
Example
XML
DictionaryHomePage element
Specifies the URL of the home page for the dictionary. Required for dictionary add-ins.
Parent element
<Dictionary>
Remarks
This element specifies the link URL in the citation text. Citation text is displayed on a line
below the content that is returned from the web service.
For this element, you can specify values for additional locales.
Example
XML
5. Add the following code after the <Permissions> node, replacing "contoso"
references with your own company name, then save your changes.
XML
<Dictionary>
<!--TargetDialects is the set of regional languages your dictionary
contains. For example, if your
dictionary applies to Spanish (Mexico) and Spanish (Peru), but
not Spanish (Spain), you can
specify that here. Do not put more than one language (for
example, Spanish and English) here.
Publish separate languages as separate dictionaries. -->
<TargetDialects>
<TargetDialect>EN-AU</TargetDialect>
<TargetDialect>EN-BZ</TargetDialect>
<TargetDialect>EN-CA</TargetDialect>
<TargetDialect>EN-029</TargetDialect>
<TargetDialect>EN-HK</TargetDialect>
<TargetDialect>EN-IN</TargetDialect>
<TargetDialect>EN-ID</TargetDialect>
<TargetDialect>EN-IE</TargetDialect>
<TargetDialect>EN-JM</TargetDialect>
<TargetDialect>EN-MY</TargetDialect>
<TargetDialect>EN-NZ</TargetDialect>
<TargetDialect>EN-PH</TargetDialect>
<TargetDialect>EN-SG</TargetDialect>
<TargetDialect>EN-ZA</TargetDialect>
<TargetDialect>EN-TT</TargetDialect>
<TargetDialect>EN-GB</TargetDialect>
<TargetDialect>EN-US</TargetDialect>
<TargetDialect>EN-ZW</TargetDialect>
</TargetDialects>
<!--QueryUri is the address of this dictionary's XML web service
(which is used to put definitions in
additional contexts, such as the spelling checker.)-->
<QueryUri DefaultValue="~remoteAppUrl/DictionaryWebService.asmx"/>
<!--Citation Text, Dictionary Name, and Dictionary Home Page will be
combined to form the citation
line (for example, this would produce "Examples by: Contoso",
where "Contoso" is a hyperlink to
http://www.contoso.com).-->
<CitationText DefaultValue="Examples by: " />
<DictionaryName DefaultValue="Contoso" />
<DictionaryHomePage DefaultValue="http://www.contoso.com" />
</Dictionary>
In the add-in's web application project in Visual Studio, you can replace the contents of
the ./Home.html file with the following sample HTML.
HTML
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<!--The title will not be shown but is supplied to ensure valid HTML.-->
<title>Example Dictionary</title>
<body>
<div id="mainContainer">
<div>INSTRUCTIONS</div>
<ol>
<li>Ensure there's text in the document.</li>
<li>Select text.</li>
</ol>
<div id="header">
<span id="headword"></span>
</div>
<div>DEFINITIONS</div>
<ol id="definitions">
</ol>
<div id="SeeMore">
<a id="SeeMoreLink" target="_blank">See More...</a>
</div>
<div id="message"></div>
</div>
</body>
</html>
In the add-in's web application project in Visual Studio, you can replace the contents of
the ./Home.css file with the following sample CSS.
CSS
#mainContainer
{
font-family: Segoe UI;
font-size: 11pt;
}
#headword
{
font-family: Segoe UI Semibold;
color: #262626;
}
#definitions
{
font-size: 8.5pt;
}
a
{
font-size: 8pt;
color: #336699;
text-decoration: none;
}
a:visited
{
color: #993366;
}
a:hover, a:active
{
text-decoration: underline;
}
The primary members of the Office JavaScript API (Office.js) that are called from this
implementation are shown in the following list.
The initialize event of the Office object, which is raised when the add-in context is
initialized, and provides access to a Document object instance that represents the
document the add-in is interacting with.
The addHandlerAsync method of the Document object, which is called in the
initialize function to add an event handler for the SelectionChanged event of
the document to listen for user selection changes.
The getSelectedDataAsync method of the Document object, which is called in the
tryUpdatingSelectedWord() function when the SelectionChanged event handler is
raised to get the word or phrase the user selected, coerce it to plain text, and then
execute the selectedTextCallback asynchronous callback function.
When the selectTextCallback asynchronous callback function that's passed as the
callback argument of the getSelectedDataAsync method executes, it gets the value
of the selected text when the callback returns. It gets that value from the callback's
selectedText argument (which is of type AsyncResult) by using the value property of
the returned AsyncResult object.
The rest of the code in the selectedTextCallback function queries the XML web
service for definitions.
The remaining code in the .js file displays the list of definitions in the add-in's
HTML UI.
In the add-in's web application project in Visual Studio, you can replace the contents of
the ./Home.js file with the following sample JavaScript.
JavaScript
// Async callback that executes when the add-in gets the user's selection.
Determines whether anything should
// be done. If so, it makes requests that will be passed to various
functions.
function selectedTextCallback(selectedText) {
selectedText = $.trim(selectedText.value);
// Be sure user has selected text. The SelectionChanged event is raised
every time the user moves
// the cursor, even if no selection.
if (selectedText != "") {
// Check whether the user selected the same word the pane is
currently displaying to
// avoid unnecessary web calls.
if (selectedText != lastLookup) {
// Update the lastLookup variable.
lastLookup = selectedText;
// Set the "headword" span to the word you looked up.
$("#headword").text("Selected text: " + selectedText);
// AJAX request to get definitions for the selected word; pass
that to refreshDefinitions.
$.ajax(xmlServiceUrl,
{
data: { word: selectedText },
dataType: 'xml',
success: refreshDefinitions,
error: errorHandler
});
}
}
// This function is called when the add-in gets back the definitions target
word.
// It removes the old definitions and replaces them with the definitions for
the current word.
// It also sets the "See More" link.
function refreshDefinitions(data, textStatus, jqXHR) {
$(".definition").remove();
// Make a new list item for each returned definition that was returned,
set the CSS class,
// and append it to the definitions div.
$(data).find("Definition").each(function () {
$(document.createElement("li"))
.text($(this).text())
.addClass("definition")
.appendTo($("#definitions"));
});
2. In Word, if the add-in task pane isn't already open, choose the Home tab, and then
choose the Show Taskpane button to open the add-in task pane. (If you're using
the volume-licensed perpetual version of Office, instead of the Microsoft 365
version or a retail perpetual version, then custom buttons aren't supported.
Instead, the task pane will open immediately.)
3. In Word, add text to the document then select any or all of that text.
Get the whole document from an add-in
for Word or PowerPoint
Article • 07/14/2023
You can create an Office Add-in to send or publish a Word document or PowerPoint
presentation to a remote location. This article demonstrates how to build a simple task
pane add-in for PowerPoint or Word that gets all of the presentation or document as a
data object and sends that data to a web server via an HTTP request.
On a shared network folder or on a web server, you need the following files.
An HTML file (GetDoc_App.html) that contains the user interface plus links to
the JavaScript files (including Office.js and application-specific .js files) and
Cascading Style Sheet (CSS) files.
A CSS file (Program.css) to contain the styles and formatting for the add-in.
Alternatively, you can create an add-in for your Office application using one of the
following options. You won't have to create new files as the equivalent of each required
file will be available for you to update. For example, the Yeoman generator options
include ./src/taskpane/taskpane.html, ./src/taskpane/taskpane.js,
./src/taskpane/taskpane.css, and ./manifest.xml.
PowerPoint
Visual Studio
Yeoman generator for Office Add-ins
Word
Visual Studio
Yeoman generator for Office Add-ins
XML
Use the following procedure to create a simple user interface for the add-in that
includes a heading and a single button.
1. In a new file in the text editor, add the HTML for your selected Office application.
PowerPoint
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge"/>
<title>Publish presentation</title>
<link rel="stylesheet" type="text/css" href="Program.css"
/>
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-
1.9.0.min.js" type="text/javascript"></script>
<script
src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js"
type="text/javascript"></script>
<script src="GetDoc_App.js"></script>
</head>
<body>
<form>
<h1>Publish presentation</h1>
<br />
<div><input id='submit' type="button" value="Submit" />
</div>
<br />
<div><h2>Status</h2>
<div id="status"></div>
</div>
</form>
</body>
</html>
Be sure that the head tags of the add-in contains a script tag with a valid link
to the Office.js file.
3. We'll use some CSS to give the add-in a simple yet modern and professional
appearance. Use the following CSS to define the style of the add-in.
css
body
{
font-family: "Segoe UI Light","Segoe UI",Tahoma,sans-serif;
}
h1,h2
{
text-decoration-color:#4ec724;
}
input [type="submit"], input[type="button"]
{
height:24px;
padding-left:1em;
padding-right:1em;
background-color:white;
border:1px solid grey;
border-color: #dedfe0 #b9b9b9 #b9b9b9 #dedfe0;
cursor:pointer;
}
4. Save the file as Program.css using UTF-8 encoding to the network location or to
the web server where the GetDoc_App.html file is located.
The following code example shows the event handler for the Office.initialize event
along with a helper function, updateStatus , for writing to the status div.
JavaScript
// The initialize or onReady function is required for all add-ins.
Office.initialize = function (reason) {
// Checks for the DOM to load using the jQuery ready method.
$(document).ready(function () {
// Update status.
updateStatus("Ready to send file.");
});
}
When you choose the Submit button in the UI, the add-in calls the sendFile function,
which contains a call to the Document.getFileAsync method. The getFileAsync method
uses the asynchronous pattern, similar to other methods in the Office JavaScript API. It
has one required parameter, fileType, and two optional parameters, options and callback.
The fileType parameter expects one of three constants from the FileType enumeration:
Office.FileType.Compressed ("compressed"), Office.FileType.PDF ("pdf"), or
Office.FileType.Text ("text"). The current file type support for each platform is listed
under the Document.getFileType remarks. When you pass in Compressed for the
fileType parameter, the getFileAsync method returns the current document as a
PowerPoint presentation file (*.pptx) or Word document file (*.docx) by creating a
temporary copy of the file on the local computer.
The getFileAsync method returns a reference to the file as a File object. The File
object exposes the following four members.
size property
sliceCount property
getSliceAsync method
closeAsync method
The size property returns the number of bytes in the file. The sliceCount returns the
number of Slice objects (discussed later in this article) in the file.
Use the following code to get the current PowerPoint or Word document as a File
object using the Document.getFileAsync method and then make a call to the locally
defined getSlice function. Note that the File object, a counter variable, and the total
number of slices in the file are passed along in the call to getSlice in an anonymous
object.
JavaScript
The local function getSlice makes a call to the File.getSliceAsync method to retrieve
a slice from the File object. The getSliceAsync method returns a Slice object from
the collection of slices. It has two required parameters, sliceIndex and callback. The
sliceIndex parameter takes an integer as an indexer into the collection of slices. Like
other methods in the Office JavaScript API, the getSliceAsync method also takes a
callback function as a parameter to handle the results from the method call.
The Slice object gives you access to the data contained in the file. Unless otherwise
specified in the options parameter of the getFileAsync method, the Slice object is 4
MB in size. The Slice object exposes three properties: size, data, and index. The size
property gets the size, in bytes, of the slice. The index property gets an integer that
represents the slice's position in the collection of slices.
JavaScript
// Get a slice from the file and then call sendSlice.
function getSlice(state) {
state.file.getSliceAsync(state.counter, function (result) {
if (result.status == Office.AsyncResultStatus.Succeeded) {
updateStatus("Sending piece " + (state.counter + 1) + " of " +
state.sliceCount);
sendSlice(result.value, state);
} else {
updateStatus(result.status);
}
});
}
The Slice.data property returns the raw data of the file as a byte array. If the data is in
text format (that is, XML or plain text), the slice contains the raw text. If you pass in
Office.FileType.Compressed for the fileType parameter of Document.getFileAsync , the
slice contains the binary data of the file as a byte array. In the case of a PowerPoint or
Word file, the slices contain byte arrays.
You must implement your own function (or use an available library) to convert byte array
data to a Base64-encoded string. For information about Base64 encoding with
JavaScript, see Base64 encoding and decoding .
Once you've converted the data to Base64, you can then transmit it to a web server in
several ways, including as the body of an HTTP POST request.
7 Note
This code sends a PowerPoint or Word file to the web server in multiple slices. The
web server or service must append each individual slice into a single file, and then
save it as a .pptx or .docx file before you can perform any manipulations on it.
JavaScript
As the name implies, the File.closeAsync method closes the connection to the
document and frees up resources. Although the Office Add-ins sandbox garbage
collects out-of-scope references to files, it's still a best practice to explicitly close files
once your code is done with them. The closeAsync method has a single parameter,
callback, that specifies the function to call on the completion of the call.
JavaScript
function closeFile(state) {
// Close the file when you're done with it.
state.file.closeAsync(function (result) {
JavaScript
/*
* Copyright (c) Microsoft Corporation. All rights reserved. Licensed under
the MIT license.
* See LICENSE in the project root for license information.
*/
// Checks for the DOM to load using the jQuery ready method.
$(document).ready(function () {
// Update status.
updateStatus("Ready to send file.");
});
}
function closeFile(state) {
// Close the file when you're done with it.
state.file.closeAsync(function (result) {
The Document object exposes methods that let you read and write to the user's current
selection in a document or spreadsheet. To do that, the Document object provides the
getSelectedDataAsync and setSelectedDataAsync methods. This topic also describes
how to read, write, and create event handlers to detect changes to the user's selection.
The getSelectedDataAsync method only works against the user's current selection. If you
need to persist the selection in the document, so that the same selection is available to
read and write across sessions of running your add-in, you must add a binding using the
Bindings.addFromSelectionAsync method (or create a binding with one of the other
"addFrom" methods of the Bindings object). For information about creating a binding to
a region of a document, and then reading and writing to a binding, see Bind to regions
in a document or spreadsheet.
JavaScript
Office.context.document.getSelectedDataAsync(Office.CoercionType.Text,
function (asyncResult) {
if (asyncResult.status == Office.AsyncResultStatus.Failed) {
write('Action failed. Error: ' + asyncResult.error.message);
}
else {
write('Selected data: ' + asyncResult.value);
}
});
"text" ). This means that the value property of the AsyncResult object that is available
from the asyncResult parameter in the callback function will return a string that contains
the selected text in the document. Specifying different coercion types will result in
different values. Office.CoercionType is an enumeration of available coercion type
values. Office.CoercionType.Text evaluates to the string "text".
Tip
When should you use the matrix versus table coercionType for data access? If
you need your selected tabular data to grow dynamically when rows and columns
are added, and you must work with table headers, you should use the table data
type (by specifying the coercionType parameter of the getSelectedDataAsync
method as "table" or Office.CoercionType.Table ). Adding rows and columns
within the data structure is supported in both table and matrix data, but appending
rows and columns is supported only for table data. If you aren't planning on adding
rows and columns, and your data doesn't require header functionality, then you
should use the matrix data type (by specifying the coercionType parameter of
getSelectedDataAsync method as "matrix" or Office.CoercionType.Matrix ), which
The anonymous function that is passed into the method as the second parameter,
callback, is executed when the getSelectedDataAsync operation is completed. The
function is called with a single parameter, asyncResult, which contains the result and the
status of the call. If the call fails, the error property of the AsyncResult object provides
access to the Error object. You can check the value of the Error.name and Error.message
properties to determine why the set operation failed. Otherwise, the selected text in the
document is displayed.
The AsyncResult.status property is used in the if statement to test whether the call
succeeded. Office.AsyncResultStatus is an enumeration of available AsyncResult.status
property values. Office.AsyncResultStatus.Failed evaluates to the string "failed" (and,
again, can also be specified as that literal string).
JavaScript
Passing in different object types for the data parameter will have different results. The
result depends on what is currently selected in the document, which Office client
application is hosting your add-in, and whether the data passed in can be coerced to
the current selection.
The anonymous function passed into the setSelectedDataAsync method as the callback
parameter is executed when the asynchronous call is completed. When you write data to
the selection by using the setSelectedDataAsync method, the asyncResult parameter of
the callback provides access only to the status of the call, and to the Error object if the
call fails.
JavaScript
Office.context.document.addHandlerAsync("documentSelectionChanged",
myHandler, function(result){}
);
The first parameter, eventType, specifies the name of the event to subscribe to. Passing
the string "documentSelectionChanged" for this parameter is equivalent to passing the
Office.EventType.DocumentSelectionChanged event type of the Office.EventType
enumeration.
The myHandler() function that is passed into the method as the second parameter,
handler, is an event handler that is executed when the selection is changed on the
document. The function is called with a single parameter, eventArgs, which will contain a
reference to a DocumentSelectionChangedEventArgs object when the asynchronous
operation completes. You can use the DocumentSelectionChangedEventArgs.document
property to access the document that raised the event.
7 Note
You can add multiple event handlers for a given event by calling the
addHandlerAsync method again and passing in an additional event handler function
for the handler parameter. This will work correctly as long as the name of each
event handler function is unique.
JavaScript
Office.context.document.removeHandlerAsync("documentSelectionChanged",
{handler:myHandler}, function(result){});
The myHandler function name that is passed as the second parameter, handler, specifies
the event handler that will be removed from the SelectionChanged event.
) Important
Add-ins frequently need to act based on the text of a document. A search method is
exposed by every content control (this includes Body, Paragraph, Range, Table,
TableRow, and the base ContentControl object). This method takes in a string (or
wildcard expression) representing the text you are searching for and a SearchOptions
object. It returns a collection of ranges which match the search text.
) Important
The Word client may limit the available search options. For more details about
current support, see Find and replace text .
Search options
The search options are a collection of boolean values defining how the search
parameter should be treated.
Property Description
ignorePunct Gets or sets a value indicating whether to ignore all punctuation characters
between words. Corresponds to the "Ignore punctuation characters"
checkbox in the Find and Replace dialog box.
ignoreSpace Gets or sets a value indicating whether to ignore all whitespace between
words. Corresponds to the "Ignore white-space characters" checkbox in the
Find and Replace dialog box.
matchPrefix Gets or sets a value indicating whether to match words that begin with the
search string. Corresponds to the "Match prefix" checkbox in the Find and
Replace dialog box.
matchSuffix Gets or sets a value indicating whether to match words that end with the
search string. Corresponds to the "Match suffix" checkbox in the Find and
Replace dialog box.
Property Description
matchWholeWord Gets or sets a value indicating whether to find operation only entire words,
not text that is part of a larger word. Corresponds to the "Find whole words
only" checkbox in the Find and Replace dialog box.
matchWildcards Gets or sets a value indicating whether the search will be performed using
special search operators. Corresponds to the "Use wildcards" checkbox in the
Find and Replace dialog box.
To find Notation
Paragraph mark ^p
Tab mark ^t
Any character ^?
Any digit ^#
Any letter ^$
Caret character ^^
Section character ^%
Paragraph character ^v
Column break ^n
Em dash ^+
En dash ^=
Endnote mark ^e
Field ^d
Footnote mark ^f
Graphic ^g
Nonbreaking hyphen ^~
To find Notation
Nonbreaking space ^s
Optional hyphen ^-
Section break ^b
White Space ^w
Wildcard guidance
The following table provides guidance around the Word JavaScript API's search
wildcards.
The end of a word > (in)> finds in and within, but not
interesting.
Any single character in this range [-] [r-t]ight finds right, sight, and tight.
Ranges must be in ascending order.
Any single character except the characters in [!x-z] t[!a-m]ck finds tock and tuck, but not
the range inside the brackets tack or tick.
Exactly n occurrences of the previous {n} fe{2}d finds feed but not fed.
character or expression
At least n occurrences of the previous {n,} fe{1,}d finds fed and feed.
character or expression
From n to m occurrences of the previous {n,m} 10{1,3} finds 10, 100, and 1000.
character or expression
One or more occurrences of the previous @ lo@t finds lot and loot.
character or expression
Examples
The following examples demonstrate common scenarios.
// Queue a set of commands to change the font for each found item.
for (let i = 0; i < searchResults.items.length; i++) {
searchResults.items[i].font.color = 'purple';
searchResults.items[i].font.highlightColor = '#FFFF00'; //Yellow
searchResults.items[i].font.bold = true;
}
// Queue a set of commands to change the font for each found item.
for (let i = 0; i < searchResults.items.length; i++) {
searchResults.items[i].font.color = 'purple';
searchResults.items[i].font.highlightColor = '#FFFF00'; //Yellow
searchResults.items[i].font.bold = true;
}
// Queue a set of commands to change the font for each found item.
for (let i = 0; i < searchResults.items.length; i++) {
searchResults.items[i].font.color = 'orange';
searchResults.items[i].font.highlightColor = 'black';
searchResults.items[i].font.bold = true;
}
// Synchronize the document state.
await context.sync();
});
// Queue a set of commands to change the font for each found item.
for (let i = 0; i < searchResults.items.length; i++) {
searchResults.items[i].font.color = 'purple';
searchResults.items[i].font.highlightColor = 'pink';
searchResults.items[i].font.bold = true;
}
// Queue a set of commands to change the font for each found item.
for (let i = 0; i < searchResults.items.length; i++) {
searchResults.items[i].font.color = 'purple';
searchResults.items[i].font.highlightColor = 'pink';
searchResults.items[i].font.bold = true;
}
See also
More information can be found in the following:
Provided by: Stephanie Krieger, Microsoft Corporation | Juan Balmori Labra, Microsoft
Corporation
If you're building Office Add-ins to run in Word, you might already know that the Office
JavaScript API (Office.js) offers several formats for reading and writing document
content. These are called coercion types, and they include plain text, tables, HTML, and
Office Open XML.
1. Word JavaScript APIs. Start with the APIs available through the WordApi
requirement sets to see if they provide what you need. For an example, see the
Insert formatted text code snippet. You can try this and other snippets in the
Script Lab add-in on Word! To learn more about Script Lab, see Explore Office
JavaScript API using Script Lab.
2. HTML coercion. If APIs aren't yet available, you can use HTML for inserting some
types of rich content, such as pictures. Depending on your scenario, there can be
drawbacks to HTML coercion, such as limitations in the formatting and positioning
options available to your content.
3. Office Open XML. Because Office Open XML is the language in which Word
documents (such as .docx and .dotx) are written, you can insert virtually any type of
content that a user can add to a Word document, with virtually any type of
formatting the user can apply. Determining the Office Open XML markup you need
to get it done is easier than you might think.
7 Note
Office Open XML is also the language behind PowerPoint and Excel (and, as of
Office 2013, Visio) documents. However, currently, you can coerce content as Office
Open XML only in Office Add-ins created for Word. For more information about
Office Open XML, including the complete language reference documentation, see
the See also section.
Throughout this article, the terms content types and rich content refer to the types of
rich content you can insert into a Word document.
Use direct formatting to specify exactly what the text will look like regardless of existing
formatting in the user's document.
Use a style to automatically coordinate the look of text you insert with the user's
document.
Adding high quality formatting and effects to your images requires much less markup
than you might expect.
Use content controls with your add-in to add content at a specified (bound) location
rather than at the selection.
Text effects are available in Word for text inside a text box (as shown here) or for regular
body text.
Figure 7. A shape
Insert built-in or custom drawing shapes, with or without text and formatting effects.
Include text formatting, borders, shading, cell sizing, or any table formatting you need.
Use built-in or custom table styles just as easily as using a paragraph style for text.
Office offers a wide array of SmartArt diagram layouts (and you can use Office Open
XML to create your own).
Tip
If you save the file to an XML format from Word, note that there are two options under
the Save as Type list in the Save As dialog box for .xml format files. Be sure to choose
Word XML Document, not the Word 2003 option.
So is that all there is to it? Well, not quite. Yes, for many scenarios, you could use the full,
flattened Office Open XML result you see with either of the preceding methods and it
would work. The good news is that you probably don't need most of that markup.
If you're one of the many add-in developers seeing Office Open XML markup for the
first time, trying to make sense of the massive amount of markup you get for the
simplest piece of content might seem overwhelming, but it doesn't have to be.
In this topic, you'll use some common scenarios we've been hearing from the Office
Add-ins developer community to show you techniques for simplifying Office Open XML
for use in your add-in. We'll explore the markup for some types of content shown earlier
along with the information you need for minimizing the Office Open XML payload. We'll
also look at the code you need for inserting rich content into a document at the active
selection and how to use Office Open XML with the bindings object to add or replace
content at specified locations.
Even a simple Word document package includes parts for document properties, styles,
theme (formatting settings), web settings, fonts, and then some, in addition to parts for
the actual content.
For example, say that you want to insert just a paragraph of text with direct formatting,
as shown earlier in Figure 1. When you grab the Office Open XML for the formatted text
using getSelectedDataAsync , you see a large amount of markup. That markup includes a
package element that represents an entire document, which contains several parts
(commonly referred to as document parts or, in the Office Open XML, as package parts),
as you see listed in Figure 13. Each part represents a separate file within the package.
You can edit Office Open XML markup in a text editor like Notepad. If you open it in
Visual Studio, use Edit > Advanced > Format Document (Ctrl+K, Ctrl+D) to format the
package for easier editing. Then you can collapse or expand document parts or sections
of them, as shown in Figure 12, to more easily review and edit the content of the Office
Open XML package. Each document part begins with a pkg:part tag.
Figure 12. Collapse and expand package parts for easier editing in Visual Studio
Figure 13. The parts included in a basic Word Office Open XML document package
With all that markup, you might be surprised to discover that the only elements you
actually need to insert the formatted text example are pieces of the .rels part and the
document.xml part.
Tip
The two lines of markup above the package tag (the XML declarations for version
and Office program ID) are assumed when you use the Office Open XML coercion
type, so you don't need to include them. Keep them if you want to open your
edited markup as a Word document to test it.
Several of the other types of content shown at the start of this topic require additional
parts as well (beyond those shown in Figure 13), and you'll address those later in this
topic. Meanwhile, since you'll see most of the parts shown in Figure 13 in the markup for
any Word document package, here's a quick summary of what each of these parts is for
and when you need it:
Inside the package tag, the first part is the .rels file, which defines relationships
between the top-level parts of the package (these are typically the document
properties, thumbnail (if any), and main document body). Some of the content in
this part is always required in your markup because you need to define the
relationship of the main document part (where your content resides) to the
document package.
The document.xml.rels part defines relationships for additional parts required by
the document.xml (main body) part, if any.
) Important
The .rels files in your package (such as the top-level .rels, document.xml.rels,
and others you may see for specific types of content) are an extremely
important tool that you can use as a guide for helping you quickly edit down
your Office Open XML package. To learn more about how to do this, see
Create your own markup: best practices later in this topic.
The document.xml part is the content in the main body of the document. You need
elements of this part, of course, since that's where your content appears. But, you
don't need everything you see in this part. We'll look at that in more detail later.
Many parts are automatically ignored by the Set methods when inserting content
into a document using Office Open XML coercion, so you might as well remove
them. These include the theme1.xml file (the document's formatting theme), the
document properties parts (core, add-in, and thumbnail), and setting files
(including settings, webSettings, and fontTable).
In the Figure 1 example, text formatting is directly applied (that is, each font and
paragraph formatting setting applied individually). But, if you use a style (such as if
you want your text to automatically take on the formatting of the Heading 1 style
in the destination document) as shown earlier in Figure 2, then you would need
part of the styles.xml part as well as a relationship definition for it. For more
information, see the topic section Add objects that use additional Office Open XML
parts.
<pkg:package
xmlns:pkg="http://schemas.microsoft.com/office/2006/xmlPackage">
<pkg:part pkg:name="/_rels/.rels"
pkg:contentType="application/vnd.openxmlformats-package.relationships+xml"
pkg:padding="512">
<pkg:xmlData>
<Relationships
xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId1"
Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/of
ficeDocument" Target="word/document.xml"/>
</Relationships>
</pkg:xmlData>
</pkg:part>
<pkg:part pkg:name="/word/document.xml"
pkg:contentType="application/vnd.openxmlformats-
officedocument.wordprocessingml.document.main+xml">
<pkg:xmlData>
<w:document
xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" >
<w:body>
<w:p>
<w:pPr>
<w:spacing w:before="360" w:after="0" w:line="480"
w:lineRule="auto"/>
<w:rPr>
<w:color w:val="70AD47" w:themeColor="accent6"/>
<w:sz w:val="28"/>
</w:rPr>
</w:pPr>
<w:r>
<w:rPr>
<w:color w:val="70AD47" w:themeColor="accent6"/>
<w:sz w:val="28"/>
</w:rPr>
<w:t>This text has formatting directly applied to achieve its
font size, color, line spacing, and paragraph spacing.</w:t>
</w:r>
</w:p>
</w:body>
</w:document>
</pkg:xmlData>
</pkg:part>
</pkg:package>
7 Note
If you add the markup shown here to an XML file along with the XML declaration
tags for version and mso-application at the top of the file (shown in Figure 13), you
can open it in Word as a Word document. Or, without those tags, you can still open
it using File > Open in Word. You'll see Compatibility Mode on the title bar in
Word, because you removed the settings that tell Word this is a Word document.
Since you're adding this markup to an existing Word document, that won't affect
your content at all.
In the following function, notice that all but the last line are used to get your saved
markup for use in the setSelectedDataAsync method call at the end of the function.
setSelectedDataASync requires only that you specify the content to be inserted and the
coercion type.
Replace yourXMLfilename with the name and path of the XML file as you've saved it in
your solution. If you aren't sure where to include XML files in your solution or how to
reference them in your code, see the Load and write Open XML in your Word add-in
code sample for examples of that and a working example of the markup and JavaScript
shown here.
JavaScript
function writeContent() {
const myOOXMLRequest = new XMLHttpRequest();
let myXML;
myOOXMLRequest.open('GET', 'yourXMLfilename', false);
myOOXMLRequest.send();
if (myOOXMLRequest.status === 200) {
myXML = myOOXMLRequest.responseText;
}
Office.context.document.setSelectedDataAsync(myXML, { coercionType:
'ooxml' });
}
) Important
Use the .rels parts as a map to quickly gauge what's included in the package and
determine what parts you can delete completely (that is, any parts not related to or
referenced by your content). Remember that every document part must have a
relationship defined in the package and those relationships appear in the .rels files.
So you should see all of them listed in either .rels, document.xml.rels, or a content-
specific .rels file.
The following markup shows the required .rels part before editing. Since we're deleting
the add-in and core document property parts, and the thumbnail part, you need to
delete those relationships from .rels as well. Notice that this will leave only the
relationship (with the relationship ID "rID1" in the following example) for document.xml.
XML
<pkg:part pkg:name="/_rels/.rels"
pkg:contentType="application/vnd.openxmlformats-package.relationships+xml"
pkg:padding="512">
<pkg:xmlData>
<Relationships
xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId3"
Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/
core-properties" Target="docProps/core.xml"/>
<Relationship Id="rId2"
Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/
thumbnail" Target="docProps/thumbnail.emf"/>
<Relationship Id="rId1"
Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/of
ficeDocument" Target="word/document.xml"/>
<Relationship Id="rId4"
Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/ex
tended-properties" Target="docProps/app.xml"/>
</Relationships>
</pkg:xmlData>
</pkg:part>
Remove the relationships (that is, the Relationship tag) for any parts that you
completely remove from the package. Including a part without a corresponding
relationship, or excluding a part and leaving its relationship in the package, will result in
an error.
The following markup shows the document.xml part, which includes our sample
formatted text content before editing.
XML
<pkg:part pkg:name="/word/document.xml"
pkg:contentType="application/vnd.openxmlformats-
officedocument.wordprocessingml.document.main+xml">
<pkg:xmlData>
<w:document mc:Ignorable="w14 w15 wp14"
xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanva
s" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships
" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math"
xmlns:v="urn:schemas-microsoft-com:vml"
xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDraw
ing"
xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDra
wing" xmlns:w10="urn:schemas-microsoft-com:office:word"
xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml"
xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml"
xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup
"
xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk"
xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml"
xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape
">
<w:body>
<w:p>
<w:pPr>
<w:spacing w:before="360" w:after="0" w:line="480"
w:lineRule="auto"/>
<w:rPr>
<w:color w:val="70AD47" w:themeColor="accent6"/>
<w:sz w:val="28"/>
</w:rPr>
</w:pPr>
<w:r>
<w:rPr>
<w:color w:val="70AD47" w:themeColor="accent6"/>
<w:sz w:val="28"/>
</w:rPr>
<w:t>This text has formatting directly applied to achieve its
font size, color, line spacing, and paragraph spacing.</w:t>
</w:r>
<w:bookmarkStart w:id="0" w:name="_GoBack"/>
<w:bookmarkEnd w:id="0"/>
</w:p>
<w:p/>
<w:sectPr>
<w:pgSz w:w="12240" w:h="15840"/>
<w:pgMar w:top="1440" w:right="1440" w:bottom="1440"
w:left="1440" w:header="720" w:footer="720" w:gutter="0"/>
<w:cols w:space="720"/>
</w:sectPr>
</w:body>
</w:document>
</pkg:xmlData>
</pkg:part>
Since document.xml is the primary document part where you place your content, take a
quick walk through that part. (Figure 14, which follows this list, provides a visual
reference to show how some of the core content and formatting tags explained here
relate to what you see in a Word document.)
The opening w:document tag includes several namespace ( xmlns ) listings. Many
of those namespaces refer to specific types of content and you only need them if
they're relevant to your content.
Notice that the prefix for the tags throughout a document part refers back to the
namespaces. In this example, the only prefix used in the tags throughout the
document.xml part is w:, so the only namespace that you need to leave in the
opening w:document tag is xmlns:w.
Tip
If you're editing your markup in Visual Studio, after you delete namespaces in
any part, look through all tags of that part. If you've removed a namespace
that's required for your markup, you'll see a red squiggly underline on the
relevant prefix for affected tags. If you remove the xmlns:mc namespace, you
must also remove the mc:Ignorable attribute that precedes the namespace
listings.
Inside the opening body tag, you see a paragraph tag ( w:p ), which includes our
sample content for this example.
The w:pPr tag includes properties for directly-applied paragraph formatting, such
as space before or after the paragraph, paragraph alignment, or indents. (Direct
formatting refers to attributes that you apply individually to content rather than as
part of a style.) This tag also includes direct font formatting that's applied to the
entire paragraph, in a nested w:rPr (run properties) tag, which contains the font
color and size set in our sample.
You might notice that font sizes and some other formatting settings in Word Office
Open XML markup look like they're double the actual size. That's because
paragraph and line spacing, as well some section formatting properties shown in
the preceding markup, are specified in twips (one-twentieth of a point). Depending
on the types of content you work with in Office Open XML, you may see several
additional units of measure, including English Metric Units (914,400 EMUs to an
inch), which are used for some Office Art (drawingML) values and 100,000 times
actual value, which is used in both drawingML and PowerPoint markup. PowerPoint
also expresses some values as 100 times actual and Excel commonly uses actual
values.
Within a paragraph, any content with like properties is included in a run ( w:r ),
such as is the case with the sample text. Each time there's a change in formatting
or content type, a new run starts. (That is, if just one word in the sample text was
bold, it would be separated into its own run.) In this example, the content includes
just the one text run.
Notice that, because the formatting included in this sample is font formatting (that
is, formatting that can be applied to as little as one character), it also appears in
the properties for the individual run.
Also notice the tags for the hidden "_GoBack" bookmark (w:bookmarkStart and
w:bookmarkEnd ), which appear in Word documents by default. You can always
delete the start and end tags for the GoBack bookmark from your markup.
The last piece of the document body is the w:sectPr tag, or section properties. This
tag includes settings such as margins and page orientation. The content you insert
using setSelectedDataAsync will take on the active section properties in the
destination document by default. So, unless your content includes a section break
(in which case you'll see more than one w:sectPr tag), you can delete this tag.
Figure 14. How common tags in document.xml relate to the content and layout of a Word
document
Tip
In markup you create, you might see another attribute in several tags that includes
the characters w:rsid, which you don't see in the examples used in this topic. These
are revision identifiers. They're used in Word for the Combine Documents feature
and they're on by default. You'll never need them in markup you're inserting with
your add-in and turning them off makes for much cleaner markup. You can easily
remove existing RSID tags or disable the feature (as described in the following
procedure) so that they aren't added to your markup for new content.
Be aware that if you use the co-authoring capabilities in Word (such as the ability to
simultaneously edit documents with others), you should enable the feature again when
finished generating the markup for your add-in.
To turn off RSID attributes in Word for documents you create going forward, do the
following:
To remove RSID tags from an existing document, try the following shortcut with the
document open in Office Open XML.
1. With your insertion point in the main body of the document, press Ctrl+Home to
go to the top of the document.
2. On the keyboard, press Spacebar, Delete, Spacebar. Then, save the document.
After removing the majority of the markup from this package, you're left with the
minimal markup that needs to be inserted for the sample, as shown in the preceding
section.
To check out the Office Open XML markup for the examples of each of these content
types shown earlier in Figures 5 through 8, explore the Load and write Open XML in
your Word add-in code sample referenced in the overview section.
Before you move on, take a look at differences to note for a couple of these content
types and how to swap out the pieces you need.
Typically, as you see for the shape and text box examples included in the Load and write
Open XML in your Word add-in code sample, the fallback markup can be removed.
Word automatically adds missing fallback markup to shapes when a document is saved.
However, if you prefer to keep the fallback markup to ensure that you're supporting all
user scenarios, there's no harm in retaining it.
If you have grouped drawing objects included in your content, you'll see additional (and
apparently repetitive) markup, but this must be retained. Portions of the markup for
drawing shapes are duplicated when the object is included in a group.
) Important
When working with text boxes and drawing shapes, be sure to check namespaces
carefully before removing them from document.xml. (Or, if you're reusing markup
from another object type, be sure to add back any required namespaces you might
have previously removed from document.xml.) A substantial portion of the
namespaces included by default in document.xml are there for drawing object
requirements.
About graphic positioning
In the code samples Load and write Open XML in your Word add-in and Word-Add-
in-Get-Set-EditOpen-XML , the text box and shape are set up using different types of
text wrapping and positioning settings. (Also be aware that the image examples in those
code samples are set up using in line with text formatting, which positions a graphic
object on the text baseline.)
The shape in those code samples is positioned relative to the right and bottom page
margins. Relative positioning lets you more easily coordinate with a user's unknown
document setup because it will adjust to the user's margins and run less risk of looking
awkward because of paper size, orientation, or margin settings. To retain relative
positioning settings when you insert a graphic object, you must retain the paragraph
mark (w:p) in which the positioning (known in Word as an anchor) is stored. If you insert
the content into an existing paragraph mark rather than including your own, you may be
able to retain the same initial visual, but many types of relative references that enable
the positioning to automatically adjust to the user's layout may be lost.
In Word, find content controls on the Developer tab of the ribbon, as shown here in
Figure 15.
Types of content controls in Word include rich text, plain text, picture, building block
gallery, check box, dropdown list, combo box, date picker, and repeating section.
Use the Properties command, shown in Figure 15, to edit the title of the control
and to set preferences such as hiding the control container.
If your add-in works with a Word template, you can include controls in that template to
enhance the behavior of the content. You can also use XML data binding in a Word
document to bind content controls to data, such as document properties, for easy form
completion or similar tasks. (Find controls that are already bound to built-in document
properties in Word on the Insert tab, under Quick Parts.)
When you use content controls with your add-in, you can also greatly expand the
options for what your add-in can do using a different type of binding. You can bind to a
content control from within the add-in and then write content to the binding rather
than to the active selection.
Don't confuse XML data binding in Word with the ability to bind to a control via your
add-in. These are completely separate features. However, you can include named
content controls in the content you insert via your add-in using OOXML coercion and
then use code in the add-in to bind to those controls.
Also be aware that both XML data binding and Office.js can interact with custom XML
parts in your app, so it's possible to integrate these powerful tools. To learn about
working with custom XML parts in the Office JavaScript API, see the See also section of
this topic.
Working with bindings in your Word add-in is covered in the next section of this topic.
First, take a look at an example of the Office Open XML required for inserting a rich text
content control that you can bind to using your add-in.
) Important
Rich text controls are the only type of content control you can use to bind to a
content control from within your add-in.
XML
<pkg:package
xmlns:pkg="http://schemas.microsoft.com/office/2006/xmlPackage">
<pkg:part pkg:name="/_rels/.rels"
pkg:contentType="application/vnd.openxmlformats-package.relationships+xml"
pkg:padding="512">
<pkg:xmlData>
<Relationships
xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId1"
Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/of
ficeDocument" Target="word/document.xml"/>
</Relationships>
</pkg:xmlData>
</pkg:part>
<pkg:part pkg:name="/word/document.xml"
pkg:contentType="application/vnd.openxmlformats-
officedocument.wordprocessingml.document.main+xml">
<pkg:xmlData>
<w:document
xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" >
<w:body>
<w:p/>
<w:sdt>
<w:sdtPr>
<w:alias w:val="MyContentControlTitle"/>
<w:id w:val="1382295294"/>
<w15:appearance w15:val="hidden"/>
<w:showingPlcHdr/>
</w:sdtPr>
<w:sdtContent>
<w:p>
<w:r>
<w:t>[This text is inside a content control that has its
container hidden. You can bind to a content control to add or interact with
content at a specified location in the document.]</w:t>
</w:r>
</w:p>
</w:sdtContent>
</w:sdt>
</w:body>
</w:document>
</pkg:xmlData>
</pkg:part>
</pkg:package>
As already mentioned, content controls, like formatted text, don't require additional
document parts, so only edited versions of the .rels and document.xml parts are
included here.
The w:sdt tag that you see within the document.xml body represents the content
control. If you generate the Office Open XML markup for a content control, you'll see
that several attributes have been removed from this example, including the tag and
document part properties. Only essential (and a couple of best practice) elements have
been retained, including the following:
The alias is the title property from the Content Control Properties dialog box in
Word. This is a required property (representing the name of the item) if you plan to
bind to the control from within your add-in.
The unique id is a required property. If you bind to the control from within your
add-in, the ID is the property the binding uses in the document to identify the
applicable named content control.
The appearance attribute is used to hide the control container, for a cleaner look.
This feature was introduced in Word 2013, as you see by the use of the w15
namespace. Because this property is used, the w15 namespace is retained at the
start of the document.xml part.
The showingPlcHdr attribute is an optional setting that sets the default content
you include inside the control (text in this example) as placeholder content. So, if
the user clicks or taps in the control area, the entire content is selected rather than
behaving like editable content in which the user can make changes.
Although the empty paragraph mark ( w:p/ ) that precedes the sdt tag isn't
required for adding a content control (and will add vertical space above the
control in the Word document), it ensures that the control is placed in its own
paragraph. This may be important, depending upon the type and formatting of
content that will be added in the control.
If you intend to bind to the control, the default content for the control (what's
inside the sdtContent tag) must include at least one complete paragraph (as in this
example), in order for your binding to accept multi-paragraph rich content.
The document part attribute that was removed from this sample w:sdt tag may appear
in a content control to reference a separate part in the package where placeholder
content information can be stored (parts located in a glossary directory in the Office
Open XML package). Although document part is the term used for XML parts (that is,
files) within an Office Open XML package, the term document parts as used in the sdt
property refers to the same term in Word that's used to describe some content types
including building blocks and document property quick parts (for example, built-in XML
data-bound controls). If you see parts under a glossary directory in your Office Open
XML package, you may need to retain them if the content you're inserting includes
these features. For a typical content control that you intend to use to bind to from your
add-in, they aren't required. Just remember that, if you do delete the glossary parts from
the package, you must also remove the document part attribute from the w:sdt tag.
The next section will discuss how to create and use bindings in your Word add-in.
When you want the option to replace content that you're inserting at the active
selection, such as to provide design element options to the user.
When you want the user to add data in the document that you can access for use
with your add-in, such as to populate fields in the task pane based upon
information the user adds in the document.
As previously mentioned, you must use a rich text content control in order to bind
to the control from your Word add-in.
The content control must have a name (this is the Title field in the Content Control
Properties dialog box, which corresponds to the Alias tag in the Office Open XML
markup). This is how the code identifies where to place the binding.
You can have several named controls and bind to them as needed. Use a unique
content control name, unique content control ID, and a unique binding ID.
JavaScript
function addAndBindControl() {
Office.context.document.bindings.addFromNamedItemAsync("MyContentControlTitl
e", "text", { id: 'myBinding' }, function (result) {
if (result.status == "failed") {
if (result.error.message == "The named item does not exist.")
const myOOXMLRequest = new XMLHttpRequest();
let myXML;
myOOXMLRequest.open('GET',
'../../Snippets_BindAndPopulate/ContentControl.xml', false);
myOOXMLRequest.send();
if (myOOXMLRequest.status === 200) {
myXML = myOOXMLRequest.responseText;
}
Office.context.document.setSelectedDataAsync(myXML, {
coercionType: 'ooxml' }, function (result) {
Office.context.document.bindings.addFromNamedItemAsync("MyContentControlTitl
e", "text", { id: 'myBinding' });
});
}
});
}
Take this step first if there's a possible scenario for your add-in where the named
control could already exist in the document when the code runs. For example,
you'll want to do this if the add-in was inserted into and saved with a template
that's been designed to work with the add-in, where the control was placed in
advance. You also need to do this if you need to bind to a control that was placed
earlier by the add-in.
The callback in the first call to the addFromNamedItemAsync method checks the
status of the result to see if the binding failed because the named item doesn't
exist in the document (that is, the content control named MyContentControlTitle in
this example). If so, the code adds the control at the active selection point (using
setSelectedDataAsync ) and then binds to it.
As mentioned earlier and shown in the preceding code, the name of the content control
is used to determine where to create the binding. However, in the Office Open XML
markup, the code adds the binding to the document using both the name and the ID
attribute of the content control.
After running code, if you examine the markup of the document in which your add-in
created bindings, you'll see two parts to each binding. In the markup for the content
control where a binding was added (in document.xml), you'll see the attribute
w15:webExtensionLinked/.
In the document part named webExtensions1.xml, you'll see a list of the bindings you've
created. Each is identified using the binding ID and the ID attribute of the applicable
control, such as the following, where the appref attribute is the content control ID:
we:binding id="myBinding" type="text" appref="1382295294"/.
) Important
You must add the binding at the time you intend to act upon it. Don't include the
markup for the binding in the Office Open XML for inserting the content control
because the process of inserting that markup will strip the binding.
Populate a binding
The code for writing content to a binding is similar to that for writing content to a
selection.
JavaScript
function populateBinding(filename) {
const myOOXMLRequest = new XMLHttpRequest();
let myXML;
myOOXMLRequest.open('GET', filename, false);
myOOXMLRequest.send();
if (myOOXMLRequest.status === 200) {
myXML = myOOXMLRequest.responseText;
}
Office.select("bindings#myBinding").setDataAsync(myXML, { coercionType:
'ooxml' });
}
As with setSelectedDataAsync , you specify the content to be inserted and the coercion
type. The only additional requirement for writing to a binding is to identify the binding
by ID. Notice how the binding ID used in this code (bindings#myBinding) corresponds
to the binding ID established (myBinding) when the binding was created in the previous
function.
Tip
The preceding code is all you need whether you are initially populating or replacing
the content in a binding. When you insert a new piece of content at a bound
location, the existing content in that binding is automatically replaced. Check out
an example of this in the previously-referenced code sample Word-Add-in-
JavaScript-AddPopulateBindings , which provides two separate content samples
that you can use interchangeably to populate the same binding.
Images (such as those shown in Figures 3 and 4) include the binary image data in
one (and sometimes two) additional parts.
SmartArt diagrams (such as the one shown in Figure 10) require multiple additional
parts to describe the layout and content.
Charts (such as the one shown in Figure 11) require multiple additional parts,
including their own relationship (.rels) part.
You can see edited examples of the markup for all of these content types in the
previously-referenced code sample Load and write Open XML in your Word add-in .
You can insert all of these content types using the same JavaScript code shown earlier
(and provided in the referenced code samples) for inserting content at the active
selection and writing content to a specified location using bindings.
Remember, if you're retaining any additional parts referenced in document.xml, you will
need to retain document.xml.rels and the relationship definitions for the applicable parts
you're keeping, such as styles.xml or an image file.
Before you explore the samples, take a look at a few tips for working with each of these
content types.
XML
<w:body>
<w:p>
<w:pPr>
<w:pStyle w:val="Heading1"/>
</w:pPr>
<w:r>
<w:t>This text is formatted using the Heading 1 paragraph style.</w:t>
</w:r>
</w:p>
</w:body>
As you see, the markup for formatted text in document.xml is considerably simpler when
you use a style, because the style contains all of the paragraph and font formatting that
you otherwise need to reference individually. However, as explained earlier, you might
want to use styles or direct formatting for different purposes: use direct formatting to
specify the appearance of your text regardless of the formatting in the user's document;
use a paragraph style (particularly a built-in paragraph style name, such as Heading 1
shown here) to have the text formatting automatically coordinate with the user's
document.
Use of a style is a good example of how important it is to read and understand the
markup for the content you're inserting, because it isn't explicit that another document
part is referenced here. If you include the style definition in this markup and don't
include the styles.xml part, the style information in document.xml will be ignored
regardless of whether or not that style is in use in the user's document.
However, if you take a look at the styles.xml part, you'll see that only a small portion of
this long piece of markup is required when editing markup for use in your add-in:
The styles.xml part includes several namespaces by default. If you are only
retaining the required style information for your content, in most cases you only
need to keep the xmlns:w namespace.
The w:docDefaults tag content that falls at the top of the styles part will be
ignored when your markup is inserted via the add-in and can be removed.
The largest piece of markup in a styles.xml part is for the w:latentStyles tag that
appears after docDefaults, which provides information (such as appearance
attributes for the Styles pane and Styles gallery) for every available style. This
information is also ignored when inserting content via your add-in and so it can be
removed.
Following the latent styles information, you see a definition for each style in use in
the document from which you're markup was generated. This includes some
default styles that are in use when you create a new document and may not be
relevant to your content. You can delete the definitions for any styles that aren't
used by your content.
Each built-in heading style has an associated Char style that's a character style
version of the same heading format. Unless you've applied the heading style as a
character style, you can remove it. If the style is used as a character style, it appears
in document.xml in a run properties tag ( w:rPr ) rather than a paragraph
properties ( w:pPr ) tag. This should only be the case if you've applied the style to
just part of a paragraph, but it can occur inadvertently if the style was incorrectly
applied.
If you're using a built-in style for your content, you don't have to include a full
definition. You only must include the style name, style ID, and at least one
formatting attribute in order for the coerced Office Open XML to apply the style to
your content upon insertion.
However, it's a best practice to include a complete style definition (even if it's the
default for built-in styles). If a style is already in use in the destination document,
your content will take on the resident definition for the style, regardless of what
you include in styles.xml. If the style isn't yet in use in the destination document,
your content will use the style definition you provide in the markup.
So, for example, the only content you needed to retain from the styles.xml part for the
sample text shown in Figure 2, which is formatted using Heading 1 style, is the
following:
7 Note
A complete Word definition for the Heading 1 style has been retained in this
example.
XML
<pkg:part pkg:name="/word/styles.xml"
pkg:contentType="application/vnd.openxmlformats-
officedocument.wordprocessingml.styles+xml">
<pkg:xmlData>
<w:styles
xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" >
<w:style w:type="paragraph" w:styleId="Heading1">
<w:name w:val="heading 1"/>
<w:basedOn w:val="Normal"/>
<w:next w:val="Normal"/>
<w:link w:val="Heading1Char"/>
<w:uiPriority w:val="9"/>
<w:qFormat/>
<w:pPr>
<w:keepNext/>
<w:keepLines/>
<w:spacing w:before="240" w:after="0" w:line="259"
w:lineRule="auto"/>
<w:outlineLvl w:val="0"/>
</w:pPr>
<w:rPr>
<w:rFonts w:asciiTheme="majorHAnsi"
w:eastAsiaTheme="majorEastAsia" w:hAnsiTheme="majorHAnsi"
w:cstheme="majorBidi"/>
<w:color w:val="2E74B5" w:themeColor="accent1" w:themeShade="BF"/>
<w:sz w:val="32"/>
<w:szCs w:val="32"/>
</w:rPr>
</w:style>
</w:styles>
</pkg:xmlData>
</pkg:part>
However, when you look at the markup both for your table in document.xml and for
your table style definition in styles.xml, you see enormously more markup than when
working with paragraph styles.
In styles.xml, you'll see a substantial amount of markup for a single table style as
well, because table styles include several types of possible formatting attributes for
each of several table areas, such as the entire table, heading rows, odd and even
banded rows and columns (separately), the first column, etc.
XML
When you review the markup, notice the additional namespaces used in the a:blip tag.
You'll see in document.xml that the xlmns:a namespace (the main drawingML
namespace) is dynamically placed at the beginning of the use of drawingML references
rather than at the top of the document.xml part. However, the relationships namespace
(r) must be retained where it appears at the start of document.xml. Check your picture
markup for additional namespace requirements. Remember that you don't have to
memorize which types of content require what namespaces, you can easily tell by
reviewing the prefixes of the tags throughout document.xml.
XML
<a14:imgLayer r:embed="rId5">
See the required markup for the formatted image shown in Figure 4 (which uses
layering effects among others) in the Load and write Open XML in your Word add-in
code sample.
Work with SmartArt diagrams
A SmartArt diagram has four associated parts, but only two are always required. You can
examine an example of SmartArt markup in the Load and write Open XML in your Word
add-in code sample. First, take a look at a brief description of each of the parts and
why they are or aren't required:
Tip
If your content includes more than one diagram, they will be numbered
consecutively, replacing the '1' in the file names listed here.
layout1.xml: This part is required. It includes the markup definition for the layout
appearance and functionality.
data1.xml: This part is required. It includes the data in use in your instance of the
diagram.
drawing1.xml: This part isn't always required but if you apply custom formatting to
elements in your instance of a diagram, such as directly formatting individual
shapes, you might need to retain it.
colors1.xml: This part isn't required. It includes color style information, but the
colors of your diagram will coordinate by default with the colors of the active
formatting theme in the destination document, based on the SmartArt color style
you apply from the SmartArt Tools design tab in Word before saving out your
Office Open XML markup.
quickStyles1.xml: This part isn't required. Similar to the colors part, you can remove
this as your diagram will take on the definition of the applied SmartArt style that's
available in the destination document (that is, it will automatically coordinate with
the formatting theme in the destination document).
The SmartArt layout1.xml file is a good example of places you may be able to further
trim your markup but mightn't be worth the extra time to do so (because it removes
such a small amount of markup relative to the entire package). If you would like to get
rid of every last line you can of markup, you can delete the dgm:sampData tag and its
contents. This sample data defines how the thumbnail preview for the diagram will
appear in the SmartArt styles galleries. However, if it's omitted, default sample data is
used.
Be aware that the markup for a SmartArt diagram in document.xml contains relationship
ID references to the layout, data, colors, and quick styles parts. You can delete the
references in document.xml to the colors and styles parts when you delete those parts
and their relationship definitions (and it's certainly a best practice to do so, since you're
deleting those relationships), but you won't get an error if you leave them, since they
aren't required for your diagram to be inserted into a document. Find these references
in document.xml in the dgm:relIds tag. Regardless of whether or not you take this step,
retain the relationship ID references for the required layout and data parts.
Tip
As with SmartArt diagrams, if your content includes more than one chart, they will
be numbered consecutively, replacing the '1' in the file names listed here.
In document.xml.rels, you'll see a reference to the required part that contains the
data that describes the chart (chart1.xml).
You also see a separate relationship file for each chart in your Office Open XML
package, such as chart1.xml.rels.
There are three files referenced in chart1.xml.rels, but only one is required. These
include the binary Excel workbook data (required) and the color and style parts
(colors1.xml and styles1.xml) that you can remove.
Charts that you can create and edit natively in Word are Excel charts, and their data is
maintained on an Excel worksheet that's embedded as binary data in your Office Open
XML package. Like the binary data parts for images, this Excel binary data is required,
but there's nothing to edit in this part. So you can just collapse the part in the editor to
avoid having to manually scroll through it all to examine the rest of your Office Open
XML package.
However, similar to SmartArt, you can delete the colors and styles parts. If you've used
the chart styles and color styles available in to format your chart, the chart will take on
the applicable formatting automatically when it's inserted into the destination
document.
See the edited markup for the example chart shown in Figure 11 in the Load and write
Open XML in your Word add-in code sample.
Edit the Office Open XML for use in your task
pane add-in
You've already seen how to identify and edit the content in your markup. If the task still
seems difficult when you take a look at the massive Office Open XML package
generated for your document, following is a quick summary of recommended steps to
help you edit that package down quickly.
Remember that you can use all .rels parts in the package as a map to quickly check for
document parts that you can remove.
1. Open the flattened XML file in Visual Studio and press Ctrl+K, Ctrl+D to format the
file. Then use the collapse/expand buttons on the left to collapse the parts you
know you need to remove. You might also want to collapse long parts you need,
but know you won't need to edit (such as the base64 binary data for an image file),
making the markup faster and easier to visually scan.
2. There are several parts of the document package that you can almost always
remove when you are preparing Office Open XML markup for use in your add-in.
You might want to start by removing these (and their associated relationship
definitions), which will greatly reduce the package right away. These include the
theme1, fontTable, settings, webSettings, thumbnail, both the core and add-in
properties files, and any taskpane or webExtension parts.
3. Remove any parts that don't relate to your content, such as footnotes, headers, or
footers that you don't require. Again, remember to also delete their associated
relationships.
4. Review the document.xml.rels part to see if any files referenced in that part are
required for your content, such as an image file, the styles part, or SmartArt
diagram parts. Delete the relationships for any parts your content doesn't require
and confirm that you have also deleted the associated part. If your content doesn't
require any of the document parts referenced in document.xml.rels, you can delete
that file also.
5. If your content has an additional .rels part (such as chart#.xml.rels), review it to see
if there are other parts referenced there that you can remove (such as quick styles
for charts) and delete both the relationship from that file as well as the associated
part.
7. Edit any additional required parts where you know that you can remove substantial
markup without affecting your content, such as the styles part.
After you've taken the preceding seven steps, you've likely cut between about 90 and
100 percent of the markup you can remove, depending on your content. In most cases,
this is likely to be as far as you want to trim.
Regardless of whether you leave it here or choose to delve further into your content to
find every last line of markup you can cut, remember that you can use the previously-
referenced code sample Word-Add-in-Get-Set-EditOpen-XML as a scratch pad to
quickly and easily test your edited markup.
Tip
If you update an Office Open XML snippet in an existing solution while developing,
clear temporary Internet files before you run the solution again to update the
Office Open XML used by your code. Markup that's included in your solution in
XML files is cached on your computer. You can, of course, clear temporary Internet
files from your default web browser. To access Internet options and delete these
settings from inside Visual Studio 2019, on the Debug menu, choose Options.
Then, under Environment, choose Web Browser and then choose Internet Explorer
Options.
So, what else do you need to know if you're creating your add-in both for standalone
use (that is, inserted from the Store or a proprietary server location) and for use in a pre-
created template that's designed to work with your add-in? The answer might be that
you already know all you need.
The markup for a given content type and methods for inserting it are the same whether
your add-in is designed to standalone or work with a template. If you are using
templates designed to work with your add-in, just be sure that your JavaScript includes
callbacks that account for scenarios where referenced content might already exist in the
document (such as demonstrated in the binding example shown in the section Add and
bind to a named content control).
When using templates with your app, whether the add-in will be resident in the
template at the time that the user created the document or the add-in will be inserting a
template, you might also want to incorporate other elements of the API to help you
create a more robust, interactive experience. For example, you may want to include
identifying data in a customXML part that you can use to determine the template type
in order to provide template-specific options to the user. To learn more about how to
work with custom XML in your add-ins, see the additional resources that follow.
See also
Office JavaScript API
The complete language reference and related documentation on Open XML:
Standard ECMA-376: Office Open XML File Formats
Explore Office JavaScript API using Script Lab
Exploring the Office JavaScript API: Data Binding and Custom XML Parts
Companion code sample: Load and write Open XML in your Word add-in
Other code samples referenced in this article:
Word-Add-in-Get-Set-EditOpen-XML
Word-Add-in-JavaScript-AddPopulateBindings
Troubleshoot Word add-ins
Article • 06/27/2023
This article discusses troubleshooting issues that are unique to Word. Use the feedback
tool at the end of the page to suggest other issues that can be added to the article.
1. Have at least one content control in the header and at least one in the footer of
the Word document.
2. Ensure the cursor is inside a content control in the header.
3. Call insertHtml to set a content control in the footer.
The footer is then unexpectedly mixed with the header. To avoid this, clear the content
control in the footer before setting it, as shown in the following code sample.
TypeScript
// Let's say there are 2 content controls in the header and 1 in the
footer.
const contentControls = context.document.contentControls;
contentControls.load();
await context.sync().then(function () {
// Clear the 2 content controls in the header.
contentControls.items[0].clear();
contentControls.items[1].clear();
Formatting properties such as color will contain null values in the response when
different values exist in the specified range. For example, if you retrieve a range and load
its range.font.color property:
If all text in the range has the same font color, range.font.color specifies that
color.
If multiple font colors are present within the range, range.font.color is null .
See also
Troubleshoot development errors with Office Add-ins
Troubleshoot user errors with Office Add-ins
Office Add-in code samples
Article • 07/18/2023
These code samples are written to help you learn how to use various features when
developing Office Add-ins.
Getting started
The following samples show how to build the simplest Office Add-in with only a
manifest, HTML web page, and a logo. These components are the fundamental parts of
an Office Add-in. For additional getting started information, see our quick starts and
tutorials.
Blazor WebAssembly
If your development background is in building VSTO Add-ins, the following samples
show how to build Office Web Add-ins using .NET Blazor WebAssembly. You can keep
much of your code in C# and Visual Studio.
Excel
Name Description
Data types explorer Builds an Excel add-in that allows you to create and explore data
(preview) types in your workbooks. Data types enable add-in developers to
organize complex data structures as objects, such as formatted
number values, web images, and entity values.
Open in Teams Create a new Excel spreadsheet in Microsoft Teams containing data
you define.
Insert an external Excel file Insert an existing template from an external Excel file into the
and populate it with JSON currently open Excel workbook. Then, populate the template with
Name Description
Create custom contextual Create a custom contextual tab on the ribbon in the Office UI. The
tabs on the ribbon sample creates a table, and when the user moves the focus inside
the table, the custom tab is displayed. When the user moves outside
the table, the custom tab is hidden.
Use keyboard shortcuts Set up a basic Excel add-in project that utilizes keyboard shortcuts.
for Office Add-in actions
Custom function sample Use web workers in custom functions to prevent blocking the UI of
using web worker your Office Add-in.
Use storage techniques to Implement localStorage to enable limited functionality for your
access data from an Office Office Add-in when a user experiences lost connection.
Add-in when offline
Custom function batching Batch multiple calls into a single call to reduce the number of
pattern network calls to a remote service.
Outlook
Name Description
Use Outlook event-based Use event-based activation to run an Outlook add-in when the
activation to tag external user changes recipients while composing a message. The add-
recipients in also uses the appendOnSendAsync API to add a disclaimer.
Use Outlook event-based Use event-based activation to run an Outlook add-in when the
activation to set the signature user creates a new message or appointment. The add-in can
respond to events, even when the task pane is not open. It
also uses the setSignatureAsync API.
Use Outlook Smart Alerts Use Outlook Smart Alerts to verify that required color
categories are applied to a new message or appointment
before it's sent.
Verify the sensitivity label of a Use the sensitivity label API in an event-based add-in to verify
message and apply the Highly Confidential sensitivity label to
applicable outgoing messages.
Word
Name Description
Get, edit, and set This sample shows how to get, edit, and set OOXML content in a Word
OOXML content in a document. The sample add-in provides a scratch pad to get Office Open
Word document with a XML for your own content and test your own edited Office Open XML
Word add-in snippets.
Load and write Open This sample add-in shows you how to add a variety of rich content types
XML in your Word to a Word document using the setSelectedDataAsync method with
add-in ooxml coercion type. The add-in also gives you the ability to show the
Office Open XML markup for each sample content type right on the
page.
Use SSO with event-based Shows how to use SSO to access a user's Microsoft Graph data
activation in an Outlook add- from an event fired in an Outlook add-in.
in
Single Sign-on (SSO) Sample Use Office's SSO feature to give the add-in access to Microsoft
Outlook Add-in Graph data.
Get OneDrive data using Build an Office Add-in, as a single-page application (SPA) with no
Microsoft Graph and msal.js backend, that connects to Microsoft Graph, and access
in an Office Add-in workbooks stored in OneDrive for Business to update a
spreadsheet.
Office Add-in auth to Learn how to build a Microsoft Office Add-in that connects to
Microsoft Graph Microsoft Graph, and access workbooks stored in OneDrive for
Business to update a spreadsheet.
Outlook Add-in auth to Build an Outlook add-in that connects to Microsoft Graph, and
Microsoft Graph . access workbooks stored in OneDrive for Business to compose a
new email message.
Single Sign-on (SSO) Office Use the getAccessToken API in Office.js to give the add-in access
Add-in with ASP.NET to Microsoft Graph data. This sample is built on ASP.NET.
Single Sign-on (SSO) Office Use the getAccessToken API in Office.js to give the add-in access
Add-in with Node.js to Microsoft Graph data. This sample is built on Node.js.
Office
Name Description
Save custom Save custom settings inside an Office Add-in. The add-in stores data as key-
settings in your value pairs, using the JavaScript API for Office property bag, browser cookies,
Office Add-in web storage (localStorage and sessionStorage), or by storing the data in a
hidden div in the document.
Shared runtime
Name Description
Share global data with a Set up a basic project that uses the shared runtime to run code
shared runtime for ribbon buttons, task pane, and custom functions in a single
browser runtime.
Manage ribbon and task pane Create contextual ribbon buttons that are enabled based on the
UI, and run code on doc open state of your add-in.
Additional samples
Name Description
Use a shared library to migrate your Visual Provides a strategy for code reuse when
Studio Tools for Office add-in to an Office web migrating from VSTO Add-ins to Office Add-ins.
add-in
Integrate an Azure function with your Excel Integrate Azure functions with custom functions
custom function to move to the cloud or integrate additional
services.
Next steps
Join the Microsoft 365 Developer Program. Get a free sandbox, tools, and other
resources you need to build solutions for the Microsoft 365 platform.
Free developer sandbox Get a free, renewable 90-day Microsoft 365 E5 developer
subscription.
Sample data packs Automatically configure your sandbox by installing user data
and content to help you build your solutions.
Access to experts Access community events to learn from Microsoft 365 experts.
Personalized recommendations Find developer resources quickly from your
personalized dashboard.
Create an Excel spreadsheet from your
web page, populate it with data, and
embed your Office Add-in
Article • 03/09/2023
Microsoft partners with SaaS web applications know that their customers often want to
open their data from a web page in an Excel spreadsheet. They use Excel to do analysis
on the data, or other types of number crunching. Then they upload the data back to the
web site.
Instead of multiple steps to export the data from the web site to a .csv file, import the
.csv file into Excel, work with the data, then export it from Excel, and upload it back to
the web site, we can simplify this process to one button click.
This article shows how to add an Excel button to your web site. When a customer
chooses the button, it automatically creates a new spreadsheet with the requested data,
uploads it to the customer's OneDrive, and opens it in Excel on a new browser tab. With
one click the requested data is opened in Excel and formatted correctly. Additionally the
pattern embeds your own Office Add-in inside the spreadsheet so that customers can
still access your services from the context of Excel.
Microsoft partners who implemented this pattern have seen increased customer
satisfaction. They've also seen a significant increase in engagement with their add-ins by
embedding them in the Excel spreadsheet. We recommend that if you have a web site
for customers to work with data, that you consider implementing this pattern in your
own solution.
Prerequisites
Visual Studio 2022 or later . Add the Office/SharePoint development workload
when configuring Visual Studio.
Visual Studio Code .
Microsoft 365. You can get a free developer sandbox that provides a renewable 90-
day Microsoft 365 E5 developer subscription. The developer sandbox includes a
Microsoft Azure subscription that you can use for app registrations in later steps in
this article. If you prefer, you can use a separate Microsoft Azure subscription for
app registrations. Get a trial subscription at Microsoft Azure.
One or more files and folders on OneDrive in the Microsoft 365 account.
Solution architecture
Web page
Azure Func ons
App
Pass data to Azure Func ons app
Upload to OneDrive
Microso Graph
OneDrive
1. The user chooses the Open in Microsoft Excel button. The web page passes the
data to a function in an Azure Functions app.
2. The function uses the Open XML SDK to create a new Excel spreadsheet in
memory. It populates the spreadsheet with the data, and embeds your Office Add-
in.
3. The function returns the spreadsheet as a Base64 encoded string to the web page.
4. The web page calls the Microsoft Graph API to upload the spreadsheet to the
user's OneDrive.
5. Microsoft Graph returns the web url location of the new spreadsheet file.
6. The web page opens a new browser tab to open the spreadsheet at the web url.
The spreadsheet contains the data, and your add-in.
The following sections describe important concepts and implementation details for
constructing the solution. A full reference implementation can be found in the sample
code for additional implementation details.
You need a button on the web site that creates the Excel spreadsheet. A best practice is
to use the Fluent UI to help your users transition between Microsoft products. You
should always use an Office icon to indicate which Office application will be launched
from your web page. For more information, see Office Brand Icons on the Fluent UI
developer portal.
Sign in the user
The sample code is built from the Microsoft identity sample named Vanilla JavaScript
single-page application using MSAL.js to authenticate users to call Microsoft Graph .
All authentication code and UI is from this sample. Please refer to this sample for more
information about writing code for authentication and authorization. For a full list of
identity samples for a wide range of platforms, see Microsoft identity platform code
samples.
Much of the SpreadsheetBuilder class contains code that was generated by the Open
XML 2.5 SDK Productivity Tools. These are available at the link for the Open XML 2.5
SDK.
C#
You can change these values to embed your own Office Add-in. This makes it
discoverable to the user and increases engagement with your add-in and web services.
If your add-in is deployed through central deployment, use the following values instead.
C#
For more information about alternative values for these attributes, see Automatically
open a task pane with a document and [MS-OWEXML]: CT_OsfWebExtensionReference
Uncomment the code and change it to add any customer properties you need. In your
add-in, use the Office Settings get method to retrieve a custom property. The following
sample shows how to get the user name property from the spreadsheet.
JavaScript
U Caution
See Persist add-in state and settings for complete details on how to read custom
properties when your add-in starts.
See also
Welcome to the Open XML SDK 2.5 for Office
Automatically open a task pane with a document
Persisting add-in state and settings
Create a spreadsheet document by providing a file name
Create a standalone Office Add-in from
your Script Lab code
Article • 06/23/2023
If you created a snippet in Script Lab, you may want to turn it into a standalone add-in.
You can copy the code from Script Lab into a project generated by the Yeoman
Generator for Office Add-ins (also called "Yo Office"). Then you can continue developing
the code as an add-in that you can eventually deploy to others.
The steps in this article refer to Visual Studio Code , but you can use any code editor
that you prefer.
Run the command yo office --projectType taskpane --ts true --host <host> --name
"basic-sample" , where <host> is one of the following values.
excel
outlook
powerpoint
word
) Important
The --name argument value must be in double quotation marks, even if it has no
spaces.
The previous command creates a new project folder named basic-sample. It's
configured to run in the host you specified, and uses TypeScript. Script Lab uses
TypeScript by default, but most of the snippets are JavaScript. You can build a Yo Office
JavaScript project if you prefer, but just be sure any code you copy over is JavaScript.
For Excel, PowerPoint, or Word, choose the Basic API Call (TypeScript)
sample.
For Outlook, choose the Use add-in settings sample.
In the next steps, you'll copy code from several tabs in Script Lab.
1. Open the taskpane.html file, and add the following script tag to the <head>
section.
HTML
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-3.3.1.js">
</script>
7 Note
The specific version of jQuery may vary. You can determine which version
Script Lab is using by choosing the Libraries tab.
command line
If you created a snippet that has additional library dependencies, be sure to add them to
the Yo Office project. Find a list of all library dependencies on the Libraries tab in Script
Lab.
Handle initialization
Script Lab handles the Office.onReady initialization automatically. You'll need to modify
the code to provide your own Office.onReady handler.
with:
TypeScript
Office.onReady(function () {
// Office is ready.
$(document).ready(function () {
// The document is ready
$("#run").click(() => tryCatch(run));
});
});
TypeScript
$("#get").click(get);
$("#set").click(set);
$("#save").click(save);
with:
TypeScript
Office.onReady(function () {
// Office is ready
$(document).ready(function () {
// The document is ready
$("#get").click(get);
$("#set").click(set);
$("#save").click(save);
});
});
Custom functions
If your snippet uses custom functions, you need to use the Yo Office custom functions
template. To turn custom functions into a standalone add-in, follow these steps.
1. Run the command yo office --projectType excel-functions --ts true --name
"functions-sample" .
) Important
The --name argument value must be in double quotation marks, even if it has
no spaces.
4. In the Script Lab task pane, choose Samples, and then choose the Basic custom
function sample.
7. Copy all of the code in the Script tab to the clipboard. Paste the code at the top of
the functions.ts (or functions.js for JavaScript) with the code you copied.
command line
npm start
Office will start and you can open the task pane for your add-in from the ribbon.
Congratulations! Now you can continue building your add-in as a standalone project.
Console logging
Many snippets in Script Lab write output to a console section at the bottom of the task
pane. The Yo Office project doesn't have a console section. All console.log* statements
will write to the default debug console (such as your browser developer tools). If you
want the output to go to your task pane, you'll need to update the code.
Batch custom function calls for a remote
service
Article • 03/09/2023
If your custom functions call a remote service you can use a batching pattern to reduce
the number of network calls to the remote service. To reduce network round trips you
batch all the calls into a single call to the web service. This is ideal when the spreadsheet
is recalculated.
For example, if someone used your custom function in 100 cells in a spreadsheet, and
then recalculated the spreadsheet, your custom function would run 100 times and make
100 network calls. By using a batching pattern, the calls can be combined to make all
100 calculations in a single network call.
) Important
Note that Excel custom functions are available on the following platforms.
Office on Windows
Microsoft 365 subscription
retail perpetual Office 2016 and later
Office on Mac
Office on the web
Office on iPad
volume-licensed perpetual versions of Office 2019 or earlier
1. A push operation to add a new operation to the batch of calls each time Excel calls
your custom function.
2. A function to make the remote request when the batch is ready.
3. Server code to respond to the batch request, calculate all of the operation results,
and return the values.
In the following sections, you'll learn how to construct the code one example at a time.
It's recommended you create a brand-new custom functions project using the Yeoman
generator for Office Add-ins generator. To create a new project, see Get started
developing Excel custom functions. You can use TypeScript or JavaScript.
In the following code, the custom function performs division but relies on a remote
service to do the actual calculation. It calls _pushOperation to batch the operation along
with other operations to the remote service. It names the operation div2. You can use
any naming scheme you want for operations as long as the remote service is also using
the same scheme (more on the remote service later). Also, the arguments the remote
service will need to run the operation are passed.
JavaScript
/**
* Divides two numbers using batching
* @CustomFunction
* @param dividend The number being divided
* @param divisor The number the dividend is divided by
* @returns The result of dividing the two numbers
*/
function div2(dividend, divisor) {
return _pushOperation("div2", [dividend, divisor]);
}
service.
JavaScript
This code also checks to see if a batch is scheduled. In this example, each batch is
scheduled to run every 100ms. You can adjust this value as needed. Higher values result
in bigger batches being sent to the remote service, and a longer wait time for the user
to see results. Lower values tend to send more batches to the remote service, but with a
quick response time for users.
The function creates an invocationEntry object that contains the string name of which
operation to run. For example, if you had two custom functions named multiply and
divide , you could reuse those as the operation names in your batch entries. args holds
the arguments that were passed to your custom function from Excel. And finally,
resolve or reject methods store a promise holding the information the remote service
returns.
JavaScript
JavaScript
// This is a private helper function, used only within your custom function
add-in.
// You wouldn't call _makeRemoteRequest in Excel, for example.
// This function makes a request for remote processing of the whole batch,
// and matches the response batch to the request batch.
function _makeRemoteRequest() {
// Copy the shared batch and allow the building of a new batch while you
are waiting for a response.
// Note the use of "splice" rather than "slice", which will modify the
original _batch array
// to empty it out.
try{
console.log("makeRemoteRequest");
const batchCopy = _batch.splice(0, _batch.length);
_isBatchedRequestScheduled = false;
// Build a simpler request batch that only contains the arguments for each
invocation.
const requestBatch = batchCopy.map((item) => {
return { operation: item.operation, args: item.args };
});
console.log("makeRemoteRequest2");
// Make the remote request.
_fetchFromRemoteService(requestBatch)
.then((responseBatch) => {
console.log("responseBatch in fetchFromRemoteService");
// Match each value from the response batch to its corresponding
invocation entry from the request batch,
// and resolve the invocation promise with its corresponding response
value.
responseBatch.forEach((response, index) => {
if (response.error) {
batchCopy[index].reject(new Error(response.error));
console.log("rejecting promise");
} else {
console.log("fulfilling promise");
console.log(response);
batchCopy[index].resolve(response.result);
}
});
});
console.log("makeRemoteRequest3");
} catch (error) {
console.log("error name:" + error.name);
console.log("error message:" + error.message);
console.log(error);
}
}
Decide how to serialize the batch operations over the network. For example, you
may want to put the array into a JSON body.
Instead of calling _fetchFromRemoteService you need to make the actual network
call to the remote service passing the batch of operations.
JavaScript
try {
if (operation === "div2") {
// Divide the first argument by the second argument.
return {
result: args[0] / args[1]
};
} else if (operation === "mul2") {
// Multiply the arguments for the given entry.
const myResult = args[0] * args[1];
console.log(myResult);
return {
result: myResult
};
} else {
return {
error: `Operation not supported: ${operation}`
};
}
} catch (error) {
return {
error: `Operation failed: ${operation}`
};
}
});
}
function pause(ms) {
console.log("pause");
return new Promise((resolve) => setTimeout(resolve, ms));
}
Depending on your server platform (Node.js or others) map the client network call
to this function.
Remove the pause function which simulates network latency as part of the mock.
Modify the function declaration to work with the parameter passed if the
parameter is changed for network purposes. For example, instead of an array, it
may be a JSON body of batched operations to process.
Modify the function to perform the operations (or call functions that do the
operations).
Apply an appropriate authentication mechanism. Ensure that only the correct
callers can access the function.
Place the code in the remote service.
Next steps
Learn about the various parameters you can use in your custom functions. Or review the
basics behind making a web call through a custom function.
See also
Volatile values in functions
Create custom functions in Excel
Excel custom functions tutorial
Office Add-ins glossary
Article • 03/21/2023
add-in
Office Add-ins are web applications that extend Office applications. These web
applications add new functionality to the Office application, such as bring in external
data, automate processes, or embed interactive objects in Office documents.
Office Add-ins differ from VBA, COM, and VSTO add-ins because they offer cross-
platform support (usually web, Windows, Mac, and iPad) and are based on standard web
technologies (HTML, CSS, and JavaScript). The primary programming language of an
Office Add-in is JavaScript or TypeScript.
add-in commands
Add-in commands are UI elements, such as buttons and menus, that extend the Office
UI for your add-in. When users select an add-in command element, they initiate actions
such as running JavaScript code or displaying the add-in in a task pane. Add-in
commands let your add-in look and feel like a part of Office, which gives users more
confidence in your add-in. See Add-in commands to learn more.
application
Application refers to an Office application. The Office applications that support Office
Add-ins are Excel, OneNote, Outlook, PowerPoint, Project, and Word.
application-specific API
Application-specific APIs provide strongly-typed objects that interact with objects that
are native to a specific Office application. For example, you call the Excel JavaScript APIs
for access to worksheets, ranges, tables, charts, and more. Application-specific APIs are
currently available for Excel, OneNote, PowerPoint, Visio, and Word. See Application-
specific API model to learn more.
client
Client typically refers to an Office application. The Office applications, or clients, that
support Office Add-ins are Excel, OneNote, Outlook, PowerPoint, Project, and Word.
Common API
Common APIs are used to access features such as UI, dialogs, and client settings that are
common across multiple Office applications. This API model uses callbacks , which
allow you to specify only one operation in each request sent to the Office application.
Common APIs were introduced with Office 2013. Some Common APIs are legacy APIs
from the early 2010s. Excel, PowerPoint, and Word all have Common API functionality,
but most of this functionality has been replaced or superseded by the application-
specific API model. The application-specific APIs are preferred when possible.
Other Common APIs, such as the Common APIs related to Outlook, UI, and
authentication, are the modern and preferred APIs for these purposes. For details about
the Common API object model, see Common JavaScript API object model.
content add-in
Content add-ins are webviews, or web browser views, that are embedded directly into
Excel, OneNote, or PowerPoint documents. Content add-ins give users access to
interface controls that run code to modify documents or display data from a data
source. Use content add-ins when you want to embed functionality directly into the
document. See Content Office Add-ins to learn more.
Contoso
Contoso Ltd. (also known as Contoso and Contoso University) is a fictional company
used by Microsoft as an example company and domain.
custom function
A custom function is a user-defined function that is packaged with an Excel add-in.
Custom functions enable developers to add new functions, beyond the typical Excel
features, by defining those functions in JavaScript as part of an add-in. Users within
Excel can access custom functions just as they would any native function in Excel. See
Create custom functions in Excel to learn more.
7 Note
host
<Host> typically refers to an Office application. The Office applications, or hosts, that
support Office Add-ins are Excel, OneNote, Outlook, PowerPoint, Project, and Word.
perpetual
Perpetual refers to versions of Office available through a volume-licensing agreement or
retail channels.
Other Microsoft content may use the term non-subscription to represent this concept.
platform
A platform usually refers to the operating system running the Office application.
Platforms that support Office Add-ins include Windows, Mac, iPad, and web browsers.
quick start
A quick start is a high-level description of key skills and knowledge required for the
basic operation of a particular program. In the Office Add-ins documentation, a quick
start is an introduction to developing an add-in for a particular application, such as
Outlook. A quick start contains a series of steps that an add-in developer can complete
in approximately 5 minutes, resulting in a functioning add-in and functional
development environment.
requirement set
Requirement sets are named groups of API members. Requirement sets can be specific
to Office applications, such as the ExcelApi 1.7 requirement set (a set of APIs that can
only be used in Excel), or common to multiple applications, such as the DialogApi 1.1
requirement set (a set of APIs that can be used in any Office application that supports
the Dialog API).
Your add-in can use requirement sets to determine whether the Office application
supports the API members that it needs to use. For more information about this, see
Specify Office applications and API requirements.
Requirement set support varies by Office application, version, and platform. For detailed
information about the platforms, requirement sets, and Common APIs that each Office
application supports, see Office client application and platform availability for Office
Add-ins.
Other Microsoft content may use the term one-time purchase or consumer to represent
this concept.
runtime
A runtime is the host environment (including a JavaScript engine and usually also an
HTML rendering engine) that the add-in runs in. In Office on Windows and Office on
Mac, the runtime is an embedded browser control (or webview) such as Internet
Explorer, Edge Legacy, Edge WebView2, or Safari. Different parts of an add-in run in
separate runtimes. For example, add-in commands, custom functions, and task pane
code typically use separate runtimes unless you configure a shared runtime. See
Runtimes in Office Add-ins and Browsers and webview controls used by Office Add-ins
for more information.
shared runtime
A shared runtime, enables all code in your add-in, including task pane, add-in
commands, and custom functions, to run in the same runtime and continue running
even when the task pane is closed. See shared runtime and Tips for using the shared
runtime in your Office Add-in to learn more.
subscription
Subscription refers to versions of Office available with a Microsoft 365 subscription.
task pane
Task panes are interface surfaces, or webviews, that typically appear on the right side of
the window within Excel, Outlook, PowerPoint, and Word. Task panes give users access
to interface controls that run code to modify documents or emails, or display data from
a data source. Use task panes when you don't need to or can't embed functionality
directly into the document. See Task panes in Office Add-ins to learn more.
tutorial
A tutorial is a teaching aid designed to help people learn to use a product or procedure.
In the Office Add-ins context, a tutorial guides an add-in developer through the
complete add-in development process for a particular application, such as Excel. This
involves following 20 or more steps and is a greater time investment than a quick start.
See also: quick start.
Other Microsoft content may use the term commercial to represent this concept.
web add-in
Web add-in is a legacy term for an Office Add-in. This term may be used when the
Microsoft 365 documentation needs to distinguish modern Office Add-ins from other
types of add-ins like VBA, COM, or VSTO.
webview
A webview is an element or view that displays web content inside an application.
Content add-ins and task panes both contain embedded web browsers and are
examples of webviews in Office Add-ins.
XLL
An XLL add-in is an Excel add-in file that provides user-defined functions and has the
file extension .xll. An XLL file is a type of dynamic link library (DLL) file that can only be
opened by Excel. XLL add-in files must be written in C or C++. Custom functions are the
modern equivalent of XLL user-defined functions. Custom functions offer support across
platforms and are backwards compatible with XLL files. See Extend custom functions
with XLL user-defined functions for more information.
See also
Office Add-ins additional resources
Office Add-ins additional resources
Article • 03/08/2023
These resources provide additional information and support for developing Office Add-
ins.
Microsoft 365 If you have a Premier support contract for Microsoft 365, visit the Microsoft
product issues and 365 Admin Center and use the Support menu to open a service request .
failures
Azure help and If you have a paid Azure subscription, visit the Azure Admin Center to open
support a ticket .
General questions If you have general questions about Microsoft 365 or Office, submit your
about Microsoft questions on Microsoft 365 and Office Community .
365
Developer Contact
need
Developer Contact
need
Office Add-in / Post API questions to Stack Overflow using the office-js tag, and also
Office include the outlook-web-addins tag if your question relates to Outlook
JavaScript API add-ins. Please note that Stack Overflow has guidelines such as requiring
questions a descriptive title, a complete and concise problem statement, and
sufficient details to reproduce your issue. Feature requests or overly
broad questions are off-topic; new users should visit the Stack Overflow
Help Center for more details.
You can also post questions using the Office Development tag on
Microsoft Q&A .
Documentation If the documentation is missing something that would help you understand
gaps how to create add-ins, please submit an issue to the Office Add-ins
documentation GitHub repository
Report issues
Submit issues and ask general questions related to add-ins, documentation, and
samples using the community help channels.
Office Add-ins or If you encounter an issue (bug) with the Office JavaScript API, please
Office JavaScript API submit an issue to the Office JavaScript APIs GitHub repository .
issues
Documentation issues If you encounter an issue (bug) with the documentation, please submit
an issue to the Office Add-ins documentation GitHub repository .
Issues with code Submit issues with samples to the Office Add-ins code samples
samples repository.
Documentation feedback
Submit documentation feedback or updates using the community help channels.
Documentation If you encounter an issue (bug) with the documentation, please submit an issue
issues to the Office Add-ins documentation GitHub repository .
Documentation To make changes to the documentation yourself, choose the Edit link on an
updates article and submit a pull request to the Office Add-ins documentation GitHub
repository .
Feature request and general help
Suggest a feature or vote up existing feature requests.
Office Add-ins or To submit a feature request for the Office JavaScript API, please post your
Office JavaScript idea to the Microsoft 365 Developer Platform Tech Community .
API feature
requests
General Send general questions about the Office Add-ins platform to Office Add-ins
questions Community Help. We encourage posting questions on the channels
mentioned here and using email only if no other mode of communication is
applicable.
Pluralsight John Brown's course "Fundamentals of Building Office Add-ins with Office JavaScript
course APIs" teaches you how to develop a PowerPoint add-in from scratch, including
about information about how to communicate with Trello and publish the add-in to the
Office Office Store.
Add-ins
LinkedIn Bill Ayer's course "Microsoft Office Add-Ins for Developers" gives an overview of
course the platform and explains many of the major concepts of Office Add-ins.
about
Office
Add-ins
Building Michael Zlatkovsky's book Building Office Add-ins using Office.js describes the
Office principles and design patterns shared by the 2016 APIs for Excel, Word, and
Add-ins OneNote. At the time of writing, Michael was a member of the Office Extensibility
using team at Microsoft, but this book is independently authored without input from
Office.js Microsoft. Neither Microsoft nor Michael collect any profit on this book, as proceeds
book are donated to disaster-relief and humanitarian charitable causes.
See also
Learn about the Microsoft 365 Developer Program
Explore Office JavaScript API using Script Lab
Microsoft Office Add-ins community call
Article • 08/10/2023
The Microsoft Office Add-ins community call is a monthly call where you can learn more
about new features, development practices, and additional information about creating
Office Add-ins. The community call occurs the second Wednesday of each month at 8:00
AM Pacific Time. You can download the calendar invite at
https://aka.ms/officeaddinscommunitycall .
Previous calls
Missed a previous community call? Check out the following blog resources to catch up
on the discussion!
See also
Recurring, monthly community call calendar invite
Community call topic requests and questions
Microsoft 365 developer YouTube channel
Microsoft 365 community YouTube channel
Microsoft 365 community site
Microsoft 365 community blog
VSTO add-in developer's guide to Office
Web Add-ins
Article • 05/20/2023
So, you've made some VSTO add-ins for Office applications that run on Windows and
now you're exploring the new way of extending Office that will run on Windows, Mac,
and the web browser version of the Office suite: Office Web Add-ins.
) Important
COM and VSTO add-ins aren't supported in the new Outlook on Windows that's
currently in preview. These add-ins are still supported in the classic Outlook on
Windows desktop client. To learn more, see Develop Outlook add-ins for new
Outlook on Windows (preview).
Your understanding of the object models for the Excel, Word, and the other Office
applications will be a huge help because the object models in Office Web Add-ins follow
similar patterns. But there are going to be some challenges:
For these reasons, much of this article duplicates our Beginner's guide to Office
extensions. What we've added are some learning resources to help VSTO add-in
developers leverage their experience, and also help them reuse their existing code.
Step 0: Prerequisites
Office Web Add-ins (also referred to as Office Add-ins) are essentially web
applications embedded in Office. So, you should first have a basic understanding
of web applications and how they're hosted on the web. There's an enormous
amount of information about this on the Internet, in books, and in online courses.
A good way to start if you have no prior knowledge of web applications at all is to
search for "What is a web app?" in your search engine.
The primary programming language you'll use to create Office Add-ins is
JavaScript or TypeScript. If you're not familiar with either of these languages, but
you have experience with VBA, VB.NET, C#, you'll probably find TypeScript easier to
learn. Again, there's a wealth of information about these languages on the Internet,
in books, and in online courses.
Office Add-ins Platform Overview: Find out what Office Web Add-ins are and how
they differ from older ways of extending Office, such as VSTO add-ins.
Develop Office Add-ins: Get an overview of Office Add-in development and
lifecycle including tooling, creating an add-in UI, and using the JavaScript APIs to
interact with the Office document.
There are a lot of links in those articles, but if you're transitioning to Office Web Add-ins,
we recommend that you come back here when you've read them and continue with the
next section.
Visual Studio
Node.js and Visual Studio Code
Step 3: Code
You can't learn to drive by reading the owner's manual, so start coding with this Excel
tutorial. You'll be using the Office JavaScript library and some XML in the add-in's
manifest. There's no need to memorize anything, because you'll be getting more
background about both in a later step.
Step 4: Understand the JavaScript library
Get the big picture of the Office JavaScript library with the Understand the Office
JavaScript APIs tutorial from Microsoft Learn training.
Then, explore the Office JavaScript APIs with the Script Lab tool -- a sandbox for running
and exploring the APIs.
Next Steps
Congratulations on finishing the VSTO add-in developer's learning path for Office Web
Add-ins! Here are some suggestions for further exploration of our documentation:
Visual Studio Tools for Office (VSTO) Add-ins are great for extending Office to provide
solutions for your business or others. They've been around for a long time and there are
thousands of solutions built with VSTO. However, they only run on Office on Windows.
You can't run VSTO Add-ins on Mac, on the web, or on mobile platforms.
) Important
COM and VSTO add-ins aren't supported in the new Outlook on Windows that's
currently in preview. These add-ins are still supported in the classic Outlook on
Windows desktop client. To learn more, see Develop Outlook add-ins for new
Outlook on Windows (preview).
Office Add-ins use HTML, JavaScript, and additional web technologies to build Office
solutions on all platforms. Migrating your existing VSTO Add-in to an Office Add-in is a
great way to make your solution available across all platforms.
You may want to maintain both your VSTO Add-in and a new Office Add-in that both
have the same functionality. This enables you to continue servicing your customers that
use the VSTO Add-in on Office on Windows. This also enables you to provide the same
functionality in an Office Add-in for customers across all platforms. You can also Make
your Office Add-in compatible with the existing VSTO Add-in.
However, it's best to avoid rewriting all the code from your VSTO Add-in for the Office
Add-in. This tutorial shows how to avoid rewriting code by using a shared code library
for both add-ins.
Create a shared class library by refactoring code into a .NET class library.
Create a REST API wrapper using ASP.NET Core for the shared class library.
Call the REST API from the Office Add-in to access shared code.
Prerequisites
To set up your development environment:
A Microsoft 365 account. You can join the Microsoft 365 developer program that
provides a renewable 90-day Microsoft 365 subscription that includes Office apps.
A Microsoft Azure Tenant. A trial subscription can be acquired here: Microsoft
Azure .
7 Note
The sample uses C#, but you can apply the techniques in this tutorial to a VSTO
Add-in written in any .NET language.
1. Download the VSTO Add-in shared library for Office Add-in PnP solution to a
working folder on your computer.
2. Start Visual Studio 2019 and open the /start/Cell-Analyzer.sln solution.
3. On the Debug menu, choose Start Debugging.
The add-in is a custom task pane for Excel. You can select any cell with text, and then
choose the Show unicode button. In the Result section, the add-in will display a list of
each character in the text along with its corresponding Unicode number.
Document code
In VSTO, code interacts with the document through .NET objects, such as
Microsoft.Office.Interop.Excel.Range . However, Office Add-ins use the Office.js library.
Although these are similar, they aren't exactly the same. So again, you can't share
document interaction code with the Office Add-in.
Logic code
Business logic, algorithms, helper functions, and similar code often make up the heart of
a VSTO Add-in. This code works independently of the UI and document code to perform
analysis, connect to backend services, run calculations, and more. This is the code that
can be shared so that you don't have to rewrite it in JavaScript.
Let's examine the VSTO Add-in. In the following code, each section is identified as
DOCUMENT, UI, or ALGORITHM code.
C#
if (null != rangeCell.Value)
{
cellValue = rangeCell.Value.ToString();
}
Using this approach, you can see that one section of code can be shared with the Office
Add-in. The following code needs to be refactored into a separate class library.
C#
1. If you haven't already, start Visual Studio 2019 and open the \start\Cell-
Analyzer.sln solution.
2. Right-click the solution in Solution Explorer and choose Add > New Project.
3. In the Add a new project dialog, choose Class Library (.NET Framework), and
choose Next.
7 Note
Don't use the .NET Core class library because it won't work with your VSTO
project.
4. In the Configure your new project dialog, set the following fields.
5. Choose Create.
7. Add the following code to the CellOperations class to create a method named
GetUnicodeFromText .
C#
C#
//Convert to Unicode listing
string result = "";
foreach (char c in cellValue)
{
int unicode = c;
result += $"{c}: {unicode}\r\n";
}
5. Update the line of code under the //Output the result comment to read as
follows:
C#
6. On the Debug menu, choose Start Debugging. The custom task pane should work
as expected. Enter some text in a cell, and then test that you can convert it to a
Unicode list with the add-in.
1. In Solution Explorer, right-click the Cell-Analyzer project, and choose Add > New
Project.
2. In the Add a new project dialog, choose ASP.NET Core Web Application, and
choose Next.
3. In the Configure your new project dialog, set the following fields.
4. Choose Create.
5. In the Create a new ASP.NET Core web application dialog, select ASP.NET Core 3.1
for the version, and select API in the list of projects.
6. Leave all other fields at default values and choose the Create button.
10. Right-click the Controllers folder, and choose Add > Controller.
11. In the Add New Scaffolded Item dialog, choose API Controller - Empty, then
choose Add.
12. In the Add Empty API Controller dialog, name the controller
AnalyzeUnicodeController, then choose Add.
13. Open the AnalyzeUnicodeController.cs file and add the following code as a
method to the AnalyzeUnicodeController class.
C#
[HttpGet]
public ActionResult<string> AnalyzeUnicode(string value)
{
if (value == null)
{
return BadRequest();
}
return
CellAnalyzerSharedLibrary.CellOperations.GetUnicodeFromText(value);
}
14. Right-click the CellAnalyzerRESTAPI project, and choose Set as Startup Project.
16. A browser will launch. Enter the following URL to test that the REST API is working:
https://localhost:<ssl port number>/api/analyzeunicode?value=test . You can
reuse the port number from the URL in the browser that Visual Studio launched.
You should see a string returned with Unicode values for each character.
1. In Solution Explorer, right-click the Cell-Analyzer solution, and choose Add > New
Project.
2. In the Add a new project dialog, choose Excel Web Add-in, and choose Next.
3. In the Configure your new project dialog, set the following fields.
4. Choose Create.
5. In the Choose the add-in type dialog, select Add new functionalities to Excel, and
choose Finish.
HTML
3. Open the Home.js file, and replace the entire contents with the following code.
JavaScript
(function () {
"use strict";
// The initialize function must be run each time a new page is
loaded.
Office.initialize = function (reason) {
$(document).ready(function () {
});
};
})();
function showUnicode() {
Excel.run(function (context) {
const range = context.workbook.getSelectedRange();
range.load("values");
return context.sync(range).then(function (range) {
const url = "https://localhost:<ssl port
number>/api/analyzeunicode?value=" + range.values[0][0];
$.ajax({
type: "GET",
url: url,
success: function (data) {
let htmlData = data.replace(/\r\n/g, '<br>');
$("#txtResult").html(htmlData);
},
error: function (data) {
$("#txtResult").html("error occurred in ajax call.");
}
});
});
});
}
4. In the previous code, enter the sslPort number you saved previously from the
launchSettings.json file.
In the previous code, the returned string will be processed to replace carriage return line
feeds with <br> HTML tags. You may occasionally run into situations where a return
value that works perfectly fine for .NET in the VSTO Add-in will need to be adjusted on
the Office Add-in side to work as expected. In this case, the REST API and shared class
library are only concerned with returning the string. The showUnicode() function is
responsible for formatting return values correctly for presentation.
2. From the View menu, choose Properties Window, if the window isn't already
displayed.
3. In the properties window, copy the value of the SSL URL, and save it somewhere.
This is the URL that you need to allow through CORS.
5. Add the following code to the top of the ConfigureServices method. Be sure to
substitute the URL SSL you copied previously for the builder.WithOrigins call.
C#
services.AddCors(options =>
{
options.AddPolicy(MyAllowSpecificOrigins,
builder =>
{
builder.WithOrigins("<your URL SSL>")
.AllowAnyMethod()
.AllowAnyHeader();
});
});
7 Note
Leave the trailing / from the end of the URL when you use it in the
builder.WithOrigins method. For example, it should appear similar to
C#
7. Add the following code to the configure method just before the line of code for
app.UseEndpoints .
C#
app.UseCors(MyAllowSpecificOrigins);
When done, your Startup class should look similar to the following code (your localhost
URL may be different).
C#
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseCors(MyAllowSpecificOrigins);
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
3. Set the Action property to Start for each of the following projects.
CellAnalyzerRESTAPI
CellAnalyzerOfficeAddin
CellAnalyzerOfficeAddinWeb
4. Choose OK.
Excel will run and sideload the Office Add-in. You can test that the localhost REST API
service is working correctly by entering a text value into a cell, and choosing the Show
Unicode button in the Office Add-in. It should call the REST API and display the unicode
values for the text characters.
Publish to an Azure App Service
You eventually want to publish the REST API project to the cloud. In the following steps
you'll see how to publish the CellAnalyzerRESTAPI project to a Microsoft Azure App
Service. See Prerequisites for information on how to get an Azure account.
You can now test the service. Open a browser and enter a URL that goes directly to the
new service. For example, use
https://<myappservice>.azurewebsites.net/api/analyzeunicode?value=test , where
myappservice is the unique name you created for the new App Service.
2. Change the url constant to use the URL for your Azure App Service as shown in
the following line of code. Replace <myappservice> with the unique name you
created for the new App Service.
JavaScript
const url =
"https://<myappservice>.azurewebsites.net/api/analyzeunicode?value=" +
range.values[0][0];
3. In Solution Explorer, right-click the top node Solution 'Cell-Analyzer', and choose
Set Startup Projects.
4. In the Solution 'Cell-Analyzer' Property Pages dialog, select Multiple startup
projects.
CellAnalyzerOfficeAddinWeb
CellAnalyzerOfficeAddin
6. Choose OK.
Excel will run and sideload the Office Add-in. To test that the App Service is working
correctly, enter a text value into a cell, and choose Show Unicode in the Office Add-in. It
should call the service and display the unicode values for the text characters.
Conclusion
In this tutorial, you learned how to create an Office Add-in that uses shared code with
the original VSTO add-in. You learned how to maintain both VSTO code for Office on
Windows, and an Office Add-in for Office on other platforms. You refactored VSTO C#
code into a shared library and deployed it to an Azure App Service. You created an
Office Add-in that uses the shared library, so that you don't have to rewrite the code in
JavaScript.
Make your Office Add-in compatible
with an existing COM add-in
Article • 02/07/2023
If you have an existing COM add-in, you can build equivalent functionality in your Office
Add-in, thereby enabling your solution to run on other platforms such as Office on the
web or Mac. In some cases, your Office Add-in may not be able to provide all of the
functionality that's available in the corresponding COM add-in. In these situations, your
COM add-in may provide a better user experience on Windows than the corresponding
Office Add-in can provide.
) Important
COM and VSTO add-ins aren't supported in the new Outlook on Windows that's
currently in preview. These add-ins are still supported in the classic Outlook on
Windows desktop client. To learn more, see Develop Outlook add-ins for new
Outlook on Windows (preview).
You can configure your Office Add-in so that when the equivalent COM add-in is already
installed on a user's computer, Office on Windows runs the COM add-in instead of the
Office Add-in. The COM add-in is called "equivalent" because Office will seamlessly
transition between the COM add-in and the Office Add-in according to which one is
installed on a user's computer.
) Important
Manifest
) Important
To enable compatibility between your Office Add-in and COM add-in, identify the
equivalent COM add-in in the manifest of your Office Add-in. Then, Office on Windows
will use the COM add-in instead of the Office Add-in, if they're both installed.
The following example shows the portion of the manifest that specifies a COM add-in as
an equivalent add-in. The value of the ProgId element identifies the COM add-in and
the EquivalentAddins element must be positioned immediately before the closing
VersionOverrides tag.
XML
<VersionOverrides>
...
<EquivalentAddins>
<EquivalentAddin>
<ProgId>ContosoCOMAddin</ProgId>
<Type>COM</Type>
</EquivalentAddin>
</EquivalentAddins>
</VersionOverrides>
Tip
For information about COM add-in and XLL UDF compatibility, see Make your
custom functions compatible with XLL user-defined functions. Not applicable for
Outlook.
Group policy
) Important
1. Download the latest Administrative Templates tool , paying attention to the tool's
Install Instructions.
4. Select the setting Deactivate Outlook web add-ins whose equivalent COM or
VSTO add-in is installed.
7 Note
The following scenarios describe what happens depending on how the user acquires the
Office Add-in.
After you specify an equivalent COM add-in for your Office Add-in, Office stops
processing updates for your Office Add-in. To acquire the latest updates for the Office
Add-in, the user must first uninstall the COM add-in.
Outlook
The COM/VSTO add-in must be connected when Outlook is started in order for the
corresponding web add-in to be disabled.
If the COM/VSTO add-in is then disconnected during a subsequent Outlook session, the
web add-in will likely remain disabled until Outlook is restarted.
See also
Make your Custom Functions compatible with XLL User Defined Functions