Best Healing Addons for WoW (Classic & Dragonflight) (2023)

");$( "#content-area" ).prepend($addFlag);} }// This function handles animation for the new ToC, which currently includes:// 1. Fading the ToC in and out to prevent it from covering up the Info section in the footer ; function handleTocAnim( $tocBox, winHeight, docHeight, scrollTop ) { // We're going to check if we're near the bottom for an animation to hide the ToC so we don't // cover up the Info section in the footer var bottomBuffer = 384; //px var isNearBottom = scrollTop + winHeight > docHeight - bottomBuffer; // Fetch the value for the animFlag key var tocAnimating = $ "animFlag" ); // If ToC has been hidden by the fade anim, display will be 'none' when // finished animating var tocHidden = $tocBox.css( 'display' ) === 'none'; if( isNearBottom ) { // If we're near the bottom, and the ToC is not animating // and not hidden, then hide it if( !tocAnimating && !tocHidden ) { $ "animFlag", true ) $tocBox.fadeOut( 400, function() { $ "animFlag", false ); }); } } else { // If we're not near the bottom, and the ToC is not animating // and hidden, then unhide it if( !tocAnimating && tocHidden ) { $ "animFlag", true ); $tocBox.fadeIn( 400, function() { $ "animFlag", false ); }); } } }// Calculate the available height for the ToC Box ; function calcAvailableHeight( height ) {return height * 80.0 / 100.0;}// This function resizes specific page elements, depending on // window size and whether the ToC is present, to keep things // consistent.// The boolean debug arg enables verbose logging. ; function handleReflow( $, winOuterWidth, winInnerHeight, maxMobileWidth, debug ) {if( debug ) {console.log( "Checking if page layout should be reflowed..." );}// We want to reflow the layout whether or not we have the TOC, // with the hasTOC bool as a flag for if it exists on the pagevar tocFlag = $("#content-side");var hasToC = true; // FORCE HAS TOC, DEPLOYING SITEWIDE -supersoup// Check number of H2 elements. If <= 3, early returnvar numH2 = $("h2");if( numH2.length <= 3 ) {return;}// Cache varsvar $mainContainer = $("#main-content");var $logoContainer = $(".hgg-logo-space");var $navContainer = $(".hgg-menu-icon");var $contentArea = $("#content-area");// Null-check variablesvar anyNull = $mainContainer.length && $logoContainer.length && $navContainer.length && $contentArea.length;if( !($mainContainer.length) && debug ) {console.log( "$mainContainer null in reflowLayout..." );}if( !($logoContainer.length) && debug ) {console.log( "$logoContainer null in reflowLayout..." );}if( !($navContainer.length) && debug ) {console.log( "$navContainer null in reflowLayout...")}if( !($contentArea.length) && debug ) {console.log( "$contentArea null in reflowLayout..." );} if( debug ) {console.log( "anyNull: " + anyNull );console.log( "hasTOC: " + hasToC );}if( hasToC ) {// The previous process for initializing offsetTopForView didn't play well when// refreshing the page while partially down the post, switching to pulling the // header height for consistency -supersoupvar offsetTopForView = $("header").height() ; //pxif (offsetTopForView === undefined || offsetTopForView < 0) {offsetTopForView = 0;}var $toc = $( ".toc-box" );if( $toc.length > 0 ) {var availableHeight = calcAvailableHeight( winInnerHeight - offsetTopForView );if( debug ) {console.log( "window.innerHeight: " + winInnerHeight );console.log( "availableHeight: " + availableHeight );console.log( "toc[0].scrollHeight: " + $toc[0].scrollHeight );console.log( "toc.height(): " + $toc.height() );}if( $toc.outerHeight() > availableHeight ) {$toc.css( 'height', availableHeight );if( debug ) {console.log( "Setting ToC height to ", availableHeight );}} else {var newHeight = availableHeight < $toc[0].scrollHeight ? availableHeight : $toc[0].scrollHeight;$toc.css( 'height', newHeight );if( debug ) {console.log( "Setting ToC height to ", newHeight );}}/*// Update largest sizevar maxSize = $ "maxSize" );var outerHeight = $toc.outerHeight;if( maxSize === 0 || maxSize == undefined || maxSize == NaN || maxSize < cssHeight ) {$ "maxSize", $toc.outerHeight);console.log( "maxSize is now " + $toc.outerHeight );}*/if( $toc.height() < $toc[0].scrollHeight ) {$toc.css( 'overflow-x', 'hidden' );$toc.css( 'overflow-y', 'auto' );}else {$toc.css( 'overflow-x', 'hidden' );$toc.css( 'overflow-y', 'none' );}}if( winOuterWidth >= 1600 ) {$mainContainer.css( "margin-left", "15.95rem" );$logoContainer.css( "margin-left", "-6.1rem" );$navContainer.css( "margin-right", "-8.0rem" );} else if( winOuterWidth < 1600 && winOuterWidth > maxMobileWidth ) {$mainContainer.css( "margin-left", "14.8rem" );$logoContainer.css( "margin-left", "-3.8rem" );$navContainer.css( "margin-right", "-3.8rem" );} else if( winOuterWidth <= maxMobileWidth ) {// Clear applied CSS$mainContainer.css( "margin-left", "0" );$logoContainer.css( "margin-left", "0" );$navContainer.css( "margin-right", "0" );} else {if( debug ) {console.log( "Unhandled window width in reflowLayout() - With ToC" );}}} else {if( winOuterWidth >= 1600 ) {// Don't do anything yet on non-ToC pages} else if( winOuterWidth < 1600 && winOuterWidth > maxMobileWidth ) {$contentArea.css( "margin-left", "0");} else if( winOuterWidth <= maxMobileWidth ) {// Don't do anything yet on non-ToC pages} else {if( debug ) {console.log( "Unhandled window width in reflowLayout() - Without ToC" );}}} }// Handles reflowing content on the page depending on different variables; (function (window, $, undefined) {$.fn.reflowLayout = function() {// Mobile width for reflow, probably want to sync// with max mobile width for the ToCconst MAX_MOBILE_WIDTH = 1438;// Should we enable verbose logging for debugging?// SHOULD NOT BE TRUE IN PRODUCTION! -supersoupvar debug = false;handleReflow( $, window.outerWidth, window.innerHeight, MAX_MOBILE_WIDTH, debug );$(window).on( 'load', function () {handleReflow( $, window.outerWidth, window.innerHeight, MAX_MOBILE_WIDTH, debug );});// For reflowing when browser size changes$(window).on( 'resize', function () {handleReflow( $, window.outerWidth, window.innerHeight, MAX_MOBILE_WIDTH, debug );});/*$(window).on( 'scroll', function () {var $toc = $( ".toc-box" );if( $toc.length === 0 )return;console.log( "availableHeight: " + calcAvailableHeight( window.innerHeight ) );console.log( "toc[0].scrollHeight: " + $toc[0].scrollHeight );console.log( "toc.outerHeight(): " + $toc.outerHeight() );});*/};})(this, jQuery);// Transform guide content by visually organizing it into cards ; (function(window, $, undefined) { $.fn.cardify = function() { var $contentBody = $("#content-body"); if($contentBody === 0) { return; } var $contentBodyChildren = $contentBody.children(); var $h2s = $contentBody.children("h2"); console.log("H2 children of #content-body: " + $h2s.length); if($h2s.length === 0) { return; } for(var i = 0; i < $h2s.length; i++) { var $array = $contentBodyChildren.nextUntil("h2"); $array.each( function(index) { console.log("Element " + index + ": " + $(this).html()); }); // console.log("Card " + i + ":" + $contentBodyChildren.nextUntil("h2").html()); } } }(this, jQuery));// Create the top level TOC before the first heading // The boolean debug arg enables verbose logging. ; function createTopLevelTOC( $, debug ) {var $contentBody = $("#content-body");if( $contentBody === 0 ) {return;}var headingsToFind = ["h2", "h3"]; var $headings = $contentBody.find(headingsToFind.join(","));if( debug ) {console.log(`Headings found: ${$headings.length}`);}if( $headings.length === 0 ) {return;}var tocContainer = document.createElement("div"); = "top_toc_container";tocContainer.classList.add("top_toc_container");var tocTitle = document.createElement("div"); // Changed from p to div for better layout controltocTitle.classList.add("top_toc_title");var tocTitleText = document.createElement("p"); // Create the p element for the title texttocTitleText.innerHTML = "Table of Contents";tocTitle.append(tocTitleText); // Append the title text to the tocTitle divvar plusIcon = document.createElement("span"); // You can use an img tag or i tag if you are using an icon libraryplusIcon.classList.add("plus_icon");plusIcon.innerHTML = "+"; // Replace with your icon// Append the icon to the titletocTitle.append(plusIcon);tocContainer.append(tocTitle);var tocList = document.createElement("ul");tocList.classList.add("top_toc_list"); = "none"; // Hide it by defaulttocContainer.append(tocList);document.body.append(tocContainer);tocTitle.addEventListener("click", function() { if ( === "none") { = "block"; // Show the list plusIcon.innerHTML = "-"; // Change the icon = "5px 5px 0px 0px"; // Change border radius when expanded } else { = "none"; // Hide the list plusIcon.innerHTML = "+"; // Change the icon = ""; // Reset border radius when not expanded }});let h2Count = 1;let h3Count = 1;for( let i = 0; i < $headings.length; i++ ) {var item = document.createElement("li");var itemTagName = $headings[i].tagName;var tagIsH3 = itemTagName === "H3";if ( debug ) {console.log(`Item ${i} tagName: ${itemTagName}`);}var count = i+1;if( tagIsH3 ) {item.classList.add("top_toc_item_h3");count = h3Count;h3Count++;}else {item.classList.add("top_toc_item_h2");count = h2Count;h3Count = 1; // Reset h3 counth2Count++;}var innerText = `${tagIsH3 ? " - " : ""} ${$headings[i].innerText}`;item.innerHTML =`${innerText}`;tocList.append(item);}tocContainer.append(tocList);var $topHeading = $headings[0];$topHeading.before(tocContainer);if( debug ) {console.log("Successfully added top level ToC");}}// The main function for creating, populating, and managing the new ToC ; (function (window, $, undefined) { $.fn.createTOC = function (settings) {const MAX_MOBILE_WIDTH = 1438;// Before anything else, if this is a post in a Category that we // specifically want to force the ToC on, let's handle that// THIS IS NO LONGER NEEDED, as we're pushing ToC sitewide -supersoup// handleForceToC( $ );// We want to create the inline top level ToC if we're not generating // the sidebar tocif ( $(window).width() <= MAX_MOBILE_WIDTH ) { if (!deactivate_mobile_toc) { createTopLevelTOC( $, false ); }}// For now, we only want to add the new ToC to manually flagged posts.// The post is flagged with the presence of a

