A menu you can click with the mouse skips the button you wanted when you press down on a gamepad. On another screen, the game gets heavy only while that screen is open. Once the UI looks right, ease of operation and the cost of running it start to matter.
Investigate these two separately. The first half decides which button receives input and in what order focus moves ; the second half checks how often the display updates and what that costs . We use the same small menu and watch what changes when you change what.

What You'll Learn
- The difference between focus, mouse Hover, and the selection outline
- Deciding button order with Explicit and Stop
- Moving a per-frame update to an on-demand update
- How to measure before and after, and what Invalidation and Retainer do
- Focus is where key input goes
- Preparation: expanding a two-button menu to three
- Naming the next button with Navigation
- Selecting the first button, and why it sometimes fails
- Split UI cost into update work and display work
- Hands-On: updating the count only when needed
- Measure before and after under the same conditions
- Choosing between Invalidation Box and Retainer Box
- Bonus: checks as you expand the screen
- Summary
Focus is where key input goes
Focus is the UI element receiving keyboard or gamepad input. When a button has focus, Enter or the gamepad's accept button presses it. Direction keys move from there to the next selection.
Hover , meanwhile, is the state where the mouse pointer is over an element. The mouse can sit over "Controls" while key focus is on "Resume".

Having focus and showing it with an outline or color are also separate. Selection can move without you noticing, because the appearance did not change. Making which button receives input visible first makes everything easier to investigate.
Preparation: expanding a two-button menu to three
We use WBP_PadMenu from the gamepad support article. It has "Resume" and "Controls", opens with the M key or the gamepad's Menu/Start, and returns to the game when you press "Resume". If you have not built it yet, start from the menu creation in that article.
Here we add elements to that Widget. Keep using BP_InputPractice and PadMenuWidget for opening and closing. We do not add pausing game time. Focus and display updates are checked under these conditions first.
In the Designer, arrange the existing Vertical Box in this order. Duplicating HelpButton for CountButton and changing the name and label keeps things consistent.
| Element | Name | Label / settings |
|---|---|---|
| Text | For the heading | Menu |
| Button + Text | ResumeButton | Resume |
| Button + Text | HelpButton | Controls |
| Button + Text | CountButton | Refresh count |
| Text | HelpText | Empty at first. Where the existing control text goes |
| Text | Count heading | Markers |
| Text | CountText | "Not counted" at first. Is Variable on |
Set all three Buttons to Is Variable and Is Focusable on , Visibility Visible, and Is Enabled on. Is Focusable decides whether it can become the key-input target; Is Enabled decides whether it accepts operation.
So the buttons do not overlap, widen the Vertical Box's height to about 300, set children's Size to Auto, and set each Button's Padding to about 8. Keep the center anchor and Alignment (0.5, 0.5), and check the arrangement in the Designer. Layout fundamentals are covered in UMG Basics.

While practicing, set Render Focus Rule to Always under "Project Settings" → "User Interface". That draws an outline around the focused element. Move the mouse off the buttons and watch the outline move with the keys.
Naming the next button with Navigation
Navigation is the setting for how focus moves when you press a direction key or Tab. Select the Button itself in the Designer and open Navigation in the Details. Set it on the Button that receives input, not on the Text inside it.
Start with these three rules.
| Rule | Behavior | When to use it |
|---|---|---|
| Escape | Moves that way and automatically finds the next selectable element | Layouts you can leave to auto search |
| Explicit | Moves to the element you specify | When you want the next button fixed |
| Stop | Does not move that way and stays on the current element | Stopping at the menu's edge |
Escape is not a setting for the keyboard Esc key. It is a Navigation rule name. Auto search works for straightforward layouts, but when the destination matters in a complex arrangement, Explicit makes your intent verifiable.
Decide the vertical movement
Our menu is selected top to bottom and stops at both ends. Enter the next Button's name in the destination field that appears when you choose Explicit. If no candidates appear, check the name and Is Variable and compile.
| Selected Button | Up | Down |
|---|---|---|
| ResumeButton | Stop | Explicit → HelpButton |
| HelpButton | Explicit → ResumeButton | Explicit → CountButton |
| CountButton | Explicit → HelpButton | Stop |
Set Left and Right to Stop on all three, since nothing moves horizontally.
So Tab works too, set Next to the same as Down and Previous to the same as Up. Next is the path Tab takes forward, and Previous is Shift+Tab backward. Deciding only up and down can leave Tab in a different order, so check them separately.

