Skip to content

Lua API ​

Everything below is tm.ui, loaded on first use and running inside your resource (@tm_lib/init.lua in your manifest). Client only.

tm.ui ​

FunctionReturnsNotes
tm.ui.window(schema, listeners?)window handleOpens a window. Re-using an id replaces that window. listeners is an optional `{ event = fn
tm.ui.get(id)handle or nilLook up an open window.
tm.ui.isOpen(id?)booleanWith an id: is that window open. Without: is any open.
tm.ui.closeAll()Closes every window from this resource.
tm.ui.confirm(opts)booleanYes/no. true only when confirmed.
tm.ui.alert(opts)Message with an OK button. Blocks until dismissed.
tm.ui.prompt(opts)values or nilA form. nil when cancelled.
tm.ui.input(title, label?, opts?)string or nilOne text field.
tm.ui.menu(opts)window handleNested menu. See menus.

confirm ​

lua
local ok = tm.ui.confirm({
    title = 'Delete vehicle?', text = 'This cannot be undone.',
    confirm = 'Delete', cancel = 'Keep', danger = true,   -- danger: red tone + red button
})

prompt ​

lua
local values = tm.ui.prompt({
    title = 'Transfer', icon = 'lucide:send', submit = 'Send',
    fields = {
        { type = 'number', path = 'amount', label = 'Amount', min = 1, rules = { required = true, min = 1 } },
        { type = 'input', path = 'note', label = 'Note' },
    },
})

Options: title, text (muted line above the fields), icon, fields, values (initial), submit, cancel, width.

input ​

lua
local name = tm.ui.input('Rename', 'New name', { required = true, placeholder = 'Name', default = 'Old', multiline = false })

Window handle ​

Returned by tm.ui.window and tm.ui.menu.

Listening ​

Method
win:on(event, fn)Add a listener. Several per event are allowed. fn(data, eventName).
win:once(event, fn)Like on, removed after the first call.
win:off(event, fn?)Remove one listener, or all listeners for the event.
win:onClick(event, fn)Same as on; reads better for buttons.
win:onChange(path, fn)Field changes: fn({ path, value, old }). The field needs notify = true.
win:onAny(fn)Every event from this window.

All of these return the handle, so calls chain. Payloads and event names: events.

Values and nodes ​

Method
win:set(path, value) / win:set({ [path] = value })Change field values. Alias: win:setModel.
win:get(path)Last known value (updated by change events and on submit).
win:getValues()Copy of all last-known values.
win:setNode(nodeId, props)Merge props into the node with that id (text, label, disabled, options, items, ...).
win:update(schema)Re-render from a fresh schema, same id and listeners, no flicker. Field values reset to the new schema's.
win.values, win.id, win.closedPlain fields.

Several set / setNode calls in the same tick are merged into one message to the UI.

Lifecycle ​

Method
win:wait()Block until submit (returns values) or close (returns nil).
win:close()Close from Lua. Does not fire the close event (that is for player dismissal).
win:setFocus(on)Give NUI focus back to the game and take it again, e.g. around a progress bar.

Window options that affect Lua ​

Schema fieldEffect
focus = falseDon't take NUI focus (display-only window). Combine with passive = true for ambient overlays (hint cards, HUD panels): they ignore the mouse and Escape.
keys = trueForward keydown / keyup events. See events.
closable = falseEscape and the X do nothing.

LuaLS annotations ​

The files under client/ carry ---@class / ---@param annotations, so lua-language-server can autocomplete the handle methods and the menu option fields (add ui/client to your workspace library).