// contained within the content of the post. Originally, this div was being used// to wrap the ToC, but I (supersoup) am going to move the ToC out to a new div.// So, the first thing we want to do is test for this div, early return if not // found, or remove it and recreate a #content-side div elsewhere if it is found.var tocFlag = $("#content-side");var hasToC = !(tocFlag.length === 0);// If #content-side element is foundif( hasToC ) {// Get rid of tosFlag #content-side elementtocFlag.remove();}// Check number of H2 and H3 elements. If <= 3, early returnvar numH2 = $("h2");var numH3 = $("h3");if( numH2.length + numH3.length <= 3 ) {return;}// Proceed with .CreateTOC() var option = $.extend({ title: "hgg-toc", insert: "body", }, settings); var ACTIVE_CLASS = 'active'; var list = ["h2", "h3"]; var $headings = this.find(list.join(",")); var tocBox = document.createElement("ul"); var $tocBox = $(tocBox); tocBox.className = "toc-box"; var idList = []; $ (i, head) { var nodeName = head.nodeName; var id = 'toc_' + i + '_' + nodeName; = id; idList.push(id); var row = document.createElement("li"); row.className = 'toc-item toc-' + nodeName; var link = document.createElement('a'); link.innerText = head.innerText; link.className = 'toc-item-link'; link.href = '#' + id; row.appendChild(link); tocBox.appendChild(row); }); // Control the takeover of the highlighted elements var isTakeOverByClick = false; // Event delegate, add click ,Highlight the currently clicked item $tocBox.on("click", ".toc-item", function (ev) { // Set as true ,Represents the click event to take over the control of the highlighted element isTakeOverByClick = true; var $item = $(this); var $itemSiblings = $item.siblings(); $itemSiblings.removeClass(ACTIVE_CLASS); $item.addClass(ACTIVE_CLASS); });// Recreate #content-side element in new locationvar $tocDiv = $("

