NUI basics: building interfaces for FiveM

11 min read6 sections · 5 questions answered
Short answer

Declare a page with ui_page and list its files under files in the fxmanifest. Lua sends data with SendNUIMessage({...}), which arrives in the page as a message event with the table in event.data. The page talks back through NUI callbacks (fetch to https://<resource>/<name>), and SetNuiFocus gives it keyboard and mouse. Files are addressed as https://cfx-nui-<resource>/path.

Every modern FiveM interface — inventories, phones, HUDs, menus, loading screens — is a web page. FiveM embeds a Chromium browser (CEF) on top of the game, and each resource can show its own page there. That page is called NUI. If you can write HTML, CSS and JavaScript, you can build FiveM UI.

Declaring the page

fxmanifest.lua
fx_version 'cerulean'
game 'gta5'

ui_page 'html/index.html'

files {
    'html/index.html',
    'html/style.css',
    'html/app.js',
    'html/img/*.png',
}

client_script 'client.lua'

Every file the page loads must be listed in files, or it is not sent to players and the browser gets a 404. Wildcards work. A built React/Vite app is listed the same way — see React and Vite.

Sending data to the page

client.lua
RegisterCommand('bank', function()
    SendNUIMessage({ action = 'open', balance = 12500 })
    SetNuiFocus(true, true)
end, false)
html/app.js
window.addEventListener('message', (event) => {
  const msg = event.data;
  if (msg.action === 'open') {
    document.querySelector('#balance').textContent = '$' + msg.balance;
    document.body.classList.add('open');
  }
});

The Lua table is converted to JSON and arrives as a plain JavaScript object. Use one field (like action) to route messages.

Talking back to Lua

The page answers with a POST request to its resource; Lua handles it with RegisterNuiCallback. Full details and a reusable helper: NUI callbacks with fetch. Keyboard and mouse control: NUI focus and cursor.

Asset URLs

ReferenceUse
img/logo.png (relative)Files in your own resource
https://cfx-nui-ox_inventory/web/images/water.pngFiles from another resource
nui://resource/pathOlder scheme, deprecated — prefer cfx-nui
https://…External hosting (CDN, remote images)

NUI page vs loading screen

`ui_page``loadscreen`
ShownIn game, whenever you display itWhile the player joins
Talks to LuaMessages and callbacksOnly receives loading events and handover data
FocusSetNuiFocusloadscreen_cursor for the mouse

Loading screens are covered in the HTML loading screen tutorial.

Plain HTML or a framework?

Plain HTML and JavaScript are perfect for small UIs. For inventories, phones or anything with lots of state, a framework (React, Vue, Svelte) built to static files keeps the code manageable. Either way the result is static files in files — nothing runs on a Node server.

Common questions

What is NUI in FiveM?

The in-game web layer: each resource can show an HTML page, rendered by embedded Chromium over the game.

Why does my NUI page not show?

Common causes: ui_page path wrong, files missing from files, the resource not restarted, or the page hidden by CSS. Check the devtools console.

How do I send data from Lua to NUI?

Call SendNUIMessage({...}) and listen for the message event in the page; the table arrives as event.data.

Can I use React for FiveM NUI?

Yes. Build it to static files, point ui_page at the built index.html and list the build output in files.

How do I load an image from another resource?

Use https://cfx-nui-<resource>/<path> — the file must be in that resource’s files.

Want a loading screen you never have to debug?

Build it in the browser, export once, and edit it whenever — no HTML, no re-uploads.

Start free

More guides