Change one thing and confirm the destination
Compile, save, Play, and open the menu with M. If down moves "Resume → Controls → Refresh count" and pressing down again at the bottom stops, the settings are right. Up goes back in reverse.
Now stop Play and temporarily change only ResumeButton's Down to CountButton. Open it again and press down, and it should skip "Controls". That shows Explicit moves to the element you named, even if something else looks adjacent . Set it back to HelpButton afterwards.
When a destination surprises you, first look at "which rule is set in which direction on the current button". If it still names a Button that became hidden or disabled, reassign it to a valid target for that screen state.
Selecting the first button, and why it sometimes fails
Navigation moves from wherever you already are to the next place. The selection right after the menu opens is decided separately.
FocusFirstButton from the gamepad article is a function inside WBP_PadMenu that calls Set User Focus . Target is ResumeButton and Player Controller is Get Owning Player. It says "move this player's input target to this Button".

Keep this order on the opening side.
- Create Widget for WBP_PadMenu and store it in PadMenuWidget.
- Display that same Widget with Add to Viewport.
- Set Input Mode UI Only to direct input to the UI and show the cursor.
- Finally, call that Widget's FocusFirstButton.
If work that hands focus to another Widget runs after this order, your setting is overwritten. Check not only "did I place Set User Focus" but what runs after the call .
| Symptom | Where to check |
|---|---|
| No outline right after opening | FocusFirstButton's exec wire, ResumeButton's Is Focusable, Render Focus Rule |
| Clickable with the mouse but not with keys | The input mode for UI, and focus on the first Button |
| Set User Focus does not select it | Whether Target is the actual Button, whether it is shown and enabled, whether the Controller matches Owning Player |
| It is selected once, then jumps away | A later input-mode change, another Set Focus, or the screen being rebuilt |
| Cannot select after restoring from hidden | Focus assignment after returning to Visible, and Navigation destinations |
With UI Only here, the Widget receives operation after opening. Rather than also closing with the game's M key, we close with ResumeButton and return to Game Only. Game and UI lets the game also receive input the UI did not handle, but it does not guarantee that keys the UI handled reach the game.
Split UI cost into update work and display work
Next is display updates for the same menu. Even when the number on screen does not change, the same search or calculation may be running behind it every frame.

A frame is one round of the game updating the screen. Calling work from a Widget's Event Tick repeats it each frame it is displayed. Bindings set on Text or Percent also read values repeatedly. Even small work adds up as element count and call count grow.
Meanwhile, UMG itself has work to do: calculating element arrangement and size and preparing the information needed for drawing. There is GPU work to actually draw it too. Cutting only your own Blueprint work does not change overall speed much if those costs dominate.
Start by asking whether you need to repeat the same calculation without the appearance changing. Measure that effect first, then move on to element count and drawing mechanisms.
Hands-On: updating the count only when needed
We show the number of markers placed in the level on the menu. What we count here is Actors existing in the world . Keep that separate from the number of items the player carries.
1. Place three markers to count
Create a Blueprint with Actor as its parent and name it BP_UIPracticeMarker . Add a Static Mesh Component, choose Cube, and set Collision Presets to NoCollision. Leave physics simulation off.
Turn off Start with Tick Enabled in Class Defaults; this Actor does no per-frame work. Compile, save, and place three where you can see them in the level. This is a counting exercise for placed Actors, so we do not add spawn or destroy logic yet.
2. Build a function that displays the marker count
Create a function RefreshPracticeMarkerCount in WBP_PadMenu with no inputs or outputs.
- Connect a white exec wire from the function entry to Get All Actors Of Class, and set Actor Class to BP_UIPracticeMarker.
- Place Length from Out Actors.
- Convert Length's result from integer to Text and pass it to Set Text's In Text.
- Place CountText with Get and connect it to Set Text's Target.
- Connect Get All Actors Of Class's white exec output to Set Text.
Get All Actors Of Class searches for Actors of the given class and returns an Array . An array is a container holding multiple values. Reading its element count with Length gives 3 here.
To turn a number into display Text , drag from Length and choose the integer To Text node. The search runs on the white exec wire, but Length and the type conversion are value nodes and take no white wire.