");$( "#content-area" ).prepend($tocDiv); // Want it to be the first subdiv of #content-areavar headBox = document.createElement("div");headBox.className = "toc-titler";headBox.innerHTML = option.title;var wrapBox = document.createElement("div");wrapBox.className = "wrap-toc";wrapBox.appendChild(headBox);wrapBox.appendChild(tocBox);// If on mobile, set sidebar hiddenif( $(window).width() <= MAX_MOBILE_WIDTH ) { = 'none';} else { = null;}var $insertBox = $(option.insert);var $helperBox = $("

");$helperBox.append(wrapBox);$insertBox.prepend($helperBox);// The style of the storage container boxvar CACHE_WIDTH = $insertBox.css('width');var CACHE_PADDING_TOP = $insertBox.css('paddingTop');var CACHE_PADDING_RIGHT = $insertBox.css('paddingRight');var CACHE_PADDING_BOTTOM = $insertBox.css('paddingBottom');var CACHE_PADDING_LEFT = $insertBox.css('paddingLeft');var CACHE_MARGIN_TOP = $insertBox.css('marginTop'); // var scrollTop = $('html,body').scrollTop(); // var offsetTop = $insertBox.offset().top; // var marginTop = parseInt($insertBox.css('marginTop')); // var offsetTopForView = offsetTop - scrollTop - marginTop; // For initialization on load$(window).on( 'load', function () {initTocAnimData( $insertBox );}); // Rolling ceiling $(window).scroll(function () {// The previous process for initializing offsetTopForView didn't play well when// refreshing the page while partially down the post, switching to pulling the // main-header height for consistency -supersoupvar offsetTopForView = $(".hgg-top-nav").height() ; //px// IE6/7/8: // For pages without doctype declaration, document.body.scrollTop can be used to get the height of scrollTop; // For pages with doctype declaration, document.documentElement.scrollTop can be used;// Safari: // Safari is special, it has its own function to get scrollTop: window.pageYOffset;// Firefox: // Relatively standard browsers such as Firefox can save more worry, just use document.documentElement.scrollTop;var scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop; // Scroll highlight // Only when the click event cancels the control of the highlighted element, the scroll event can have the control of the highlighted element !isTakeOverByClick && $.each(idList, function (index, id) { var $head = $('#' + id); var $item = $('[href="#' + id + '"]').parent(); var $itemSiblings = $item.siblings();var offsetBuffer = 64; // px, we want the class swap to trigger slightly before so we show an accurate active element// when zooming to a specific element var offsetTopHead = $head.offset().top - offsetBuffer; var isActived = $item.hasClass(ACTIVE_CLASS); if (scrollTop >= offsetTopHead) { $itemSiblings.removeClass(ACTIVE_CLASS); !isActived && $item.addClass(ACTIVE_CLASS); } else { $item.removeClass(ACTIVE_CLASS); } }); // Set to false, which means that the click event will cancel the control of the highlighted element isTakeOverByClick = false;// Handle animation for the ToChandleTocAnim( $insertBox, $(window).height(), $(document).height(), scrollTop );// Handle any changes to ToC CSS on scrollvar isFixed = $helperBox.css("position") === "fixed"; if (scrollTop >= offsetTopForView) {if (isFixed) return;$tocBox.css({overflow: 'auto',padding: 0,});$helperBox.css({position: 'fixed',top: CACHE_MARGIN_TOP,width: CACHE_WIDTH,paddingTop: CACHE_PADDING_TOP,paddingRight: CACHE_PADDING_RIGHT,paddingBottom: CACHE_PADDING_BOTTOM,paddingLeft: CACHE_PADDING_LEFT,backgroundColor: $tocBox.css('backgroundColor')});} else {if (!isFixed) return;$helperBox.css({position: 'static',padding: 0});$tocBox.css({overflow: 'auto',paddingTop: CACHE_PADDING_TOP,paddingRight: CACHE_PADDING_RIGHT,paddingBottom: CACHE_PADDING_BOTTOM,paddingLeft: CACHE_PADDING_LEFT,});} }); };}(this, jQuery));});

