diff --git a/README.md b/README.md
index 86aa387d..199c912e 100644
--- a/README.md
+++ b/README.md
@@ -103,6 +103,7 @@ Check out these samples if you want to take advantage of the [shared runtime](ht
| [Use a shared library to migrate your Visual Studio Tools for Office add-in to an Office web add-in](Samples/VSTO-shared-code-migration) | Provides a strategy for code reuse when migrating from VSTO Add-ins to Office Add-ins. |
| [Integrate an Azure function with your Excel custom function](Excel-custom-functions/AzureFunction) | Learn how to integrate Azure functions with custom functions to move to the cloud or integrate additional services. |
| [Dynamic DPI code samples](Samples/dynamic-dpi) | A collection of samples for handling DPI changes in COM, VSTO, and Office Add-ins. |
+| [Rubric grader task pane add-in for OneNote on the web](Samples/onenote-add-in-rubric-grader/) | Explore the basics of OneNote add-ins with a sample tool for teachers. |
## Learn more
diff --git a/Samples/onenote-add-in-rubric-grader/.gitignore b/Samples/onenote-add-in-rubric-grader/.gitignore
new file mode 100644
index 00000000..a3225d43
--- /dev/null
+++ b/Samples/onenote-add-in-rubric-grader/.gitignore
@@ -0,0 +1,6 @@
+bower_components/
+node_modules/
+.vscode/
+npm-debug.log
+localhost.crt
+localhost.key
\ No newline at end of file
diff --git a/Samples/onenote-add-in-rubric-grader/LICENSE b/Samples/onenote-add-in-rubric-grader/LICENSE
new file mode 100644
index 00000000..5b7689b1
--- /dev/null
+++ b/Samples/onenote-add-in-rubric-grader/LICENSE
@@ -0,0 +1,24 @@
+The MIT License (MIT)
+
+Copyright (c) Microsoft Corporation
+All rights reserved.
+
+MIT License:
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/Samples/onenote-add-in-rubric-grader/README.md b/Samples/onenote-add-in-rubric-grader/README.md
new file mode 100644
index 00000000..c71979f2
--- /dev/null
+++ b/Samples/onenote-add-in-rubric-grader/README.md
@@ -0,0 +1,120 @@
+---
+title: "Rubric grader task pane add-in for OneNote on the web"
+page_type: sample
+urlFragment: onenote-add-in-rubric-grader
+products:
+ - m365
+ - office
+ - office-onenote
+languages:
+- javascript
+extensions:
+ contentType: samples
+ technologies:
+ - Add-ins
+ createdDate: 6/17/2025 4:00:00 PM
+description: Explore the basics of OneNote add-ins with a sample tool for teachers.
+---
+
+# Rubric grader task pane add-in for OneNote on the web
+
+## Summary
+
+The Rubric Grader sample shows you how to use the OneNote JavaScript API in a OneNote task pane add-in. The add-in gets page content, adds an outline to the page, and opens a different page.
+
+The add-in helps teachers grade writing assignments based on a grading rubric.
+
+
+
+## Features
+
+- Interact with OneNote through a custom task pane
+
+## Applies to
+
+- OneNote on the web
+
+## Prerequisites
+
+- A Microsoft 365 tenant
+
+## Solution
+
+| Solution | Author(s) |
+|---------|----------|
+| Rubric grader task pane add-in for OneNote on the web | Microsoft |
+
+## Version history
+
+| Version | Date | Comments |
+|---------|------|---------|
+| 1.0 | 6-17-2025 | Initial release |
+
+## Run the sample
+
+You can run this sample in Onenote in a browser. The add-in web files are served from this repo on GitHub.
+
+1. Download the **manifest.xml** file from this sample to a folder on your computer.
+1. Open [Office on the web](https://office.live.com/).
+1. Under **Apps**, choose **OneNote**.
+1. Open a notebook that contains a couple of pages. Make sure at least one page has a paragraph of content.
+1. Open the **Insert** tab on the ribbon and choose **Office Add-ins**.
+1. On the **Office Add-ins** dialog, select the **MY ADD-INS** tab, choose **Upload My Add-in**.
+1. Browse to the add-in manifest file, and then select **Upload**.
+1. Verify that the add-in loaded successfully. You will see a **Show Taskpane** button on the **Home** tab on the ribbon.
+
+Once the add-in is loaded use the following steps to try out the functionality.
+
+## Run the sample from localhost
+
+If you prefer to configure a web server and host the add-in's web files from your computer, use the following steps.
+
+1. Install a recent version of [npm](https://www.npmjs.com/get-npm) and [Node.js](https://nodejs.org/) on your computer. To verify if you've already installed these tools, run the commands `node -v` and `npm -v` in your terminal.
+
+1. You need http-server to run the local web server. If you haven't installed this yet, you can do this with the following command.
+
+ ```console
+ npm install --global http-server
+ ```
+
+1. You need Office-Addin-dev-certs to generate self-signed certificates to run the local web server. If you haven't installed this yet, you can do this with the following command.
+
+ ```console
+ npm install --global office-addin-dev-certs
+ ```
+
+1. Clone or download this sample to a folder on your computer, then go to that folder in a console or terminal window.
+
+1. Run the following command to generate a self-signed certificate to use for the web server.
+
+ ```console
+ npx office-addin-dev-certs install
+ ```
+
+ This command will display the folder location where it generated the certificate files.
+
+1. Go to the folder location where the certificate files were generated, then copy the **localhost.crt** and **localhost.key** files to the cloned or downloaded sample folder.
+
+1. Run the following command.
+
+ ```console
+ http-server -S -C localhost.crt -K localhost.key --cors . -p 3000
+ ```
+
+ The http-server will run and host the current folder's files on localhost:3000.
+
+1. Now that your localhost web server is running, you can sideload the **manifest-localhost.xml** file provided in the sample folder. Using this file, follow the steps in [Run the sample](#run-the-sample) to sideload and run the add-in.
+
+## Questions and feedback
+
+- Did you experience any problems with the sample? [Create an issue](https://github.com/OfficeDev/Office-Add-in-samples/issues/new/choose) and we'll help you out.
+- We'd love to get your feedback about this sample. Go to our [Office samples survey](https://aka.ms/OfficeSamplesSurvey) to give feedback and suggest improvements.
+- For general questions about developing Office Add-ins, go to [Microsoft Q&A](https://learn.microsoft.com/answers/topics/office-js-dev.html) using the office-js-dev tag.
+
+## Copyright
+
+Copyright (c) 2025 Microsoft Corporation. All rights reserved.
+
+This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information, see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
+
+
diff --git a/Samples/onenote-add-in-rubric-grader/app/app.css b/Samples/onenote-add-in-rubric-grader/app/app.css
new file mode 100644
index 00000000..48d32467
--- /dev/null
+++ b/Samples/onenote-add-in-rubric-grader/app/app.css
@@ -0,0 +1,41 @@
+/* Common app styling */
+
+.padding-header {
+ padding: 30px 30px 20px 20px;
+}
+
+.padding-body {
+ padding: 5px 20px;
+}
+
+.padding-top {
+ padding: 25px 0px 0px 0px;
+}
+
+#notification-message {
+ background-color: #818285;
+ color: #fff;
+ position: absolute;
+ width: 100%;
+ min-height: 80px;
+ right: 0;
+ z-index: 100;
+ bottom: 0;
+ display: none; /* Hidden until invoked */
+}
+
+ #notification-message #notification-message-header {
+ font-size: medium;
+ margin-bottom: 10px;
+ }
+
+ #notification-message #notification-message-close {
+ background-image: url("../Images/Close.png");
+ background-repeat: no-repeat;
+ width: 24px;
+ height: 24px;
+ position: absolute;
+ right: 5px;
+ top: 5px;
+ cursor: pointer;
+ }
diff --git a/Samples/onenote-add-in-rubric-grader/app/app.js b/Samples/onenote-add-in-rubric-grader/app/app.js
new file mode 100644
index 00000000..f860558b
--- /dev/null
+++ b/Samples/onenote-add-in-rubric-grader/app/app.js
@@ -0,0 +1,30 @@
+const app = (function(){ // jshint ignore:line
+ 'use strict';
+
+ let self = {};
+
+ // Common initialization function (to be called from each page)
+ self.initialize = function(){
+ jQuery('body').append(
+ '
' +
+ '
' +
+ '' +
+ '' +
+ '' +
+ '
' +
+ '
');
+
+ jQuery('#notification-message-close').click(function(){
+ jQuery('#notification-message').hide();
+ });
+
+ // After initialization, expose a common notification function
+ self.showNotification = function(header, text){
+ jQuery('#notification-message-header').text(header);
+ jQuery('#notification-message-body').text(text);
+ jQuery('#notification-message').slideDown('fast');
+ };
+ };
+
+ return self;
+})();
diff --git a/Samples/onenote-add-in-rubric-grader/app/home/grader.fabricdropdownhelper.js b/Samples/onenote-add-in-rubric-grader/app/home/grader.fabricdropdownhelper.js
new file mode 100644
index 00000000..157fc616
--- /dev/null
+++ b/Samples/onenote-add-in-rubric-grader/app/home/grader.fabricdropdownhelper.js
@@ -0,0 +1,146 @@
+/*
+* Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
+* See LICENSE in the project root for license information.
+*/
+
+// Helper based on Office UI Fabric dropdown, which hides the original 'select' dropdown and
+// creates a "fake" dropdown that can be more easily styled across browsers.
+// http://dev.office.com/fabric/components/dropdown
+function useFabricDropdown (id) {
+ var $dropdownWrapper = $('#' + id),
+ $originalDropdown = $dropdownWrapper.children('.ms-Dropdown-select'),
+ $originalDropdownOptions = $originalDropdown.children('option'),
+ newDropdownTitle = '',
+ newDropdownItems = '',
+ newDropdownSource = '';
+
+ /** Go through the options to fill up newDropdownTitle and newDropdownItems. */
+ $originalDropdownOptions.each(function (index, option) {
+
+ /** If the option is selected, it should be the new dropdown's title. */
+ if (option.selected) {
+ newDropdownTitle = option.text;
+ }
+
+ /** Add this option to the list of items. */
+ newDropdownItems += '
';
+ $dropdownWrapper.append(newDropdownSource);
+
+ function _openDropdown(evt) {
+ if (!$dropdownWrapper.hasClass('is-disabled')) {
+
+ /** First, let's close any open dropdowns on this page. */
+ $dropdownWrapper.find('.is-open').removeClass('is-open');
+
+ /** Stop the click event from propagating, which would just close the dropdown immediately. */
+ evt.stopPropagation();
+
+ /** Before opening, size the items list to match the dropdown. */
+ var dropdownWidth = $(this).parents(".ms-Dropdown").width();
+ $(this).next(".ms-Dropdown-items").css('width', dropdownWidth + 'px');
+
+ /** Go ahead and open that dropdown. */
+ $dropdownWrapper.toggleClass('is-open');
+ $('.ms-Dropdown').each(function(){
+ if ($(this)[0] !== $dropdownWrapper[0]) {
+ $(this).removeClass('is-open');
+ }
+ });
+
+ /** Temporarily bind an event to the document that will close this dropdown when clicking anywhere. */
+ $(document).bind("click.dropdown", function() {
+ $dropdownWrapper.removeClass('is-open');
+ $(document).unbind('click.dropdown');
+ });
+ }
+ }
+
+ /** Toggle open/closed state of the dropdown when clicking its title. */
+ $dropdownWrapper.on('click', '.ms-Dropdown-title', function(event) {
+ _openDropdown(event);
+ });
+
+ /** Keyboard accessibility */
+ $dropdownWrapper.on('keyup', function(event) {
+ var keyCode = event.keyCode || event.which;
+ // Open dropdown on enter or arrow up or arrow down and focus on first option
+ if (!$(this).hasClass('is-open')) {
+ if (keyCode === 13 || keyCode === 38 || keyCode === 40) {
+ _openDropdown(event);
+ if (!$(this).find('.ms-Dropdown-item').hasClass('is-selected')) {
+ $(this).find('.ms-Dropdown-item:first').addClass('is-selected');
+ }
+ }
+ }
+ else if ($(this).hasClass('is-open')) {
+ // Up arrow focuses previous option
+ if (keyCode === 38) {
+ if ($(this).find('.ms-Dropdown-item.is-selected').prev().siblings().size() > 0) {
+ $(this).find('.ms-Dropdown-item.is-selected').removeClass('is-selected').prev().addClass('is-selected');
+ }
+ }
+ // Down arrow focuses next option
+ if (keyCode === 40) {
+ if ($(this).find('.ms-Dropdown-item.is-selected').next().siblings().size() > 0) {
+ $(this).find('.ms-Dropdown-item.is-selected').removeClass('is-selected').next().addClass('is-selected');
+ }
+ }
+ // Enter to select item
+ if (keyCode === 13) {
+ if (!$dropdownWrapper.hasClass('is-disabled')) {
+
+ // Item text
+ var selectedItemText = $(this).find('.ms-Dropdown-item.is-selected').text();
+
+ $(this).find('.ms-Dropdown-title').html(selectedItemText);
+
+ /** Update the original dropdown. */
+ $originalDropdown.find("option").each(function(key, value) {
+ if (value.text === selectedItemText) {
+ $(this).prop('selected', true);
+ } else {
+ $(this).prop('selected', false);
+ }
+ });
+ $originalDropdown.change();
+
+ $(this).removeClass('is-open');
+ }
+ }
+ }
+
+ // Close dropdown on esc
+ if (keyCode === 27) {
+ $(this).removeClass('is-open');
+ }
+ });
+
+ /** Select an option from the dropdown. */
+ $dropdownWrapper.on('click', '.ms-Dropdown-item', function () {
+ if (!$dropdownWrapper.hasClass('is-disabled')) {
+
+ /** Deselect all items and select this one. */
+ $(this).siblings('.ms-Dropdown-item').removeClass('is-selected');
+ $(this).addClass('is-selected');
+
+ /** Update the replacement dropdown's title. */
+ $(this).parents().siblings('.ms-Dropdown-title').html($(this).text());
+
+ /** Update the original dropdown. */
+ var selectedItemText = $(this).text();
+ $originalDropdown.find("option").each(function(key, value) {
+ if (value.text === selectedItemText) {
+ $(this).prop('selected', true);
+ } else {
+ $(this).prop('selected', false);
+ }
+ });
+ $originalDropdown.change();
+ }
+ });
+}
\ No newline at end of file
diff --git a/Samples/onenote-add-in-rubric-grader/app/home/grader.html b/Samples/onenote-add-in-rubric-grader/app/home/grader.html
new file mode 100644
index 00000000..6f838f5a
--- /dev/null
+++ b/Samples/onenote-add-in-rubric-grader/app/home/grader.html
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+ Rubric Grader
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Rubric Grader
+
+
+
+
+
+
+
+
+
+ Words:
+
+ Sentences:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Samples/onenote-add-in-rubric-grader/app/home/grader.js b/Samples/onenote-add-in-rubric-grader/app/home/grader.js
new file mode 100644
index 00000000..d407c31f
--- /dev/null
+++ b/Samples/onenote-add-in-rubric-grader/app/home/grader.js
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
+ * See LICENSE in the source repository root for complete license information.
+ */
+
+(function () {
+ "use strict";
+
+ // Define the configurable grading criteria and score values.
+ const criteria = ['Content', 'Organization', 'Style', 'Grammar'];
+ const score = [0,1,2,3,4,5,6,7,8,9,10];
+ const defaultValue = 5;
+
+ // The initialize function is run each time the page is loaded.
+ Office.initialize = function (reason) {
+ $(document).ready(function () {
+ app.initialize();
+
+ populateScoringDropDowns();
+ populatePagePickerDropDown();
+
+ // Set up event handlers for the UI.
+ $('#getStats').click(getStats);
+ $('#addGrade').click(createGrade);
+ $('#clear').click(clearGrade);
+ $('#openPage').click(openPage);
+ });
+ };
+
+ // Populates the page picker with pages from the current section.
+ function populatePagePickerDropDown() {
+ OneNote.run(function (context) {
+
+ // Get the ID and title of the pages in the current section.
+ const pages = context.application.getActiveSection().pages;
+
+ // Queue a command to load the id and title for each page.
+ pages.load('id,title');
+
+ // Run the queued commands, and return a promise to indicate task completion.
+ return context.sync()
+ .then(function () {
+
+ // Get the ID and title of each page, add them as picker options.
+ const dropdown = $('#page-picker');
+ $.each(pages.items, function(index, object) {
+ let pageId = object.id;
+ let pageTitle = object.title;
+
+ if (index === 0) {
+ dropdown.append($('