Now wire the execution order for that calculation.

The two diagrams show the same function's wiring in parts. Place only one Get All Actors Of Class and connect both the data and exec wires.
Do not add a Binding to CountText's Text; update it with this function's Set Text.
3. Call it every frame once, and watch how often it runs
In WBP_PadMenu's event graph, call RefreshPracticeMarkerCount from Event Tick. Compile, Play, and open the menu. If 3 appears under "Markers", the chain from search to display works.
The display stays at 3, but the work repeats. To confirm, temporarily insert a Print String at RefreshPracticeMarkerCount's entry with In String Count refreshed , Print to Screen off, and Print to Log on. Open the menu and the same line repeats in the Output Log. Keep this check brief.
That log is for confirming it gets called . Log output has a cost too, so remove it before measuring performance.
4. Move it to opening and to the refresh button
Stop Play and disconnect the white wire from Event Tick to the function. Instead call the same RefreshPracticeMarkerCount from two places.
You can add CountButton's click event by selecting that Button in the Designer and pressing "+" on On Clicked under Details → Events.
| When it is called | Purpose |
|---|---|
| WBP_PadMenu's Event Construct | Show the initial count on the created menu |
| CountButton's On Clicked | Re-check the count when "Refresh count" is pressed |
If Event Construct already has work, continue at its end. Since opening creates the Widget each time here, the first count runs when you open it. Event Construct can also re-run when the display hierarchy is rebuilt; it is not an event guaranteed to fire exactly once in a Widget's lifetime.

Open the menu again and 3 appears. Waiting adds no log lines, and pressing "Refresh count" adds one. The displayed number is the same, but we reduced how often it is checked. Remove the Print String afterwards.

Stop Play, add one more marker, and open it again to see 4. In this exercise the marker count never changes at runtime, which is exactly why checking it while you wait was unnecessary.
In a real game where inventory or HP changes, notify the UI from the work that changed it. Combining an initial display with later change notifications leads into the HP bar hands-on.
Measure before and after under the same conditions
Cutting call count and making the whole game visibly faster are different claims. With three markers the work is tiny, and the time difference can vanish into measurement noise.
When investigating a real screen with real cost, work in the order measure → change one thing → re-measure under the same conditions .
- Remove debug logs such as Print String.
- Run
stat unitin the console during Play. Display it before opening the menu in UI Only. - Stand still in the same place, open the menu with the same camera and window size, and read Game and the rest.
- Stop Play and change only the update work you are investigating.
- Reopen the menu the same way, observe for a while, and compare.
Game is the game thread's processing time . It is CPU-side time where most of the game runs, not a UI-only number. The unit ms is milliseconds, one thousandth of a second. Do not judge from one instant; compare several times with the same actions.

For this exercise, compare the Tick version against the Construct/click version. Comparing only before and after opening the menu mixes in other costs such as Widget creation. On screens that pause, do not treat "game paused" versus "game running" as your before-and-after comparison.
If you see no difference, there is no need to force a conclusion that it improved. To chase which work takes time in more detail, move on to the Unreal Insights article. After getting a sense of the trend in the editor, confirm on your shipping target too.
Choosing between Invalidation Box and Retainer Box
Even after tidying update frequency, screens with many elements pay for layout and draw preparation. That is when you consider mechanisms that cache calculated information or drawn results. A cache stores what you built once so you can use it again.