Home  >  Guides  >  World of Warcraft

Last updated by Best Healing Addons for WoW (Classic & Dragonflight) (1) Sarah Arnold on Mar 17, 2023

Human Made

Best Healing Addons for WoW (Classic & Dragonflight) (2)

Healing is hard enough in WoW, use addons to make it easier! (Images: Blizzard via HGG/Sarah Arnold)

Healing in World of Warcraft is a very different animal than dealing damage. Healers spend most of their time watching friendly unit frames, trying to make the health bars go up rather than down. It’s a role that can be prone to tunnel vision, and healers are often the first to be blamed when something goes wrong. Thankfully, WoW players have made tons of addons to help healers with their healing!

Mouseover addons can help you cast your spells more quickly and efficiently, timer addons can help you see when spells come off of cooldown, and healing meters can help you gauge the effectiveness of your spells. We’ll go over each of these healing addon types and some of the best examples that are available. Every addon listed in this guide is available for both World of Warcraft: Dragonflight and WoW Classic.

Looking for more World of Warcraft tips and tricks? View all our World of Warcraft guides.

Mouseover Casting Addons

Healing is a lot more reactive than damage dealing, and one of the best things you can do to improve your healing is to improve your reaction time. Enter mouseover macros, which allow you to cast spells on unit frames without needing to target them first. That’s one click instead of two, which may not seem like a lot, but it can make a big difference in the heat of battle.

