Verse UI: Programmatic Widget Population with GetPlayerUI
Tutorial intermediate compiles

Verse UI: Programmatic Widget Population with GetPlayerUI

Updated intermediate Code verified

What you'll learn

You will learn to take a Verse data array and programmatically build a stacked UI list for a player. Instead of hand-placing widgets, you iterate your data, build one text_block widget per item, and add each to the player's UI canvas. This is the foundation for dynamic inventory menus, shop lists, and quest trackers.

How it works

The technique relies on three grounded APIs and one important failable-call rule:

  1. Detect the request: Subscribe to a trigger_device.TriggeredEvent. The handler receives an ?agent, which you must bind with if (Agent := MaybeAgent?) — there is no nil.
  2. Get the canvas — carefully: GetPlayerUI is declared <transacts><decides>. Because it can FAIL (a player might not have a UI), you call it with square brackets inside a failure context: if (UI := GetPlayerUI[PlayerObj]). Calling it with () as a bare statement will not compile.
  3. Populate: Loop your data with for (Item : Data), build a text_block widget per item, arrange them in a stack_box, and call AddWidget(RootWidget) once. Track a running index so each row shows its slot number.

A key correctness note: agent and player are different types. TriggeredEvent gives an agent, so we convert to a player with the failable player[Agent] cast — again inside an if.

Let's build it

Paste this into a new Verse file, build, then place the device and a trigger in your level.

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/UI }
using { /UnrealEngine.com/Temporary/SpatialMath }
using { /Fortnite.com/UI }

# Dynamic UI list builder: turns a data array into stacked text rows.
ui_slot_populator := class<concrete>(creative_device):

    # Trigger the player steps on to request the UI list.
    @editable ActivateTrigger : trigger_device = trigger_device{}

    # The data we render. Swap this for real inventory/shop data.
    InventoryData : []string = array{"Sword", "Shield", "Health Potion", "Key Card", "Map"}

    OnBegin<override>()<suspends>: void =
        # Subscribe so each trigger activation rebuilds the list for that agent.
        ActivateTrigger.TriggeredEvent.Subscribe(OnTriggered)

    # Handler signature matches TriggeredEvent: receives an ?agent.
    OnTriggered(MaybeAgent : ?agent): void =
        # Bind the optional agent (no nil in Verse).
        if (Agent := MaybeAgent?):
            # agent -> player is a failable cast, so do it in a condition.
            if:
                PlayerObj := player[Agent]
                # GetPlayerUI is <decides>: brackets, inside failure context.
                UI := GetPlayerUI[PlayerObj]
            then:
                PopulateUI(UI)

    # Build one text widget per data item, stack them, add once.
    PopulateUI(UI : player_ui): void =
        RootStack := stack_box{Orientation := orientation.Vertical}
        var Index : int = 1
        for (ItemName : InventoryData):
            # One row widget per inventory entry, showing its slot number.
            Row := text_block:
                DefaultText := StringToMessage("Slot {Index}: {ItemName}")
            RootStack.AddWidget(stack_box_slot{Widget := Row})
            set Index += 1
        # Render the fully built stack to the player's canvas.
        UI.AddWidget(RootStack)

    # text_block wants a message; interpolate the string into one.
    StringToMessage<localizes>(Value : string) : message = "{Value}"```

## Try it yourself

1. Place a **Trigger** device and this Verse device in your level, then assign the trigger to `ActivateTrigger`.
2. Add or remove entries in `InventoryData`  the list grows/shrinks automatically because we loop over it.
3. Step on the trigger. Each activation rebuilds the vertical list for the activating player.
4. Extend it: swap `InventoryData` for a `[]struct` of items so each row can show price, icon, or quantity.

## Recap

- **`GetPlayerUI[Player]`** is `<transacts><decides>`  call it with `[]` inside an `if`, and READ the result; it can fail.
- **`player[Agent]`** is the failable cast from the `agent` you get in a trigger event to the `player` `GetPlayerUI` needs.
- **`AddWidget(Widget)`** renders a widget tree; build a `stack_box` of `text_block`s and add it once, driven by your data loop.
- Bind optionals with `if (X := Maybe?)`  there is no `nil` in Verse.

Check your understanding

Test yourself with an interactive quiz and track your progress + earn XP — free for members.

Turn this into a guided course

Add Programmatic UI Slot Population via Verse Data Binding to your free study plan — we'll suggest related pages and stitch the lot into one compile-checked, self-guided lesson with worked examples and quizzes.

Original tutorial generated by Verse Island from the Verse/UEFN knowledge base, with references to the Epic Games sources above. Code is validated against the knowledge base.

Comments

    Sign in to vote, comment, or suggest an edit. Sign in