Skip to content

UReactWebBrowser

Source: SampleProject/Plugins/UnrealReactBridge/Source/UnrealReactBridge/Public/ReactWebBrowser.h

The React ↔ Unreal bridge as a single, self-contained widget. Drag React Web Browser from the Palette into any Widget Blueprint — no parent class to inherit, no child widget to name exactly right. All bridge lifecycle (BindUObject timing, event queue, init script) is handled internally.

  • UCLASS: BlueprintType
  • Display name: React Web Browser
  • Parent class (C++): UWidget — not UWebBrowser. UWebBrowser declares a non-virtual LoadURL(FString) that navigates without resetting bridge state, and UHT has no way to hide an inherited non-virtual UFUNCTION on a derived class, so inheriting it would leave that trap sitting in the Palette forever. UReactWebBrowser owns its SWebBrowser directly instead.

Multiple browsers on one HUD

Drop more than one ReactWebBrowser into the same Widget Blueprint and each must be a direct child of a CanvasPanel — see Multi-HUD at named anchors and Known Issues → LayerId collision for why.

Properties

PropertyTypeCategoryNotes
URLFString (EditAnywhere, BlueprintReadWrite)React BridgeReact app URL. Use http://localhost:5173 for a Vite dev server, or a file:// path for a packaged build. Falls back to Project Settings → Unreal React Bridge → Default Dev URL if empty.
BridgeNameFString (EditAnywhere, BlueprintReadWrite)React BridgeOptional. Identifier used to address this browser from a Sender's TargetBridgeName. Empty (default) = receives broadcasts only.
InitialStateTMap<FString, FString> (EditAnywhere, BlueprintReadWrite)React Bridge | Initial StateKey/value pairs delivered to React on the ue5-bridge-ready event under detail.initialState. Each value should be a valid JSON string; non-JSON values are wrapped as JSON strings. See /guide/initial-state.
bInteractivebool (EditAnywhere, BlueprintReadWrite)React BridgeWhen true (default) the browser can take mouse & keyboard focus so React <input> fields work. Set false for a display-only overlay.

Functions

FunctionSignatureNotes
SendEventvoid SendEvent(const FString& EventName, const FString& JsonData)Queues if React not yet ready; queue is flushed once on OnReactReadyEvent.
LoadReactURLvoid LoadReactURL(const FString& NewURL)Resets bridge state and re-initializes on load.
IsReadybool IsReady() const (BlueprintPure)Has React called window.ue.bridge.ready() (i.e. fired onreactready) yet?
SetInteractivevoid SetInteractive(bool bNewInteractive)Toggle mouse/keyboard focus. Applies immediately to an already-mounted browser.
SetVisiblevoid SetVisible(bool bVisible)Show/hide without unmounting. The embedded browser stays alive across the toggle.

SendEvent

cpp
void SendEvent(const FString& EventName, const FString& JsonData);
ParamTypeRequiredNotes
EventNameFStringyesCase-sensitive
JsonDataFStringyesValid JSON string; reaches React as event.detail

Returnsvoid. Fires synchronously if ready; otherwise enqueued and flushed when OnReactReadyEvent is invoked.

LoadReactURL

cpp
void LoadReactURL(const FString& NewURL);
ParamTypeRequiredNotes
NewURLFStringyesNew page URL (http://, https://, or file:///)

Returnsvoid. Triggers the full lifecycle again: page load → bridge re-bind → OnReactReadyEvent re-fires. Any state held in React is lost; rehydrate via InitialState on the next ready.

Named LoadReactURL, not LoadURL, purely for naming consistency with the rest of the bridge API — this class does not inherit UWebBrowser (see above), so there is no competing inherited LoadURL(FString) to collide with. LoadReactURL is the only load entry point this widget exposes to Blueprint.

IsReady

cpp
bool IsReady() const;

Returnstrue once React has called window.ue.bridge.ready() and the queued events have been flushed.

SetInteractive

cpp
void SetInteractive(bool bNewInteractive);
ParamTypeRequiredNotes
bNewInteractiveboolyestrue = can take mouse/keyboard focus; false = display-only, HitTestInvisible

Returnsvoid. Reapplies focusability + hit-test visibility immediately, so it works on an already-mounted browser (e.g. a toggled-open chat panel).

SetVisible

cpp
void SetVisible(bool bVisible);
ParamTypeRequiredNotes
bVisibleboolyestrue = show (the interactive-resolved visibility); false = Collapsed

Returnsvoid. The embedded SWebBrowser is kept alive across a hide, so re-showing never reconstructs it.

macOS: why SetVisible exists

On macOS, a freshly-constructed native web view grabs Slate keyboard focus once, which drops held game input (WASD) and shows the OS cursor — see Known Issues. Toggling SetVisible never reconstructs the browser, so the grab never re-fires. Mount once (e.g. at BeginPlay), then use SetVisible for any runtime show/hide — never destroy and recreate the widget just to hide a panel.

Events

All events are BlueprintAssignable and live under category React Bridge.

EventSignatureWhen
OnReactReadyEventFOnReactBrowserReady()React signaled ready, bridge live, queued events flushed
OnEventReceivedFOnReactBrowserEventReceived(const FString& EventName, const FString& JsonData)A React-side event arrived. Receiver components handle most cases; this event is for ad-hoc handling directly on the widget
OnBridgeErrorFOnReactBrowserBridgeError(const FBridgeErrorInfo& ErrorInfo)Any bridge error — see /reference/types#fbridgeerrorinfo
cpp
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnReactBrowserReady);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnReactBrowserEventReceived,
    const FString&, EventName,
    const FString&, JsonData);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnReactBrowserBridgeError,
    const FBridgeErrorInfo&, ErrorInfo);

Lifecycle notes

  • The widget self-registers with UUnrealReactBridgeSubsystem inside RebuildWidget() and unregisters in ReleaseSlateResources() — a plain UWidget has no NativeConstruct/NativeDestruct, so lifecycle is driven from those two instead. You don't call any registration API yourself.
  • LoadReactURL restarts the full lifecycle: page reload → bridge re-bind → OnReactReadyEvent fires again.
  • At Widget Blueprint compile time, ValidateCompiledDefaults checks for the LayerId-collision constraint (see the tip above) and warns if this browser shares a non-CanvasPanel ancestor with another ReactWebBrowser.

Example

text
WBP_MyHUD
└── CanvasPanel (root)
    └── ReactWebBrowser  ← React Web Browser widget, dropped onto the canvas

Details
  URL:         http://localhost:5173
  BridgeName:  MainHUD
  InitialState:
    "player" → {"name":"Alice","hp":100}
    "level"  → 7
text
Level Blueprint
  Event BeginPlay
    └─ Create Widget (Class: WBP_MyHUD)  → HudRef
    └─ Add to Viewport (Target: HudRef)
cpp
// C++: drive the widget after creation
if (UReactWebBrowser* Browser = Cast<UReactWebBrowser>(
        Hud->WidgetTree->FindWidget(TEXT("ReactWebBrowser"))))
{
    Browser->InitialState.Add(TEXT("player"),
        TEXT("{\"name\":\"Alice\",\"hp\":100}"));

    Browser->OnReactReadyEvent.AddDynamic(this, &AGameMode::HandleReactReady);
    Browser->OnEventReceived.AddDynamic(this, &AGameMode::HandleHudEvent);
}

See also

Released under the MIT License.