Mouseover macros can be set up using the default macro system in the game, but the system is rather clunky and basic, and you will need to type out a bunch of commands for every macro you want to make. Addons make it very easy to simulate macros with just a few clicks.


Download: CurseForge, Wago
Command: /vuhdo

VuhDo replaces the default unit frames with ones that are highly customizable, and adds easily configurable mouseover casting to them. It also comes with an optional buff tracker.

Unit frame options include appearance options like size and color. You can sort and separate groups in a lot of different ways, and use different setups based on group size. Perhaps most useful to healers is the ability to track both debuffs and buffs on your group, so you can see what needs to be dispelled and when you need to refresh a heal-over-time. You can pick and choose what is tracked and how it appears on the frames.

VuhDo’s mouse binding options are robust, allowing you to set up mouseover macros by simply typing in the name of the spell. Modifier keys, extra mouse buttons, and the mouse wheel can all be used. There are options to automatically cleanse, buff, or resurrect targets you click on when certain conditions are met. You can also set it to automatically use trinkets, glove enchants, or any instant spell, and these will be used on cooldown when you use your other mouse binds.

HealBot Continued

Download: CurseForge, Wago
Command: /hb

HealBot was the original mouseover healing addon for WoW, and to this day you may hear people refer to these addons as “HealBot addons.” Like VuhDo, it offers both customizable unit frames and the ability to bind spells to your mouse.

VuhDo and HealBot have both been around a long time and have almost the same features, just presented in different ways. It mostly comes down to personal preference and which options menu seems less intimidating to you.

Be sure to grab HealBot Continued, as the original HealBot addon is no longer supported.


Download: CurseForge, Wago
Command: /clique

Clique makes it easy to set up mouse binds for your spells. Unlike HealBot and VuhDo, it does not come with its own unit frames. That means you can use it with any unit frame addon you like, including ElvUI or Shadowed Unit Frames, or even just the default ones in the game.

Since mouse binds are all that Clique does, it does it especially well: you can set up a binding by opening your spellbook and clicking on a spell using the keybind you want to set. It also works with macros.

Timers & Indicators

Tracking your cooldowns is essential in any role, but in healing it can mean the difference between a good healer and a great one, and the difference between your group surviving an encounter or having to run back. Addons are immensely helpful for keeping track of what spells you can use and when.


Download: CurseForge, Wago
Profiles: Wago
Command: /wa

WeakAuras is an extremely powerful framework that can help you track all sorts of buffs, debuffs, cooldowns, resources, casts… almost anything you can think of. It can be intimidating to get started with, but luckily, there’s a dedicated website where users can share their WeakAuras, and importing them is fairly simple.

