Overview
A button is a Verse UI widget — a container that holds a single child widget (usually a text_block) and fires events when the player interacts with it on their HUD. Unlike the physical button_device you place in the world (which players walk up to and interact with for a duration), the button widget lives on the screen and responds to a mouse click or the bound input action.
Reach for the button widget when you want screen-space UI: a Ready Up button in a lobby, a Respawn prompt, a shop Buy button, or a menu the player opens with a key. You build the widget in Verse, add it to a player's screen with player_ui, and subscribe to:
OnClick— fires when the player clicks the button. This is the one you'll use most.HighlightEvent— fires when the player's cursor moves onto the button (hover-in).UnhighlightEvent— fires when the cursor leaves the button (hover-out).
All three hand your handler a widget_message, which carries the player who triggered it via the .Player field.
API Reference
button
Button is a container of a single child widget slot and fires the OnClick event when the button is clicked.
Full public surface, resolved verbatim from the live Epic digest (UnrealEngine.digest.verse). Inherited members are merged from widget.
button<native><public> := class<final>(widget):
Events (subscribe a handler to react):
| Event | Signature | Description |
|---|---|---|
OnClick |
OnClick<public>():listenable(widget_message) |
Subscribable event that fires when the button is clicked. |
HighlightEvent |
HighlightEvent<public>():listenable(widget_message) |
— |
UnhighlightEvent |
UnhighlightEvent<public>():listenable(widget_message) |
— |
widget
Base class for all UI elements drawn on the
player's screen.
Full public surface, resolved verbatim from the live Epic digest (UnrealEngine.digest.verse).
widget<native><public> := class<abstract><unique><epic_internal>:
Walkthrough
Let's build a lobby Ready Up button. When a player joins, we draw a button on their screen. Clicking it opens a vault door (a door_device) for that player and swaps the button label to "READY!". Hovering highlights it. This uses OnClick, HighlightEvent, and UnhighlightEvent — the full event surface.
using { /Fortnite.com/Devices }
using { /Fortnite.com/UI }
using { /UnrealEngine.com/Temporary/UI }
using { /UnrealEngine.com/Temporary/SpatialMath }
using { /Verse.org/Simulation }
ready_button_device := class(creative_device):
# The vault door we open when the player clicks Ready
@editable
VaultDoor : door_device = door_device{}
# Localized message helper — button labels take a `message`, not a raw string
Label<localizes>(S : string) : message = "{S}"
OnBegin<override>()<suspends> : void =
# Draw a button for every player already in the game
for (Player : GetPlayspace().GetPlayers()):
AddReadyButton(Player)
AddReadyButton(Player : player) : void =
if (PlayerUI := GetPlayerUI[Player]):
# Build the label that sits inside the button
LabelText := text_block{ DefaultText := Label("READY UP") }
# The button is a container holding that text as its child
ReadyBtn := button_loud{}
ReadyBtn.SetChildWidget(LabelText)
# Subscribe to all three events. The handlers are methods below.
ReadyBtn.OnClick().Subscribe(OnReadyClicked)
ReadyBtn.HighlightEvent().Subscribe(OnReadyHighlighted)
ReadyBtn.UnhighlightEvent().Subscribe(OnReadyUnhighlighted)
# Wrap the button in a canvas so we can position it on screen
Canvas := canvas{}
Canvas.AddWidget(canvas_slot{
Widget := ReadyBtn,
Anchors := anchors{ Minimum := vector2{X := 0.5, Y := 0.85}, Maximum := vector2{X := 0.5, Y := 0.85} },
Alignment := vector2{X := 0.5, Y := 0.5}
})
PlayerUI.AddWidget(Canvas)
# OnClick hands us a widget_message; read the player off it
OnReadyClicked(Message : widget_message) : void =
Player := Message.Player
# Open the vault door for the player who clicked
if (Agent := agent[Player]):
VaultDoor.Open(Agent)
OnReadyHighlighted(Message : widget_message) : void =
Print("Player is hovering the Ready button")
OnReadyUnhighlighted(Message : widget_message) : void =
Print("Player stopped hovering the Ready button")
Line by line:
- The
using { /Fortnite.com/UI }and/UnrealEngine.com/Temporary/UIimports bring inbutton_loud,text_block,canvas, andplayer_ui. Without them the button symbols read as "Unknown identifier". @editable VaultDoorlets you point at a placeddoor_devicein the level from the Details panel — we open it on click via its realOpen(Agent)method.Label<localizes>(S:string):messageis the localized-text helper. Button labels aremessage, never raw strings — this converts one for us.- In
OnBegin,GetPlayspace().GetPlayers()loops every player and callsAddReadyButtonto draw their personal button. GetPlayerUI[Player]returns theplayer_uifor that player (it can fail, hence theif).text_blockis the child widget shown inside the button.button_loudis a concrete clickable button;SetChildWidgetputs the text inside it.ReadyBtn.OnClick().Subscribe(OnReadyClicked)wires the click. NoteOnClick()is a function returning a listenable — you call it, then.Subscribe.- The
canvas+canvas_slotposition the button at the bottom-center of the screen (anchors 0.5/0.85). OnReadyClickedreadsMessage.Player, converts it to anagent, and callsVaultDoor.Open(Agent)— real game state changes on click.
Common patterns
Pattern 1 — Highlight feedback with HighlightEvent. Play a sound-cue-style log (or trigger a device) when the cursor enters a button.
using { /Fortnite.com/Devices }
using { /Fortnite.com/UI }
using { /UnrealEngine.com/Temporary/UI }
using { /Verse.org/Simulation }
hover_button_device := class(creative_device):
Label<localizes>(S : string) : message = "{S}"
OnBegin<override>()<suspends> : void =
if (Player := GetPlayspace().GetPlayers()[0], UI := GetPlayerUI[Player]):
Btn := button_loud{}
Btn.SetChildWidget(text_block{ DefaultText := Label("BUY") })
Btn.HighlightEvent().Subscribe(OnHovered)
UI.AddWidget(Btn)
OnHovered(Message : widget_message) : void =
Print("Cursor entered the Buy button")
Pattern 2 — Wire a click into a real device (button_device.Enable). Here clicking a HUD button enables a placed physical button_device, unlocking a world interaction.
using { /Fortnite.com/Devices }
using { /Fortnite.com/UI }
using { /UnrealEngine.com/Temporary/UI }
using { /Verse.org/Simulation }
unlock_button_device := class(creative_device):
@editable
WorldButton : button_device = button_device{}
Label<localizes>(S : string) : message = "{S}"
OnBegin<override>()<suspends> : void =
# Start with the world button disabled
WorldButton.Disable()
if (Player := GetPlayspace().GetPlayers()[0], UI := GetPlayerUI[Player]):
Btn := button_loud{}
Btn.SetChildWidget(text_block{ DefaultText := Label("ENABLE TERMINAL") })
Btn.OnClick().Subscribe(OnUnlockClicked)
UI.AddWidget(Btn)
OnUnlockClicked(Message : widget_message) : void =
# Enable the physical button device so players can now use it
WorldButton.Enable()
Print("World terminal enabled")
Pattern 3 — UnhighlightEvent to reset UI state. Track hover exit so you can undo a highlight effect.
using { /Fortnite.com/Devices }
using { /Fortnite.com/UI }
using { /UnrealEngine.com/Temporary/UI }
using { /Verse.org/Simulation }
unhover_button_device := class(creative_device):
Label<localizes>(S : string) : message = "{S}"
OnBegin<override>()<suspends> : void =
if (Player := GetPlayspace().GetPlayers()[0], UI := GetPlayerUI[Player]):
Btn := button_loud{}
Btn.SetChildWidget(text_block{ DefaultText := Label("MENU") })
Btn.HighlightEvent().Subscribe(OnIn)
Btn.UnhighlightEvent().Subscribe(OnOut)
UI.AddWidget(Btn)
OnIn(Message : widget_message) : void =
Print("Highlighted")
OnOut(Message : widget_message) : void =
Print("Reset to normal")
Gotchas
OnClickis a function, not a field. You must call it with()before subscribing:Btn.OnClick().Subscribe(Handler). WritingBtn.OnClick.Subscribe(...)will not compile.- Handlers receive a
widget_message, not anagent. The player is on the message:Message.Player. If you need anagent(fordoor.Open(Agent), item grants, etc.) convert withif (Agent := agent[Message.Player]):. - Button labels are
message, never raw strings. Use aLabel<localizes>(S:string):messagehelper — there is noStringToMessage. Passing"BUY"directly where amessageis expected fails to compile. - A button holds a single child. Use
SetChildWidget(or the constructor slot) to place atext_blockinside — a bare button with no child renders empty. GetPlayerUI[...]can fail. It returns a value inside anif/failure context; always unwrap it (if (UI := GetPlayerUI[Player]):) before callingAddWidget.- The button widget is not the button_device. They share the
OnClick/interaction idea but are different types: the widget is drawn on the HUD in Verse; the device is placed in the world and usesInteractedWithEvent. Don't mix their methods. - Subscribe in
OnBegin(or right after building the widget), and keep references alive. If the widget or your subscription goes out of scope, clicks stop being handled.