How to Build a FiveM NUI HUD with Lua and React

FiveM NUI lets a resource use web technology—HTML, CSS and JavaScript—to render an in-game interface. That makes React a good fit for a component-heavy HUD, but the browser is only one part of the system. A reliable HUD needs a clear contract between the Lua resource, the NUI page and the server-side logic.
This guide shows the architecture without pretending that a frontend framework solves game-state or security problems for you.
The three layers of a NUI HUD
Think of the resource as three connected layers:
- FiveM client Lua: reads local game state and sends UI updates;
- NUI browser: renders the interface and handles user input;
- server Lua: validates permissions and state-changing actions.
The browser should not decide whether a player owns a vehicle or can use an admin action. It should request an action and display the result.
1. Configure the resource manifest
The resource needs an fxmanifest.lua that points to the built UI page and includes the files the page imports. A minimal shape looks like this:
fx_version 'cerulean'
game 'gta5'
ui_page 'web/dist/index.html'
files {
'web/dist/index.html',
'web/dist/**/*'
}
client_script 'client/main.lua'
Cfx.re's manifest documentation notes that a file-based ui_page and its dependencies must be included in the resource packfile. The cerulean FX version also uses the secure https://cfx-nui-... resource scope for browser assets. Read the manifest reference.
2. Send data from Lua to React
Lua can send a JSON-encodable message to the current NUI page:
SendNUIMessage({
action = 'hud:updatePlayer',
data = {
health = 87,
armor = 50,
talking = false
}
})
React listens for the browser message and updates state:
useEffect(() => {
const onMessage = (event: MessageEvent) => {
if (event.data?.action !== "hud:updatePlayer") return;
setPlayerData((current) => ({ ...current, ...event.data.data }));
};
window.addEventListener("message", onMessage);
return () => window.removeEventListener("message", onMessage);
}, []);
Keep message names namespaced and payloads small. Sending one complete payload when values change is easier to reason about than many unrelated messages that update the same component from different paths.
3. Send requests from React back to Lua
The browser can call a NUI callback with fetch:
await fetch(`https://${GetParentResourceName()}/hud:closeSettings`, {
method: "POST",
headers: { "Content-Type": "application/json; charset=UTF-8" },
body: JSON.stringify({})
});
The client script must register the matching callback and answer every request:
RegisterNUICallback('hud:closeSettings', function(_, cb)
closeSettings()
cb({ ok = true })
end)
Cfx.re's NUI callback documentation is explicit: the callback response is returned to the UI, and every code path should call cb, even when the response is only an empty object. Otherwise the browser request can time out. Read the NUI callback docs.
4. Keep UI state separate from game state
React state answers “what should be rendered?” It should not become a second source of truth for money, inventory, vehicle ownership or permissions. For display-only values, a client payload is enough. For actions that change the game, use a request flow:
- the player clicks a UI control;
- NUI sends a request to the client script;
- client sends a named server request;
- server validates source, permissions, ownership and arguments;
- server returns a result;
- client sends the result to NUI.
That separation keeps the UI responsive while preserving server authority.
5. Make the layout responsive
Design against a reference viewport, but store positions in a normalised or design-space coordinate system. On a different resolution, resolve the stored position against the current viewport. Avoid hard-coding one set of pixel coordinates and calling the UI responsive.
Test at 1280×720, 1920×1080, ultrawide and 4K. Check safe areas, text truncation, scale limits and whether a draggable element can be recovered with a restore-default action.
Common NUI problems
Blank page: check ui_page, the files glob, built asset paths and the F8 console. Cfx.re exposes NUI developer tools while the game is running.
Click does nothing: verify the exact callback name, the resource name returned by GetParentResourceName, and whether the Lua handler calls cb.
UI updates but feels slow: avoid sending unchanged payloads and inspect browser work in NUI devtools before adding more animation.
A button changes sensitive state locally: move the actual authority to the server and treat the button payload as untrusted input.
Why React can be worth it
React is useful when the HUD has reusable modules, settings screens, derived display states and multiple layout modes. It is not automatically faster than vanilla HTML, and the build output must still be bundled correctly into the resource. Choose it for maintainability and component structure, not because a framework name sounds premium.
Zloma HUD uses a React NUI with modular player, vehicle, weapon, radio, settings and layout components while the FiveM resource remains responsible for game integration. You can see the finished approach in the Zloma Scripts catalogue.
Final takeaway
Build the message contract first, keep the UI focused on rendering, answer every callback, and leave sensitive decisions to the server. That architecture scales from a small status widget to a complete, configurable FiveM HUD.
Keep learning
FiveM HUD Guide: What Matters for a Modern Roleplay Server
Learn which FiveM HUD features matter, how to avoid clutter and performance problems, and what to check before choosing a HUD for your roleplay server.
FiveM SecurityFiveM Client vs. Server Events: How to Secure UI Actions
Understand why FiveM clients cannot be trusted, how to validate network events, and how to secure NUI actions involving permissions, inventory, money and vehicles.
FiveM PerformanceFiveM HUD Performance: Update Loops, NUI Messages and Optimization
Learn how to optimize a FiveM HUD with sensible update intervals, change-only NUI messages, cached values and practical client performance testing.
Build a better server experience
Need a production-ready FiveM resource?
Explore Zloma Scripts for practical resources with clean interfaces, framework compatibility, and documentation you can actually use.
Browse Zloma Scripts