This addon is useful in just about any area of the game. For healers, it can help you see when important spells come off of cooldown, or when a boss is using a dangerous ability that you need to react to. You can even keep track of your tank’s cooldowns so you know when they might need some extra help from you.


Download: CurseForge, Wago
Command: /tmw

TellMeWhen does a lot of the same things as WeakAuras. It doesn’t have as many options for customization and advanced scripting, but that makes it less intimidating to get started with. It’s still a very robust framework with a lot of options.


Download: CurseForge
Command: /omnicc

OmniCC is a very simple addon that adds text to spell cooldowns and buff timers. Now you can see on your action bars exactly when each spell will be available again. This is especially helpful for healers as you perform triage on your group.

Healing Meters

Healing meters, or damage meters as they’re usually called, can be very useful in figuring out how your healing output compares to that of other healers. They can also help you test out different spell rotations and compare the results. Even more useful is some of the less obvious information they can provide: who is dying to what, who is taking damage from what, who is casting dispels and crowd control, and all sorts of other minutiae.

The caveat, though, is that meters don’t always give you the full picture, and you should always look at them with a skeptical eye. Big numbers on a chart are no substitute for performing your role and reacting appropriately to mechanics.


Download: CurseForge, Wago
Command: /details

Details! is the most, well, detailed of the available damage meters, with the broadest options for data and customization. For healers, there are options to track healing done, heals per second, overhealing, healing taken, healing absorbed, mana restored, and dispels, as well as damage taken and deaths. It also lets you track threat, damage, and more.

You can have multiple windows tracking different things, and you can customize their position and appearance to your heart’s content. Clicking on a bar will give you a detailed breakdown of that player’s casts. There are lots of other little features as well, like the ability to announce your interrupts, or view where your numbers rank within your guild. There is also integration with WeakAuras and Plater Nameplates.


Download: CurseForge
Command: /recount

Recount serves the same purpose as Details!, but is much simpler. For healers, it can track healing done, absorbs, healing taken, overhealing done, HoT uptime, mana gained, and dispels. It can also track damage done, damage taken, CC breaks, and a few other data points. There are fewer customization options than Details! has, but for the average user it’s probably plenty. Recount also lacks a threat meter, but a standalone threat meter can be installed separately.


Best Healing Addons for WoW (Classic & Dragonflight) (13)

Download: CurseForge
Command: /skada

Skada is another option for a meter addon, resting somewhere between customizability of Details! and the simplicity of Recount. Ultimately, any of these three meters will be able to give you the same healing data. It comes down to how deep you want to be able to dive into that data and how much you want to be able to customize your meter’s appearance.

Join the High Ground!

Thanks for reading! We hope you’ve found some great addons to boost your healing and keep your group in WoW alive. If you have any questions or think another addon should be on this list, leave a comment below, and be sure to subscribe to High Ground for more useful guides!

Happy gaming!

  • WoW Classic WotLK: Shaman Leveling Guide (1-80)

  • WoW Hardcore Classic – Best Class for Leveling

  • WoW Dragonflight: The 15 Best Warlock Transmog Sets

  • WoW Classic WotLK: Warrior Leveling Guide (1-80)

  • WoW Classic WotLK: Hunter Leveling Guide (1-80)

  • WoW Dragonflight: The 15 Best Druid Transmog Sets

" );})(jQuery);});

Submit a Comment

Top Articles
Latest Posts
Article information

Author: Foster Heidenreich CPA

Last Updated: 27/07/2023

Views: 6368

Rating: 4.6 / 5 (76 voted)

Reviews: 91% of readers found this page helpful

Author information

Name: Foster Heidenreich CPA

Birthday: 1995-01-14

Address: 55021 Usha Garden, North Larisa, DE 19209

Phone: +6812240846623

Job: Corporate Healthcare Strategist

Hobby: Singing, Listening to music, Rafting, LARPing, Gardening, Quilting, Rappelling

Introduction: My name is Foster Heidenreich CPA, I am a delightful, quaint, glorious, quaint, faithful, enchanting, fine person who loves writing and wants to share my knowledge and understanding with you.