[UE5] UMG Is Slow and Focus Jumps Around: Controlling Selection and Optimizing Performance

Created: 2025-12-12Last updated: 2026-07-19

Selection gets lost when you use a gamepad, and the frame rate drops when you open a menu. This article illustrates how to fix both of UMG's biggest problems with Navigation settings, Invalidation Box, and Retainer Box, including a hands-on pause menu fix.

Once your UI starts taking shape, two walls show up almost at the same time. Selection jumps to strange places when you use a gamepad , and the frame rate drops the moment you open the UI . Both are the kind of problem you never notice while building and only discover during polish.

This article covers how to control focus (which widget is currently receiving input) yourself, plus the causes of slow UI and what to do about them. At the end, we fix a real pause menu .

Terminology: In this article, focus means "the thing receiving input," which is separate from the mouse cursor . The gamepad D-pad moves focus, and that is also different from the visual change you get when hovering with the mouse (Hovered).

Illustration of gamepad selection jumping to an unintended place, alongside a slow, heavy UI

What You'll Learn

  • Focus jumps because automatic navigation guesses wrong
  • Four things to check when Set User Focus has no effect
  • Slow UI comes from either your own logic or drawing
  • Invalidation Box caches calculations, Retainer Box bakes to a texture
  • Hands-on: fixing both focus and performance in a pause menu

Sponsored

Why Focus Jumps

Focus is the state that says "which widget is currently accepting input." With a mouse alone you never have to think about it, but the concept jumps to the front the moment someone plays with a gamepad or keyboard .

Diagram of a menu with rows of buttons where pressing Down sends focus to a distant button instead of the neighboring one

By default, UMG automatically looks for the widget nearest in the direction you pressed and moves focus there. That guess only works well when your buttons line up neatly in a row or column.

The guess goes wrong in cases like these:

  • An invisible container sits between buttons, shifting the positions from what you expect
  • Hidden widgets (Collapsed / Hidden) are mixed in, changing the pool of candidates
  • Buttons are laid out in a grid, so "down" has no single obvious answer

In other words, jumping focus isn't a bug. It's the result of leaving things to a guess . That also makes the fix obvious: stop the guessing and specify the destination yourself .

Stop the Guessing with Explicit Navigation

Select a widget you want players to operate (a Button, for example) and scroll down in the Details panel to find Navigation . You can specify how movement works for each of the four directions.

Diagram showing how pressing Down behaves differently under the three modes: Escape, Explicit, and Stop
ModeBehaviorWhen to Use
Escape (default)Automatically searches for the nearest widgetSimple menus laid out in a straight line
ExplicitName a single destinationAny menu where you want a guaranteed order
CustomDecide the destination with a functionSpecial rules such as grid movement
StopNo movement in that directionThe end of a list, or a dialog you don't want to leave

For a menu with several buttons in a row, setting Up and Down to Explicit on every button is ultimately the fastest fix. Point "the bottom button's Down" at the top button and you get looping for free.

There's one more thing that will bite you every time you forget it: where focus lands first .

Call Set User Focus after the widget is in the Viewport. Calling it while the widget doesn't exist on screen yet does nothing. Calling it inside Event Construct can fail, so call it after Add to Viewport .

If it still doesn't land, check these four things: (1) is the target visible (Collapsed / Hidden won't take focus), (2) is Is Focusable enabled , (3) is the Owning Player correct , and (4) is something later overwriting the focus .