Invalidation Box: reusing information for parts that do not change
Invalidation Box stores the information used to lay out and draw child Widgets. While nothing changes it reuses that information, recalculating only when something needs it.
The mark saying "the stored information is stale" is invalidation . It does not mean the UI became disabled and unusable.
A panel with lots of descriptive text and fixed icons is a good candidate. Select that group in the Designer, wrap it with an Invalidation Box from "Wrap With", and compare before and after on the same screen. Areas that add and remove elements every frame, or continuously change size, cannot reuse information for long.
You can also mark just the frequently changing small elements as Is Volatile . That treats their draw information as rebuilt each time, separating them from the static parts around them. It is not a setting for making the whole screen volatile.
If your project has Global Invalidation enabled, the whole window uses that mechanism. Individual Invalidation Box caching is not used inside it, so check the Slate.EnableGlobalInvalidation setting before adding a Box.
Retainer Box: drawing UI into a single image
Retainer Box draws child UI into an image destination called a Render Target and then displays that. Think of it as gathering into one picture instead of drawing everything directly to screen.
You can also adjust which frames update that picture. For a display where changes need not be instantaneous, wrap it in a Retainer Box in the Designer and set Render Rules to the following combination to try different update intervals.
| Setting | Value to try | Meaning |
|---|---|---|
| Render On Phase | On | Update on the specified frame phase |
| Phase Count | 3 | Split the update order into three |
| Phase | 0 | Update on phase 0 of those |
| Render On Invalidation | Off | Do not use extra updates from child change requests in this comparison |
With these settings, periodic updates land once every three frames. Phase is an ordering, not seconds. If the game's frame rate changes, so does the real-time interval. Turning Render On Invalidation on also updates on child change requests, so updates happen outside this cycle too.

Spacing out updates can make changes appear delayed. Selection outlines and press feedback especially become hard to operate when delayed. There is no need to wrap our whole three-button menu in a Retainer just to try it.
A Retainer uses extra image memory and costs work when redrawing. Decide whether you want to batch draw calls, thin out updates, or add material effects like noise, and choose accordingly. "Invalidation Box helped little, so replace everything with Retainer" is not how to choose.
Bonus: checks as you expand the screen
Separate hiding from not creating
Hidden and Collapsed are display states. Collapsed also frees the layout space, but it does not free the memory of a Widget you already created. Creating every tab and list up front and hiding them leaves the creation and memory cost behind.
For long lists, consider mechanisms like List View that build mostly the visible rows. Wrapping in a Scroll Box does not automatically skip creating every entry.
Try the cases where the selection disappears
After closing a settings panel, return focus to the button that opened it. After deleting the selected entry, move to a remaining neighbor. Pair work that changes the display with work that decides the next selectable place like this.
If you want to show focus with color, the standard Button Style's Hovered alone cannot represent gamepad selection. Query the selection state with Has User Focus and reflect it in the appearance. Confirm movement and confirmation work with the Always outline first, then build it out.
Widget Reflector also helps investigate which Widgets actually compose the screen. It helps trace the hierarchy of displayed elements once the menu structure gets complex.
Extending to a pause screen
The pause menu article adds stopping and resuming game time on top of opening, closing, and input targeting. The Navigation we set here is still needed once pause is added. First get the loop of open with M, select, and walk again via "Resume" working, then add time control.
Summary
Focus problems get easier to investigate when you separate "who receives input first" from "where it moves next". Cost problems come down to finding work that repeats even though the display is unchanged, moving it to the right moment, and then measuring.
First confirm you can select all three buttons in order, and that counting is called only on menu open and refresh press. On top of that, applying Invalidation or Retainer where the real cost is keeps your goal and its effect in view.
Reference: Navigation rules, Set User Focus, UMG optimization guidelines, UI Invalidation, Retainer Box.