# Best Practices for Adding Ribbon Tabs, Groups and Buttons to the TXTextControl.Web Ribbon Bar

> The Web.TextControl ribbon bar uses pure HTML and CSS, so developers can extend it without modifying control source code. Custom tabs, groups, and buttons are loaded as HTML fragments via jQuery in the ribbonTabsLoaded event and inserted into the existing ribbon DOM structure.

- **Author:** Bjoern Meyer
- **Published:** 2017-12-21
- **Modified:** 2026-03-05
- **Description:** The Web.TextControl ribbon bar uses pure HTML and CSS, so developers can extend it without modifying control source code. Custom tabs, groups, and buttons are loaded as HTML fragments via jQuery in the ribbonTabsLoaded event and inserted into the existing ribbon DOM structure.
- **3 min read** (554 words)
- **Tags:**
  - ASP.NET
  - HTML5
  - JavaScript
  - Ribbon
- **Web URL:** https://www.textcontrol.com/blog/2017/12/21/best-practices-for-adding-ribbon-content-to-txtextcontrol-web/
- **LLMs URL:** https://www.textcontrol.com/blog/2017/12/21/best-practices-for-adding-ribbon-content-to-txtextcontrol-web/llms.txt
- **LLMs-Full URL:** https://www.textcontrol.com/blog/2017/12/21/best-practices-for-adding-ribbon-content-to-txtextcontrol-web/llms-full.txt
- **GitHub Repository:** https://github.com/TextControl/TextControl.Web.MVC.NewRibbonTab

---

TX Text Control .NET for ASP.NET is shipped with a fully-featured Ribbon control and ready-to-use Ribbon tabs for all typical tasks of TX Text Control. That allows a rapid application building within seconds without writing a single line of code.

The ribbon bar is completely built in pure HTML and CSS and can be therefore easily manipulated. Elements can be added, removed and rearranged.

This article explains the easiest way of adding new content to the existing ribbon bar by loading pre-designed HTML using jQuery into the ribbon DOM.

First of all, create a new folder in your project that contains the HTML and resources for your custom ribbon content. In this sample, the folder is named *RibbonExtensions*:

![Creating folders in Solution Explorer](https://s1-www.textcontrol.com/assets/dist/blog/2017/12/21/a/assets/solution_explorer.webp "Creating folders in Solution Explorer")

For each new ribbon tab, a new folder has been created. This whole folder and file structure is just a sample and can be structured based on your actual requirements and preferences.

The HTML of a new ribbon tab container looks like this:

```
<li>
    <a id="tabNew" 
       tabindex="-1" 
       rel="ribbonTabNew" 
       data-applicationmodes="0" 
       class="" 
       data-text="New">
        New
    </a>
</li>
```

The HTML representation of new ribbon tab content is shown in the following GitHub gist:

```
<div class="tab-content" id="ribbonTabNew" style="display: none;">
    <!-- Clipboard group -->
    <div class="ribbon-group" id="ribbonGroupClipboard">
        <div class="ribbon-group-content">

            <div id="newTabButtonContainer"
                 style="display: inline-block; float: left; margin-right: 5px">
               
                <div onclick="alert('Clicked! JavaScript is part of loaded Html in this case.');"
                     class="ribbon-button ribbon-button-big"
                     id="btnNewButton">

                    <div class="ribbon-button-big-image-container">
                        <img src="/RibbonExtensions/Images/icon_large_test.png"
                             class="ribbon-button-big-image">
                    </div>
                    <div class="ribbon-button-big-label-container">
                        <p class="ribbon-button-label">New<br>Button</p>
                    </div>
                </div>

            </div>

        </div>
    </div>
</div>
```

The following JavaScript code is loading the HTML dynamically after the ribbon has been loaded completely. In the *ribbonTabsLoaded* event of TX Text Control, jQuery is used to get the HTML in order to add it after the last existing tab.

After that, the tab content is loaded and dynamically added to the last content container item.

```
// ribbon can be manipulated when complete ribbon has been loaded
TXTextControl.addEventListener("ribbonTabsLoaded", function (e) {

    // get the new tab container and add it after the existing last tab
    $.get("/RibbonExtensions/NewTab/NewTab.html", function (data) {

        $("ul.tabs:first li:last").after(data);

        // attach the click event to switch tabs on a click
        $("#tabNew").click(function () {
            switchTabs($(this));
        });

    });

    // get the ribbon tab content and add it to the content container
    $.get("/RibbonExtensions/NewTab/NewTabContent.html", function (data) {

        $("#txRibbonTabContentContainer div:last").after(data);

    });

});

// enables the clicked tab and disables other tabs
function switchTabs(tabObject) {
    $('#txRibbonTabContentContainer div.tab-content').css("display", "none");
    $('#ribbonbar ul.tabs a').removeClass("selected");
    var id = tabObject.attr("rel");

    $('#' + id).css("display", "inline-block");
    tabObject.addClass("selected");
}
```

Additionally, a *click* event is attached to the ribbon tab menu item to switch the tabs programmatically when a user clicks on the menu item title. The function *switchTabs* hides the current content in order to display our new content.

![New ribbon tab](https://s1-www.textcontrol.com/assets/dist/blog/2017/12/21/a/assets/new-ribbon-tab.webp "New ribbon tab")

In the next step, a new ribbon group with a button should be added to the *Reporting* ribbon tab after the *Merge Fields* group. The following HTML is the group representation including the custom button:

```
<div class="ribbon-group" id="ribbonGroupNewGroup" data-applicationmodes="0">
    <div class="ribbon-group-content">

        <div id="newTabButtonContainer"
             style="display: inline-block; float: left; margin-right: 5px">

            <div onclick="alert('Clicked! JavaScript is part of loaded Html in this case.');"
                 class="ribbon-button ribbon-button-big"
                 id="btnNewButton">

                <div class="ribbon-button-big-image-container">
                    <img src="/RibbonExtensions/Images/icon_large_test.png"
                         class="ribbon-button-big-image">
                </div>
                <div class="ribbon-button-big-label-container">
                    <p class="ribbon-button-label">New<br>Button</p>
                </div>
            </div>

        </div>

    </div>
    <!-- Ribbon group label -->
    <div class="ribbon-group-label-container">
        <p class="ribbon-group-label">New Group</p>
    </div>
</div>
```

In the *ribbonTabsLoaded* event, this HTML gets loaded and added after the existing ribbon group:

```
TXTextControl.addEventListener("ribbonTabsLoaded", function (e) {

    // get the ribbon tab content and add it after the Merge Fields group in
    // the reporting tab
    $.get("/RibbonExtensions/ReportingTab/NewGroup.html", function (data) {

        $("#ribbonGroupMergeField").after(data);

    });

});
```

![New ribbon group](https://s1-www.textcontrol.com/assets/dist/blog/2017/12/21/a/assets/new-ribbon-group.webp "New ribbon group")

Test this on your own by downloading this sample project from our GitHub repository.

---

## About Bjoern Meyer

As CEO, Bjoern is the visionary behind our strategic direction and business development, bridging the gap between our customers and engineering teams. His deep passion for coding and web technologies drives the creation of innovative products. If you're at a tech conference, be sure to stop by our booth - you'll most likely meet Bjoern in person. With an advanced graduate degree (Dipl. Inf.) in Computer Science, specializing in AI, from the University of Bremen, Bjoern brings significant expertise to his role. In his spare time, Bjoern enjoys running, paragliding, mountain biking, and playing the piano.

- [LinkedIn](https://www.linkedin.com/in/bjoernmeyer/)
- [X](https://x.com/txbjoern)
- [GitHub](https://github.com/bjoerntx)

---

## Related Posts

- [Detect Toggle Button Changes Using a MutationObserver](https://www.textcontrol.com/blog/2021/11/11/detect-toggle-button-changes-using-a-mutationobserver/llms.txt)
- [Build a Custom Backstage View in ASP.NET Core with TX Text Control](https://www.textcontrol.com/blog/2026/02/17/build-a-custom-backstage-view-in-aspnet-core-with-tx-text-control/llms.txt)
- [5 Document Workflows You Can Automate With JavaScript Rich Text Editor](https://www.textcontrol.com/blog/2026/01/14/five-document-workflows-you-can-automate-with-javascript-rich-text-editor/llms.txt)
- [Add JavaScript to PDFs with TX Text Control in C# .NET: Time-Based Alerts Made Easy](https://www.textcontrol.com/blog/2025/06/13/add-javascript-to-pdfs-with-tx-text-control-in-c-dot-net-time-based-alerts-made-easy/llms.txt)
- [Using the Document Editor in SPA Applications using the removeFromDom Method](https://www.textcontrol.com/blog/2024/09/02/using-the-document-editor-in-spa-applications-using-the-removefromdom-method/llms.txt)
- [Observe When the Reporting Preview Tab is Active Using MutationObserver](https://www.textcontrol.com/blog/2024/07/23/observe-when-the-reporting-preview-tab-is-active-using-mutationobserver/llms.txt)
- [Removing Empty Pages in TX Text Control with JavaScript](https://www.textcontrol.com/blog/2024/06/19/removing-empty-pages-in-tx-textcontrol-with-javascript/llms.txt)
- [Document Editor: Useful JavaScript Functions for Tables](https://www.textcontrol.com/blog/2024/06/19/document-editor-useful-javascript-functions-for-tables/llms.txt)
- [Extract Data from PDF Documents with C#](https://www.textcontrol.com/blog/2024/06/10/extract-data-from-pdf-documents-with-csharp/llms.txt)
- [Inject JavaScript to PDF Documents in C#](https://www.textcontrol.com/blog/2024/06/07/inject-javascript-to-pdf-documents-in-csharp/llms.txt)
- [Loading Documents from Azure Blob Storage into the TX Text Control Document Editor using pure JavaScript](https://www.textcontrol.com/blog/2024/04/08/loading-documents-from-azure-blob-storage-into-tx-text-control-document-editor-using-pure-javascript/llms.txt)
- [Building an ASP.NET Core Backend Application to Host the Document Editor and Document Viewer](https://www.textcontrol.com/blog/2024/03/14/building-an-asp-net-core-backend-application-to-host-the-document-editor-and-document-viewer/llms.txt)
- [Manipulating the Context Menu in the Document Editor using JavaScript](https://www.textcontrol.com/blog/2023/12/22/manipulating-the-context-menu-in-the-document-editor-using-javascript/llms.txt)
- [Document Editor: How to Customize the Reconnecting Alert Message](https://www.textcontrol.com/blog/2023/12/18/document-editor-how-to-customize-the-reconnecting-alert-message/llms.txt)
- [Document Editor: Initialization Events](https://www.textcontrol.com/blog/2023/10/23/document-editor-initialization-events/llms.txt)
- [Reuse Document Editor Instances by Dynamically Moving them in the DOM](https://www.textcontrol.com/blog/2023/10/02/reuse-document-editor-instances-by-dynamically-moving-them-in-the-dom/llms.txt)
- [Reuse Angular Document Editor Instances in Bootstrap Tabs](https://www.textcontrol.com/blog/2023/05/22/reuse-angular-document-editor-instances-in-bootstrap-tabs/llms.txt)
- [Updating SubTextParts using JavaScript Promises](https://www.textcontrol.com/blog/2022/12/23/updating-subtextparts-using-javascript-promises/llms.txt)
- [MailMerge: Working with Image Placeholders](https://www.textcontrol.com/blog/2022/12/22/mailmerge-working-with-image-placeholders/llms.txt)
- [Sneak Peek 31.0: Customizing the Context Menu of the ASP.NET Document Editor](https://www.textcontrol.com/blog/2022/08/25/sneak-peek-310-customizing-the-context-menu-of-the-aspnet-document-editor/llms.txt)
- [Text Control Error Navigator Launched](https://www.textcontrol.com/blog/2022/08/15/text-control-error-navigator-launched/llms.txt)
- [Restoring the Merge Field Default Behavior](https://www.textcontrol.com/blog/2022/08/15/restoring-the-merge-field-default-behavior/llms.txt)
- [JavaScript: Avoid Flickering and Visual Updates by Grouping Undo Steps](https://www.textcontrol.com/blog/2022/07/25/javascript-avoid-flickering-and-visual-updates-by-grouping-undo-steps/llms.txt)
- [DS Server or TX Text Control? Different Deployment Scenarios](https://www.textcontrol.com/blog/2022/05/03/ds-server-or-tx-text-control-different-deployment-scenarios/llms.txt)
- [Document Editor: JavaScript Object Availability and Order of Events](https://www.textcontrol.com/blog/2022/05/03/documenteditor-javascript-object-availability-and-order-of-events/llms.txt)