Event BeginPlay (Player Controller)
  → Create Widget (Class: WBP_PauseMenu)
  → Set MenuRef
  → Add to Viewport (Target: MenuRef)
  → Set User Focus (Target: MenuRef's StartButton, Player Controller: Self)  ← after it's on screen

Why UMG Gets Slow

UMG cost splits into two broad categories. Mixing them up means optimizing the wrong thing and burning time.

Diagram separating the cost of running Blueprint logic from the cost of drawing pixels on screen
  1. Logic cost: Event Tick, Binding functions, and the Cast or search operations inside them. In short, the code you wrote
  2. Draw cost: layout calculations and rendering, scaling with the number of widgets. In short, UMG's own work

It's more efficient to suspect the first one first . Your own code is easier to pin down, and fixes show clear results.

  • Logic in Event Tick: UI Tick keeps running as long as the game runs. It can even run while the widget isn't displayed, so the safest choice is not to use it at all
  • Heavy work in a Binding: Bindings are called continuously while the widget is displayed. If there's a Get All Actors Of Class search inside one, it runs forever

The fix is the same in both cases: change it to update only when the value changes (see Loose Coupling with Event Dispatchers).

Draw cost becomes the bottleneck when you have a huge number of widgets (inventory slots, long lists) or when you use large translucent areas or complex materials . The threshold depends on resolution and content, so don't ask "how many widgets is too many." Measure and decide .

Sponsored

Invalidation Box and Retainer Box

The names are similar and people mix them up, but they cache different things .

Contrast diagram showing Invalidation Box remembering calculation results while Retainer Box bakes the drawing into a texture
Invalidation BoxRetainer Box
What it cachesThe calculation results needed to drawThe texture of the drawn result
Cost it addressesLayout calculation and draw preparationDrawing itself (draw calls)
MemorySmallLarge (it holds a texture)
What it enablesSkipping updatesSkipping updates + applying materials
Good fit forComplex UI whose contents rarely changeHeavy UI with stacked translucency, blur effects

Invalidation Box works on the idea of "if nothing inside changed, there's no need to recalculate." When a child widget's property changes, the cache is discarded automatically and rebuilt on the next draw.

  • Effective for: complex hierarchies that stay on screen and only change occasionally (status panels, equipment lists)
  • Not effective for: simple widgets like a single text block, or anything that changes every frame (you keep throwing the cache away, which is a net loss)

Retainer Box bakes a drawn result into a texture and pastes that. It's powerful but eats memory, so limit it to cases where Invalidation Box isn't enough or where you want to apply a material effect to the UI . Setting Phase Count and Phase reduces the update rate (for example, Phase Count = 3 updates roughly once every three frames). Note that it still updates when a child requests invalidation.

Neither one is a superset of the other. Invalidation Box is a tool for skipping CPU-side recalculation and draw preparation . Retainer Box is a tool for turning the drawn result into a texture, lowering the update rate, and applying materials . They serve different purposes, so pick the one that matches your case.

There is, however, an order of operations. (1) Fix Tick/Bindings → (2) reduce unnecessary widgets → (3) use a Box where appropriate. Skipping steps 1 and 2 to start with a Box means spending time on the smallest wins.


Hands-On: Fixing a Pause Menu

A pause screen in an action game, a status screen in an RPG, a crafting menu in a survival game. Every genre has that one UI that runs slowly even though the game is frozen behind it. Here we take a typical pause menu and fix both focus and performance .

The open/close flow itself and the details of Trigger When Paused are the main subject of Implementing a Pause Menu. This article uses the pause screen as a subject and focuses on fixing focus and performance.

Setup to reproduce it: first, set up a pause key with Enhanced Input (see Getting Started with Enhanced Input).

TypeNameSettings
Input ActionIA_PauseDigital (Bool). Check Trigger When Paused (explained below)
Input Mapping ContextAdd to an existing oneAssign Esc or similar to IA_Pause
Widget BlueprintWBP_PauseMenuLayout below
Variable on BP_PlayerControllerMenuRefObject Reference of type WBP_PauseMenu

Lay out WBP_PauseMenu so that automatic navigation deliberately gets it wrong .

ElementPlacement
ResumeButton / OptionButtonSide by side in a Horizontal Box (upper part of the screen)
QuitButtonAlone below them (lower part, offset slightly to the right)
ItemCountTextDisplays how many items the player holds ( this is where we plant the heavy Binding )

Create a Binding on ItemCountText's Text that calls Get All Actors Of Class (BP_Item) and counts the results . This is the classic "wrote it for debugging and forgot about it" case.

Confirming the symptoms: hit Play, open the pause menu, and press a direction on the gamepad. Nothing should have focus at all (because Set User Focus is never called). Even if something does, the two upper buttons and the single lower button are offset, so Down sends focus somewhere you didn't intend . And the Game time in stat unit rises only while the menu is open.

Diagram of a pause menu with no stable focus while Game time is elevated at the same time

Step 1: open it, then set focus. On the Player Controller side, set focus after adding the widget.

Node graph running Create Widget into Add to Viewport, then calling Set User Focus
Enhanced Input Action IA_Pause
  Started
    → Branch (Condition: Is Valid (MenuRef))
        False (= open)
          → Create Widget (Class: WBP_PauseMenu, Owning Player: Self)
          → Set MenuRef
          → Add to Viewport (Target: MenuRef)
          → Set Input Mode Game and UI (In Widget to Focus: MenuRef)
          → Set Show Mouse Cursor (true)
          → Set Game Paused (true)
          → Set User Focus (Target: MenuRef's ResumeButton)      ← after it's on screen
        True (= close)
          → Remove from Parent (Target: MenuRef)
          → Set MenuRef (None)
          → Set Input Mode Game Only
          → Set Show Mouse Cursor (false)
          → Set Game Paused (false)

Two things will trip you up if you forget them.

  • Enable Trigger When Paused on IA_Pause . Without it, pressing the same key while paused does nothing, and you can't close the menu
  • Use Game and UI as the input mode . With UI Only, the Player Controller's game input (unpausing) never arrives

Step 2: name the destinations. Set each Button's Navigation to Explicit and specify where focus goes. The upper row is horizontal and the lower button stands alone, which is exactly the layout automatic navigation struggles with , so being explicit here stabilizes the behavior.

ButtonLeftRightDownUp
ResumeButtonOptionButtonOptionButtonQuitButtonQuitButton
OptionButtonResumeButtonResumeButtonQuitButtonQuitButton
QuitButtonResumeButton (loop)ResumeButton

Step 3: drop the Binding and update on an event instead. Delete the Binding on ItemCountText and count once, the moment the menu opens , instead.

For a pause menu this is the most reliable approach. World Timers also stop after Set Game Paused (true) , so "update periodically with a Timer" isn't an option. And since the value can't change while paused anyway, counting once on open is enough.

WBP_PauseMenu's Event Construct
  → Get All Actors Of Class (Actor Class: BP_Item)
  → Length
  → Set Text (Target: ItemCountText, In Text: the count as a string)

It's the same Get All Actors Of Class, but running it every frame versus once on open is a completely different cost . We didn't make the operation cheaper. We reduced how often it's called .

Step 4: address drawing if you need to. With three buttons, you're done. If you have a complex block that never changes , like an equipment list or an inventory, wrap just that part in an Invalidation Box . Only the static part, not the entire menu.

Hit Play and check. Resume should have focus the instant the menu opens, the direction keys should move between all three buttons as intended, and Esc should close it again. And the Game time in stat unit should be roughly unchanged from before you opened it. If all of that holds, you're done.

Here's how to narrow things down when it doesn't work.

  • Nothing has focusSet User Focus runs before Add to Viewport. Or the target is hidden or has Is Focusable off
  • Can't close the menu → Check Trigger When Paused on IA_Pause, or the input mode is UI Only
  • Direction keys do nothing → Check the input mode, and also check whether focus moved to a different widget
  • Still slow → Look for a remaining Event Tick or Binding. Adding a Box comes after that

Two points to take away.

  • Set focus after the widget is on screen: at Create Widget time, it doesn't exist on screen yet. Once the order is right, also keep visibility, Is Focusable, and Owning Player on your checklist to narrow problems down faster
  • Count the calls before you optimize the work: the same operation costs an order of magnitude more per frame than once. Reviewing when something is called is usually more effective than optimizing what it does

If you want to revisit your UI design from the ground up, go to Getting Started with UMG. If you want to learn how to measure cost in detail, go to stat Commands.

Sponsored

Bonus: Good to Know for Later

When mouse and gamepad are both in play, keep the states straight. Hovering with the mouse changes Hovered, which is a different state from the focus you move with the direction keys. Clicking, however, does move focus there. To avoid "I was selecting with the pad and then touching the mouse changed my selection," the standard approach is to detect the input device switching and reapply focus .

Don't forget the "focus is invisible" problem. A UMG Button's Style has Normal / Hovered / Pressed / Disabled, and no Focused entry . If you want the focus position to be visible, either use the standard focus outline (Focus Brush) or read the focus state and change the visuals yourself instead of relying on Is Hovered. Even correct behavior means nothing to the player if it isn't visible.

Widget Reflector shows you structure and updates. Open Tools → Debug → Widget Reflector in the editor and click your UI with Pick Painted Widgets to walk the widget hierarchy. When you want to find what is being redrawn , also enable Invalidation Debugging and Paint Debugging. It's the shortest path when you have no idea what's slow.

Consider whether you can just have fewer widgets. Images and Borders stacked purely for decoration, and empty containers, all cost something. When UI feels slow, opening the Hierarchy and deleting unnecessary layers is often more effective than any optimization technique.


Summary

Both of UMG's big problems have clear causes.

SymptomCauseFix
Focus jumps somewhere oddAutomatic navigation guessingName destinations with Explicit Navigation
Nothing has focus at firstSet User Focus runs too earlyCall it after Add to Viewport
Direction keys do nothingInput mode is still Game OnlySet Input Mode Game and UI (keeps the unpause key; UI Only suits title screens)
Slow when openedTick / BindingUpdate only when the value changes
Slow with hundreds of widgetsDraw costInvalidation Box, then Retainer Box as a last step

Be explicit instead of leaving it to a guess. Run things when values change instead of every frame. Those two principles clear up most UMG problems.

Take a look at the UI you're building right now. Is there a Binding in there that you added for debugging and never removed?