Description
Brannfred
Brannfred brings a spotlight-style search bar to WoW Classic TBC Anniversary/Era/Hardcore/SoD and Classic MoP. One keybind opens a floating input where you can fuzzy-search spells, quests, inventory, items, equipment sets, and more — all from a single place, without knowing where to look first.
Use a bang prefix (e.g. !s or !spell) to narrow results to a specific source. Other addons can register their own data sources via the provider API.
Note: Currently targets WoW Classic Editions only. Porting to Retail version is not planned but may be considered if there is enough interest.
The Brannfred Frame is completely customizable; you can change border, colors, and font in the Brannfred Settings. Additionally, all icons can be styled with Masque.
Opening Brannfred
There are three ways to open the search bar:
- Keybind — Open the Brannfred settings and click the "Toggle Brannfred search" button in the Key binding section. This is the recommended way.
- Slash commands — Type
/brannfredor/bfrdin chat to toggle the frame. - Minimap icon — Left-click the Brannfred minimap button.
Using Context Menus
Every result in Brannfred can have multiple actions tied to it. You can trigger different actions using:
Primary action (default) — Press
Enter, left-click on a result, or click the first action in the context menu. This is the most common thing you want to do with an item.Modifier-based actions — Hold a modifier key while pressing
Enteror clicking in the Results menu without the Context Menu open:Shift-EnterorShift-Click— secondary actionCtrl-EnterorCtrl-Click— tertiary actionAlt-EnterorAlt-Click— rare action
Context menu — Right-click on any result or use
TABto open or close a context menu for a search result entry showing all available actions with their modifier hints:
1. Show in Bags [En] ← Press 1 or click or press Enter
2. Use / Equip [En] ← Press 2 or click
3. Link in Chat [Sh] ← Press 3 or Shift-Click or press Shift-Enter
In the context menu you can:
Click on any action to trigger it
Press the number (1, 2, 3…) to trigger that action. Up to 10 actions can be called via numbers.
Use arrow keys to navigate and
Enterto selectPress
TABor right-click again to close the context menuIn the addon options you can decide which action is using which modifier key or disable it.
Real example: You search for an item in your inventory (e.g. "Healing Potion"):
- Press
Enter→ shows the item in your bags and highlights it (primary action) - Hold
Shiftand pressEnter→ links the item in chat (secondary action) - Right-click the result → opens context menu showing all available actions
Modules
Brannfred comes with a bunch of powerful modules from the get-go. The provided modifier keys are the default modifiers and can be swapped via the addon options.
Spellbook
Prefix: !s, !spell, or !skill
Simple search inside your Spellbook. Trade skills (i.e. opening any of the crafting menus) can be opened directly from Brannfred. Skills and so on can be dragged into your Action Bars.
Actions:
Enteror left-click[En]— casts the spell (profession/trade skills only; combat spells cannot be cast from the search bar).- Drag — picks up the spell so you can drop it onto an Action Bar slot.
- Hover over icon — shows the full spell tooltip including cast time, range, cost, and cooldown.
Tip: Right-click on a spell to open the context menu and see all available actions with their modifier keys.
Inventory
Prefix: !b, !bag, or !inv
This Module requires the Syndicator Addon to be installed. Simply search within your Brannfred search bar for pretty much everything in your inventory, bank, or other characters' inventory. Additionally, if you have Baganator installed you will be led to the corresponding inventory/bank space where the item gets highlighted.
Item names are coloured by quality (grey / white / green / blue / purple / orange).
Actions:
Enteror left-click[En]— shows the item in your bags (or uses/equips it; configurable in Inventory options).Ctrl-EnterorCtrl-Click[Ct]— toggles the secondary action (by default, uses/equips the item if the primary is "show in bags").Shift-EnterorShift-Click[Sh]— inserts the item link into the active chat input.- Drag — picks up the item so you can move it or link it.
- Hover over icon — shows the full item tooltip.
Tip: The primary action (Enter) is configurable in the Inventory options. You can swap between "Show in Bags" and "Use / Equip" as the primary action.
Quests
Prefix: !q or !quest
This Module requires the Questie Addon. It lets you search your quest log.
Quest names are coloured by level difficulty relative to your character (red / orange / yellow / green / grey). Completed quests show a light-green (Completed) suffix; failed quests have their icon tinted red.
Actions:
Enteror left-click[En]— opens the quest in your Quest Log.Shift-EnterorShift-Click[Sh]— posts a quest link in chat.Ctrl-EnterorCtrl-Click[Ct]— opens the World Map and navigates to the nearest objective or turn-in NPC.Alt-EnterorAlt-Click[Al]— sets a TomTom waypoint to the nearest objective or turn-in (TomTom is not required, but this action does nothing without it).
Item Database
Prefix: !idb or !itemdb
Search for items you don't currently own. Item names are coloured by quality (grey / white / green / blue / purple / orange) and the meta column shows the item sub-type (e.g. Sword, Cloth, Potion).
Requires the Ludwig addon. Its pre-built database (~15 000+ items) is available immediately from the first search.
Actions:
Shift-EnterorShift-Click[Sh]— inserts the item link into the active chat input.Ctrl-EnterorCtrl-Click[Ct]— opens the Dressing Room for equippable items.- Hover over icon — shows the full item tooltip.
Calculator
Prefix: !calc, !c, or !math
You can do quite a bit of calculation with it… I needed a use case for a dynamic data provider and that was the result. I went a bit overboard since I would only use the basic stuff, but since Lua provides a broad set of functions I added them :)…
Operators
| Operator | Description |
|---|---|
+ - * / |
Basic arithmetic |
% |
Modulo |
^ |
Exponentiation (right-associative: 2^3^2 = 2^9) |
Unary - and + |
Negation / identity |
() |
Parentheses for grouping: (2 + 3) * 4 |
Constants
| Constant | Value |
|---|---|
pi |
π (3.14159…) |
e |
Euler's number (2.71828…) |
Functions
| Function | Description |
|---|---|
sqrt(x) |
Square root |
abs(x) |
Absolute value |
floor(x) |
Round down |
ceil(x) |
Round up |
round(x) |
Round to nearest |
sin/cos/tan(x) |
Trigonometry (radians) |
asin/acos/atan(x) |
Inverse trig functions |
log(x)/ln(x) |
Natural logarithm |
log2(x) |
Base-2 logarithm |
log10(x) |
Base-10 logarithm |
exp(x) |
e^x |
min(a,b,…)/max(a,b,…) |
Minimum / Maximum |
Friends
Prefix: !f — shows both Battle.net and in-game friends together.
Use !bnet / !bn to show only Battle.net friends, or !friend / !fr for in-game friends only.
Lists all your friends sorted by priority: in-game online friends appear first, followed by Battle.net online friends (e.g. playing another game), and offline friends always at the bottom. Online friends are shown in green, offline in grey.
Actions:
Enteror left-click[En]— pre-fills the chat box with/w <name>so you can start typing immediately.Shift-EnterorShift-Click[Sh]— invites the friend to your party (only works when they are actively in-game).
Battle.net friends: when the friend is playing WoW, their character name is shown with the BattleTag appended in blue parentheses (e.g. Friedbert (John#1234)). When online but not in WoW, only the BattleTag or Real ID name is shown. The meta column shows AFK, DND, Online, or Offline status.
In-game friends: the meta column shows their level when online, or Offline otherwise.
The detail panel shows class, current zone, and any friend note you have set.
Equipment Sets
Prefix: !eq, !equip, !set, or !gear
Requires the ItemRack addon. Lists all your saved equipment sets. The meta column shows [active] for the currently worn set, or the number of item slots the set defines.
Actions:
Enteror left-click[En]— equips the selected set.
Provider API
Any addon can register its own data source with Brannfred. Create a new addon with Brannfred as a dependency, implement a provider table, and call Brannfred:RegisterProvider().
Minimal example
local MyProvider = {
type = "mytype", -- unique string, used for prefix filtering
label = "My Source", -- shown in the type label column
aliases = { "my", "mine" }, -- bang-prefix shortcuts: !my, !mine
providerIcon = "Interface/ICONS/…", -- icon shown in the ! autocomplete list
color = { r=1, g=1, b=1 },
labelColor = { r=0.4, g=0.8, b=1 },
entries = {},
}
function MyProvider:OnEnable()
self.entries = {}
self.entries[#self.entries + 1] = {
name = "My Entry",
icon = "Interface/ICONS/…",
type = "mytype", -- must match provider.type
color = self.color,
labelColor = self.labelColor,
context_actions = {
{
name = "My Action",
func = function() print("activated!") end,
modifier = "primary", -- primary action (Enter / click)
},
},
}
end
Brannfred:RegisterProvider(MyProvider)
Provider fields
| Field | Required | Description |
|---|---|---|
type |
yes | Unique identifier string. Used for !prefix filtering. |
label |
yes | Human-readable name shown in the type-label column. |
aliases |
— | Additional bang-prefix strings (e.g. { "s", "spell" }). |
providerIcon |
— | Icon shown in the ! autocomplete list. Falls back to the first entry's icon. |
color |
— | Default {r,g,b} for entry name text. |
labelColor |
— | Default {r,g,b} for the type label column. |
entries |
— | Flat list of entry tables. Populated in OnEnable or onQuery. |
OnEnable() |
— | Called when Brannfred enables. Build self.entries here. |
prefixOnly |
— | true → excluded from global (unprefixed) search. |
preserveOrder |
— | true → Search does not re-sort entries; the provider is responsible for ordering them itself. |
hideFromAutocomplete |
— | true → provider is hidden from the ! autocomplete list but still reachable via its aliases. |
onQuery(query) |
— | Called per keystroke for dynamic providers; build self.entries inside it. |
Entry fields
| Field | Required | Description |
| ----------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------ | ---------------------------------------------------- |
| name | yes | Display name and default fuzzy-match target. |
| icon | yes | Texture path or FileDataID. |
| type | yes | Must equal provider.type. |
| color | — | {r,g,b} override for the entry name text. |
| iconColor | — | {r,g,b} tint applied to the entry icon via SetVertexColor (e.g. red for failed quests). Defaults to white (no tint). |
| labelColor | — | {r,g,b} override for the type label. |
| searchName | — | Alternative string used for fuzzy matching (e.g. "Fireball Rank 5"). |
| getMeta() | — | Returns a short string for the meta column (color escape codes supported). |
| getStats() | — | Returns a one-line stat string shown in the description panel header. |
| getDesc() | — | Returns a longer description shown below the separator line. |
| context_actions | yes | Array of action tables with { name = "...", func = function() ... end, modifier = "primary" | "shift" | "ctrl" | "alt" }. Triggered by Enter/click or modifier keys. |
| onDrag() | — | Called when the row is dragged (e.g. PickupSpellBookItem). |
| onIconTooltip(anchor) | — | Called when the cursor enters the entry's icon (both in the result rows and the description panel). anchor is the icon button frame. Show a GameTooltip here. |
| _noPreview | — | true → suppresses the description panel for this entry. |
Understanding context_actions
Every entry must define one or more actions via the context_actions array. Each action in the array is a table with the following structure:
{
name = "Action Display Name", -- shown in the context menu
func = function() /* do something */ end, -- called when the action is triggered
modifier = "primary", -- "primary", "shift", "ctrl", "alt", or nil
}
Modifiers
The modifier field determines when an action is triggered:
| Modifier | Trigger | Hint | Example |
|---|---|---|---|
"primary" |
Enter or left-click on the entry |
[En] |
Primary action — the main thing you want to do |
"shift" |
Shift-Enter or Shift-Click |
[Sh] |
Open related UI, show more details |
"ctrl" |
Ctrl-Enter or Ctrl-Click |
[Ct] |
Alternative action or power move |
"alt" |
Alt-Enter or Alt-Click |
[Al] |
Rare/special action |
nil |
Context menu only | — | Action without keyboard shortcut (context-menu-only) |
Note: Set modifier = nil if you want an action to appear only in the context menu without any keyboard shortcut. This is useful for rarely-used or potentially destructive actions.
Single-action entries (most common)
For simple entries with only one action, set modifier = "primary":
{
name = "Alchemy",
icon = "Interface/ICONS/trade_alchemy",
type = "spell",
context_actions = {
{
name = "Open",
func = function() CastSpellByName("Alchemy") end,
modifier = "primary", -- triggered by Enter / left-click
},
},
}
User interaction:
- Press
Enteror left-click → opens the Alchemy window
Multi-action entries
You can define multiple actions with different modifiers. The primary action is always the first one with modifier = "primary":
{
name = "Engineering",
icon = "Interface/ICONS/trade_engineering",
type = "spell",
context_actions = {
{
name = "Open",
func = function() CastSpellByName("Engineering") end,
modifier = "primary", -- primary action
},
{
name = "Show Details",
func = function() print("Engineering: Create gadgets and explosives") end,
modifier = "shift",
},
{
name = "Link Profession",
func = function() ChatFrame1:AddMessage("[Engineering]") end,
modifier = "ctrl",
},
},
}
User interaction:
- Press
Enteror left-click → opens Engineering window - Press
Shift-EnterorShift-Click→ prints profession details - Press
Ctrl-EnterorCtrl-Click→ links profession in chat - Right-click → opens a context menu with all three actions listed (showing hints
[En],[Sh],[Ct])
Real-world example: The Inventory module
The Inventory Provider demonstrates a practical multi-action setup:
context_actions = {
{
name = L["Show in Bags"], -- primary: open bags and highlight
func = function() showInBags(entry) end,
modifier = "primary",
},
{
name = L["Use / Equip"], -- ctrl+enter: use item directly
func = function() /* use item logic */ end,
modifier = "ctrl",
},
{
name = L["Link in Chat"], -- shift+enter: insert link to chat
func = linkInChat,
modifier = "shift",
},
}
The context menu shows all actions in order, with Show in Bags [En] at the top (the default when you press Enter).
Context-menu-only actions
Some actions should only be available via the context menu, without a keyboard shortcut (e.g., rarely-used or destructive actions). To create such an action, set modifier = nil:
context_actions = {
{
name = "Equip Set",
func = function() ItemRack.EquipSet(setName) end,
modifier = "primary", -- primary action
},
{
name = "Delete Set",
func = function() ItemRack.DeleteSet(setName) end,
modifier = nil, -- context menu only, no keyboard shortcut
},
}
In this example, "Delete Set" appears in the context menu but cannot be triggered accidentally via a keyboard shortcut.
Built-in hint customization
The UI automatically adds modifier hints ([En], [Sh], [Ct], [Al]) based on your context_actions definitions. You can override which action name is linked to a modifier in the Brannfred Settings under the Key bindings section for each provider.
Dynamic providers
For providers whose results depend on the typed query (e.g. a calculator), implement onQuery(query) instead of a static entries list. Brannfred calls provider:onQuery(query) on every keystroke when the user types !mytype <query>, then reads provider.entries. Set prefixOnly = true so the provider stays invisible in global search.
local DynProvider = {
type = "dyn",
label = "Dynamic",
aliases = { "dyn" },
prefixOnly = true,
preserveOrder = true,
entries = {},
}
function DynProvider:onQuery(query)
self.entries = {}
-- build entries based on query …
self.entries[1] = { name = "Result: " .. query, icon = "…", type = "dyn" }
end
Brannfred:RegisterProvider(DynProvider)
Options sub-page
Providers can add a sub-page under Brannfred in the Blizzard options panel:
Brannfred:RegisterProviderOptions("MyType", "My Source", {
someToggle = {
type = "toggle",
name = "Enable feature",
get = function() return Brannfred.db.profile.myFeature end,
set = function(_, v) Brannfred.db.profile.myFeature = v end,
},
})

