Introduction
Welcome to the official and comprehensive documentation for MasonUI. This guide serves as an all-in-one resource for developers looking to create powerful, modern, and efficient menus within the FiveM ecosystem.
MasonUI is designed to be both simple for beginners and powerful for advanced users. Whether you're creating a simple settings menu or a complex, data-driven interface, MasonUI provides the tools you need to build it with clean, readable code.
Setup & Core Concepts
1. Installation
First, ensure the masonui resource is placed in your server's resources
directory and properly started in your server.cfg (e.g., ensure masonui).
To enable data-saving features, you must execute the following SQL query on your database.
-- This table stores all player-specific settings for menus with auto-saving enabled.
CREATE TABLE IF NOT EXISTS `masonui_data` (
`identifier` VARCHAR(60) NOT NULL,
`data_key` VARCHAR(100) NOT NULL,
`data_value` TEXT DEFAULT NULL,
PRIMARY KEY (`identifier`, `data_key`)
);2. Dependencies
Make sure MasonUI is loaded before your own resources that use it.
Add it to your fxmanifest.lua as a dependency if needed:
dependency 'masonui'
3. Identifier Setup
MasonUI requires a unique player identifier to save and restore player-specific data.
You can configure which identifier type should be used inside config.lua.
Config = {}
-- Choose your Identifier-Type.
-- Possible options: 'esx', 'license', 'steam', 'discord'
Config.IdentifierType = 'license'
- esx: Uses the ESX internal identifier (
xPlayer.identifier). - license: Uses the Rockstar license key (
license:). - steam: Uses the player's Steam ID (
steam:). - discord: Uses the player's Discord ID (
discord:).
In your client scripts, you can fetch the current identifier via:
-- Client example:
local id = MasonUI.GetIdentifier()
print("My Identifier:", id)
-- Or via export in other resources:
local id = exports["masonui"]:getIdentifier()
print("My Identifier via Export:", id)
4. The Core Concept: Safe Initialization
To prevent script timing issues where your menu resource might try to create a menu before MasonUI is fully loaded, MasonUI uses a registration system. Instead of running your menu creation code directly in a thread, you wrap it in a function and pass it to MasonUI.RegisterMenu.
This guarantees that your code will only execute after the MasonUI framework is ready, eliminating common race condition errors.
-- In your own resource, e.g., my_menus/client.lua
-- IMPORTANT: Ensure your script loads AFTER MasonUI's client scripts.
-- In your resource's fxmanifest.lua:
-- client_scripts {
-- '@masonui/client/main.lua', -- This might not be needed if it's a dependency
-- 'client.lua'
-- }
-- 1. Register a function that contains all your menu creation logic.
MasonUI.RegisterMenu(function()
-- This code is now guaranteed to run safely.
print("MasonUI is loaded. Creating my menus now!")
-- You can create all your menus and items inside this function.
MasonUI.CreateMenu("main", "Main Menu", "banner.png")
MasonUI.AddItem("main", { label = "A simple button" })
-- ... more menus and items
end)
-- 2. Your commands or other logic can be in standard threads.
Citizen.CreateThread(function()
RegisterCommand("menu", function()
-- This function simply opens a menu you've already created.
MasonUI.OpenMenu("main")
end, false)
end)
5. Basic Menu Control Flow
These are the fundamental functions you'll use to control the visibility and navigation of your menus.
-- Opens a menu by its unique ID.
-- If the menu has data to load from the database, it will be fetched automatically on first open.
MasonUI.OpenMenu('settings_menu')
-- Navigates back one level in the menu stack.
-- If the user is at the top-level menu, this will close the UI entirely.
MasonUI.BackMenu()
-- Immediately closes all open menus and the UI.
-- Useful for actions that should terminate the menu interaction completely.
MasonUI.CloseAllMenus()
Item Types & Properties
The type property in the item data table is the most important, as it defines the item's core functionality. If omitted, it defaults to a standard button.
Common Properties
These properties can be applied to almost any item type to modify its state and appearance.
| Property | Type | Description |
|---|---|---|
label | string | (Required) The primary text displayed for the item. |
action | function | A function that executes when the item is clicked (Enter/Return). Not used by all types. |
onchange | function | A function that executes when the item's value changes (e.g., checkbox, slider, list). |
disabled | boolean | If true, the item is grayed out and cannot be selected or interacted with. |
locked | boolean | If true, a lock icon is displayed, and the action is blocked. The item can still be selected. |
decorator | string | Adds a visual element. Use 'submenu' to display a "»" symbol, indicating navigation. |
description | string | Help text shown at the bottom of the menu when the item is highlighted. |
icon | string | An icon to display. If the string starts with 'fa-' (e.g., 'fa-solid fa-car'), it's treated as a FontAwesome icon. Otherwise, it's treated as a path or URL to an image file (e.g., 'my-icon.png'). |
Button
The default and most basic item type. It executes an action when selected.
MasonUI.AddItem('main', {
label = 'Open Settings',
decorator = 'submenu', -- Visual hint that this opens another menu
description = 'Configure your personal in-game settings.',
action = function()
MasonUI.OpenMenu('settings')
end
})
MasonUI.AddItem('main', {
label = 'Show Notification',
icon = 'fa-solid fa-bell',
action = function()
ESX.ShowNotification('This is a test notification!')
end
})Checkbox
A simple on/off toggle. Its state is managed by the checked property. The onchange callback receives the new boolean state.
MasonUI.AddItem('settings', {
type = 'checkbox',
label = 'Enable Minimap',
defaultValue = true, -- The initial state when the menu is first created.
onchange = function(isChecked)
-- Code to show/hide the minimap
DisplayRadar(isChecked)
print("Minimap enabled state is now: " .. tostring(isChecked))
end
})Slider
A slider for selecting a numerical value within a defined range. Use Left/Right arrow keys to adjust. The onchange callback receives the new number value.
MasonUI.AddItem('settings', {
type = 'slider',
label = 'Music Volume',
description = 'Adjust the volume of the in-game background music.',
min = 0, -- (Optional) The minimum value. Defaults to 0.
max = 100, -- (Optional) The maximum value. Defaults to 100.
step = 10, -- (Optional) The increment/decrement amount. Defaults to 1.
defaultValue = 80, -- The initial value of the slider.
onchange = function(newValue)
-- Assume you have a function to set music volume
SetMusicVolume(newValue / 100) -- Convert to 0.0-1.0 scale
end
})List
A selection list that allows the user to cycle through a predefined set of options using Left/Right arrow keys. The onchange callback receives the selected string value.
MasonUI.AddItem('settings', {
type = 'list',
label = 'Crosshair Style',
values = {'Dot', 'Cross', 'Circle', 'Disabled'},
defaultValue = 'Dot', -- Must exactly match one of the strings in the `values` table.
onchange = function(selectedValue)
print("User selected crosshair style: " .. selectedValue)
-- Code to apply the new crosshair style
end
})Keybind
A specialized item for setting and listening to key presses. When the user clicks this item, the UI enters a "listening" state. The next key press is captured and saved as the keybind's value. The onaction function is a global listener that fires whenever the assigned key is pressed, as long as the menu is closed.
MasonUI.AddItem('controls', {
type = 'keybind',
label = 'Toggle Engine',
description = 'The key used to turn your vehicle engine on and off.',
defaultValue = 'G', -- The key to use by default.
onaction = function()
-- This code executes when the 'G' key (or whatever the user sets) is pressed,
-- but only when the MasonUI is NOT open.
print("Engine keybind pressed!")
-- Add your engine toggle logic here
end,
onchange = function(newKey)
ESX.ShowNotification("Engine keybind changed to: " .. newKey)
end
})Placeholder
A non-interactive text label, perfect for creating section titles or separators within a menu.
-- Example of organizing a settings menu with placeholders
MasonUI.AddItem('settings', {
type = 'placeholder',
label = '--- Graphics ---' ,
align = 'center', -- (Optional) Can also be 'left' or 'right'. Default: left
color = 'white' -- (Optional) You can use hex codes (e.g. #fff) or named CSS colors.
})
MasonUI.AddItem('settings', { type = 'slider', label = 'Field of View', ... })
MasonUI.AddItem('settings', { type = 'checkbox', label = 'Show Shadows', ... })
MasonUI.AddItem('settings', {
type = 'placeholder',
label = '--- Audio ---',
align = 'center', -- (Optional) Can also be 'left' or 'right'. Default: left
color = 'white' -- (Optional) You can use hex codes (e.g. #fff) or named CSS colors
})
MasonUI.AddItem('settings', { type = 'slider', label = 'Master Volume', ... })
State Text
A versatile item that functions like a standard button but also includes a dynamic text display on the right side. It's perfect for showing a value that is read-only in the menu but can be changed by other parts of your script, such as current job, cash on hand, or server status. The text is updated using the MasonUI.SetStateValue() function.
MasonUI.AddItem('player_info', {
type = 'stateText',
label = 'Job',
state = 'Unemployed', -- The initial text to display.
description = 'This is your current occupation.',
action = function()
-- Could open a job center menu, for example
print("Player wants to change jobs.")
end
})
-- To update this item's state text from another script:
-- MasonUI.SetStateValue('player_info', 'Job', 'Police Officer')
Progressbar
A visual bar that represents a numerical value within a defined range. Unlike a slider, it cannot be adjusted by the user directly in the menu. It's ideal for displaying dynamic stats like hunger, thirst, experience points, or cooldown timers. Its value must be updated programmatically using the MasonUI.SetProgressValue() function. It can also have an action that fires upon selection.
MasonUI.AddItem('status', {
type = 'progressbar',
label = 'Hunger',
min = 0,
max = 100,
defaultValue = 65,
progressText = '65%', -- (Optional) Text to display inside the bar.
action = function()
-- Example: Eat a snack if the player has one
print("Player wants to eat.")
end
})
-- To update this bar later from another script:
-- MasonUI.SetProgressValue('status', 'Hunger', 75, '75%')
MasonUI Callbacks
Callbacks are a fundamental concept for creating dynamic menus. They allow your client script to request information from the server (e.g., player data, inventory items, configurations from the database) without freezing the user's game. The server completes its task and "calls back" once it has the result.
While MasonUI is standalone, you need a callback system to fetch data from the server. The following example uses our own Callback System very similar to the ESX Callback System.
Client-Side: Requesting Data with Callback.TriggerServerCallback
This function sends a request to the server. It has three main parts:
- Event Name: A unique name the server will listen for (e.g.,
'myResource:getData'). - Callback Function: The function that will be executed after the server has responded. The data sent by the server is passed as arguments to this function.
- Arguments: Any additional data you want to send to the server (e.g., a player ID).
Server-Side: Answering Requests with Callback.RegisterServerCallback
This function registers a "listener" on the server. When a client triggers a callback with the matching event name, the function defined here is executed.
- source: The server ID of the player who sent the request.
- cb (Callback): A function you must call to send the response back to the client.
- args: The additional arguments the client sent with the request.
Important: Unlike ESX, an xPlayer object is not automatically passed here. You work directly with the player's source ID and must manually query player data from the database if needed.
Practical Example: Fetching the "Message of the Day"
Here is a complete example showing how a menu button can retrieve information from the server and display it.
-- Client-Side: A button that triggers the callback
MasonUI.AddItem("main", {
label = "Show Message of the Day",
action = function()
print("[Client] Requesting message from server...")
-- Trigger the callback. We aren't sending any additional arguments.
Callback.TriggerServerCallback('myResource:getMessageOfTheDay', function(message)
-- This code executes after the server responds.
-- 'message' is the value the server sends back via cb().
print("[Client] Response received!")
-- Display the message in a dialog.
MasonUI.OpenInputDialog({
title = "Message of the Day",
placeholder = message,
readOnly = true -- Makes the input field non-editable
}, function()
-- This callback is empty, as we don't need to do anything on "Submit".
end)
end)
end
})
-- Server-Side: The callback handler that provides the message
Callback.RegisterServerCallback('myResource:getMessageOfTheDay', function(source, cb)
-- Log a message in the server console to see that the request arrived.
print(("[Server] Player %s is requesting the message of the day."):format(source))
-- Simulate a database query or get the info from somewhere else.
local message = "Remember to always read the documentation! :)"
-- Send the message back to the client using the `cb` callback function.
cb(message)
end)
Advanced Interactivity
1. Pagination for Long Lists
When you have too many items to fit on one screen, you can enable pagination by setting the itemsPerPage option in CreateMenu. MasonUI will automatically handle page creation, item distribution, and navigation controls (Page Up/Down keys or Left/Right arrow keys on non-interactive items).
-- Create a menu that will show a maximum of 8 items per page.
MasonUI.CreateMenu("player_list", "Online Players", "banner.png", { itemsPerPage = 8 })
-- Let's add 30 items to it. MasonUI will create 4 pages.
-- (Page 1: 8 items, Page 2: 8, Page 3: 8, Page 4: 6)
for i = 1, 30 do
MasonUI.AddItem("player_list", {
label = "Player " .. i,
action = function() print("Selected player " .. i) end
})
end
2. Dynamic & Asynchronous Menus
Menus don't have to be static. You can create or rebuild them on the fly, which is essential when content depends on external data, like a database query or a server callback. A common use case is creating a list of online players.
The key is to call MasonUI.CreateMenu inside the callback of your data-fetching function. This ensures the menu is populated only after the data has been received.
-- In your main menu, create a button that will trigger the process.
MasonUI.AddItem('main', {
label = 'View Online Players',
decorator = 'submenu',
action = function()
ESX.ShowNotification("Fetching player list from server...")
-- 1. Trigger a server callback to get the player data.
Callback.TriggerServerCallback("myResource:getPlayers", function(players)
-- 3. This callback function runs once the server responds with the data.
-- 4. Create (or re-create) the player list menu HERE.
-- This clears any old data from a previous open.
MasonUI.CreateMenu("playerlist", "Online Players", "banner.png")
if not players or #players == 0 then
MasonUI.AddItem("playerlist", { type = 'placeholder', label = "No other players are online." })
else
for _, playerData in ipairs(players) do
MasonUI.AddItem("playerlist", {
label = string.format("[%s] %s", playerData.source, playerData.name),
action = function()
ESX.ShowNotification("You selected " .. playerData.name)
-- You could add admin actions here, e.g., teleport, kick, etc.
end
})
end
end
-- 5. Finally, open the newly populated menu.
MasonUI.OpenMenu("playerlist")
end)
end
})
-- On the server-side (server.lua), you would have something like this:
-- Callback.RegisterServerCallback('myResource:getPlayers', function(source, cb)
-- local players = ESX.GetPlayers()
-- local playerData = {}
-- for i=1, #players do
-- local xPlayer = ESX.GetPlayerFromId(players[i])
-- table.insert(playerData, { name = xPlayer.getName(), source = xPlayer.source })
-- end
-- cb(playerData)
-- end)
3. Programmatic Control (Setters & Getters)
You can dynamically change or retrieve the state of any item after it has been created. This is extremely powerful for creating reactive menus where one setting can affect another. For example, enabling an "Expert Mode" checkbox could automatically disable an "Aim Assist" slider.
Most setter and getter functions come in two variants: one that identifies an item by its unique label (e.g., SetSliderValue), and one that identifies it by its numerical position in the menu's item list (e.g., SetSliderValueByIndex). Using the index is faster and more reliable if item labels are not unique or change dynamically. The index is 1-based (the first item is index 1).
All setter functions return true on success and nil on failure (e.g., if the menu or item doesn't exist).
-- --- List of all available functions ---
--// By Item Label (Convenient but slightly slower) //--
-- Checkbox
MasonUI.SetCheckboxState('menuId', 'itemLabel', true)
local isChecked = MasonUI.GetCheckboxState('menuId', 'itemLabel')
-- Slider
MasonUI.SetSliderValue('menuId', 'itemLabel', 75)
local sliderVal = MasonUI.GetSliderValue('menuId', 'itemLabel')
-- List
MasonUI.SetListValue('menuId', 'itemLabel', 'Option B')
local listVal = MasonUI.GetListValue('menuId', 'itemLabel')
-- Keybind
MasonUI.SetKeybindValue('menuId', 'itemLabel', 'K')
local key = MasonUI.GetKeybindValue('menuId', 'itemLabel')
-- Progressbar
MasonUI.SetProgressValue('menuId', 'itemLabel', 50, '50%')
local progressVal = MasonUI.GetProgressValue('menuId', 'itemLabel')
-- State Text
MasonUI.SetStateValue('menuId', 'itemLabel', 'Connected')
local stateVal = MasonUI.GetStateValue('menuId', 'itemLabel')
-- Placeholder
MasonUI.SetPlaceholderLabel('menuId', 'itemLabel', 'New Title')
-- Generic Item Properties
MasonUI.SetItemDisabled('menuId', 'itemLabel', true)
MasonUI.SetItemLocked('menuId', 'itemLabel', true)
MasonUI.SetItemIcon('menuId', 'itemLabel', 'fa-solid fa-star')
MasonUI.SetItemDescription('menuId', 'itemLabel', 'New description')
local desc = MasonUI.GetItemDescription('menuId', 'itemLabel')
local type = MasonUI.GetItemType('menuId', 'itemLabel') -- returns e.g., 'slider', 'checkbox'
--// By Item Index (Faster, 1-based index) //--
-- Example: Set the second item's description
MasonUI.SetItemDescriptionByIndex('menuId', 2, 'This is the second item.')
-- The following functions all have a 'ByIndex' equivalent:
-- SetCheckboxStateByIndex, GetCheckboxStateByIndex
-- SetSliderValueByIndex, GetSliderValueByIndex
-- SetListValueByIndex, GetListValueByIndex
-- SetKeybindValueByIndex, GetKeybindValueByIndex
-- SetProgressValueByIndex, GetProgressValueByIndex
-- SetStateValueByIndex, GetStateValueByIndex
-- SetItemDisabledByIndex, SetItemLockedByIndex, SetItemIconByIndex
-- SetItemDescriptionByIndex, GetItemDescriptionByIndex
-- GetItemTypeByIndex
--// Menu-wide Functions //--
local currentMenuId = MasonUI.GetCurrentMenu()
local currentSelectionIndex = MasonUI.GetCurrentIndex() -- returns number or nil
-- Remember! Each item you add with ex. MasonUI.AddItem counts into the index!
4. External Menu Navigation
You can simulate user input to navigate the currently open menu from external scripts. This is useful for integrating MasonUI with other input systems or for creating automated sequences. These functions will have no effect if no menu is open.
-- Navigate the menu up or down
MasonUI.MenuUp()
MasonUI.MenuDown()
-- Navigate left or right (e.g., for sliders, lists, or changing pages)
MasonUI.MenuLeft()
MasonUI.MenuRight()
-- Example: Go down 3 items and then right once
Citizen.CreateThread(function()
if MasonUI.GetCurrentMenu() then
MasonUI.MenuDown()
Citizen.Wait(150)
MasonUI.MenuDown()
Citizen.Wait(150)
MasonUI.MenuDown()
Citizen.Wait(150)
MasonUI.MenuRight()
end
end)
5. Item Deletion
For dynamic menus where available options can change during gameplay (e.g., an inventory list), it's often necessary to completely remove items. The MasonUI.RemoveItem() function serves exactly this purpose. It removes a specific item from the menu and updates the view if the menu is currently open.
The function returns true if the item was successfully found and removed, and false (or nil) if the menu or the specified item does not exist.
-- Assuming your inventory menu was initialized like this:
MasonUI.CreateMenu('inventory', 'Inventory')
MasonUI.AddItem('inventory', { label = 'Pistol' })
MasonUI.AddItem('inventory', { label = 'First Aid Kit' })
-- Now, a player wants to sell the pistol. After a successful transaction,
-- remove the item from the menu:
local success = MasonUI.RemoveItem('inventory', 'Pistol')
if success then
print('Pistol was removed from the menu.')
else
print('Could not find Pistol in the menu.')
end
6. Advanced Manipulation & State Control
Beyond simple getters and setters, these functions provide deeper programmatic control over the menu's structure, state, and user focus, enabling highly dynamic and responsive interfaces.
MasonUI.IsMenuOpen
A simple but essential boolean function that returns true if any MasonUI menu is currently visible on the screen, and false otherwise. This is crucial for preventing conflicts with other scripts, such as custom HUDs or other input systems.
-- In a script that manages a custom HUD
Citizen.CreateThread(function()
while true do
Citizen.Wait(500)
-- Only draw the HUD if MasonUI is not open
if not exports.masonui:IsMenuOpen() then
DrawCustomHudElements()
end
end
end)
MasonUI.ClearMenu
Removes all items from a specified menu, leaving it empty. This is more efficient and explicit than re-creating a menu with CreateMenu if you only need to clear its contents before repopulating it with fresh data.
-- Function to refresh a list of vehicles for sale
function RefreshVehicleList()
-- Clear out the old list first
MasonUI.ClearMenu('vehicle_shop')
-- Fetch new data and repopulate
Callback.TriggerServerCallback('getVehicles', function(vehicles)
for _, vehicle in ipairs(vehicles) do
MasonUI.AddItem('vehicle_shop', { label = vehicle.name, ... })
end
end)
end
MasonUI.RemoveItemByIndex
Removes an item from a menu based on its numerical position (1-based index) rather than its label. This is useful for managing menus where items might not have unique labels or are easier to track by their position.
-- Removes the very first item from the 'inventory' menu
local success = MasonUI.RemoveItemByIndex('inventory', 1)
if success then
print("First inventory slot cleared.")
endMasonUI.InsertItem
Adds a new item to a menu at a specific numerical position (1-based index), pushing all subsequent items down by one. This allows for precise control over the order of items, rather than always adding to the end.
-- An important server announcement arrives
local announcement = {
type = 'placeholder',
label = 'SERVER RESTART IN 5 MINS',
color = '#ff4757'
}
-- Insert this announcement at the very top of the main menu (position 1)
MasonUI.InsertItem('main_menu', announcement, 1)
MasonUI.SetFocus
Programmatically sets the user's focus (the highlighted item) to a specific item index within the currently open menu. If the target item is on a different page, the menu will automatically switch to that page. The function returns false if the menu isn't open or the index is invalid (e.g., a placeholder).
-- When a player buys an item, re-open the shop and focus on the next item
local lastBoughtItemIndex = 4
MasonUI.OpenMenu('item_shop')
-- Set focus to the item right after the one they just bought
MasonUI.SetFocus('item_shop', lastBoughtItemIndex + 1)
7. Event System & Advanced Navigation
For truly dynamic and decoupled code, MasonUI provides an event system and advanced navigation functions. This allows you to react to menu state changes globally and control the user's navigation flow with more precision.
Event System: MasonUI.on & MasonUI.off
The event system allows you to register listener functions ("callbacks") that are executed whenever a global menu event occurs. This is powerful for centralizing logic that would otherwise need to be repeated in many places (e.g., playing sounds, managing third-party UIs).
-- Available Events:
-- 'menuOpen': Fires when any menu is opened.
-- - Callback receives: menuId (string)
-- 'menuClose': Fires when the last menu is closed and the UI becomes hidden.
-- - Callback receives: no arguments
-- 'selectionChange': Fires when the user highlights a different item.
-- - Callback receives: menuId (string), newItemIndex (number), newItemData (table)
-- Example: Centralized UI management
local function onMenuOpen(menuId)
PlaySoundFrontend(-1, "SELECT", "HUD_FRONTEND_DEFAULT_SOUNDSET", true)
print("Opened menu: " .. menuId)
end
MasonUI.on('menuOpen', onMenuOpen)
MasonUI.on('menuClose', function()
PlaySoundFrontend(-1, "BACK", "HUD_FRONTEND_DEFAULT_SOUNDSET", true)
end)
MasonUI.on('selectionChange', function(menuId, index, item)
print(string.format("Selection in '%s' changed to #%d ('%s')", menuId, index, item.label))
end)
-- To remove a listener later:
-- MasonUI.off('menuOpen', onMenuOpen)
Advanced Navigation: JumpToMenu & GetMenuStack
These functions give you more control over the menu navigation stack than a simple BackMenu() call.
- GetMenuStack(): Returns a table containing the IDs of all currently open menus, from the base menu to the one currently visible. Useful for debugging or context-aware logic.
- JumpToMenu(menuId): Navigates backward through the stack until it finds the specified
menuId, effectively closing all menus on top of it. This is ideal for a "Return to Main Menu" button deep inside a nested structure.
-- In a deeply nested menu (e.g., main -> settings -> graphics -> advanced)
MasonUI.AddItem('advanced_graphics', {
label = '<< Return to Main Menu',
description = 'Skips intermediate menus and returns to the start.',
action = function()
-- Get the current navigation path for debugging
local stack = MasonUI.GetMenuStack()
print('Current path was: ' .. table.concat(stack, ' -> ')) -- e.g., "main -> settings -> graphics -> advanced_graphics"
-- Jump directly back to the 'main' menu
MasonUI.JumpToMenu('main')
end
})
MasonUI.RefreshMenu
Forces the currently open menu to redraw its user interface. This is the ideal function to call after you have programmatically altered the contents of the current menu (e.g., after using ClearMenu, AddItem, or RemoveItem) to make the changes immediately visible to the user without disrupting the navigation history.
-- Example: Refreshing a dynamic list after fetching new data.
local function refreshPlayerList()
-- 1. Clear all old items from the currently open menu.
MasonUI.ClearMenu('player_list')
-- 2. Add the new, updated items.
local newPlayers = {'PlayerA', 'PlayerB', 'PlayerC'} -- Simulate new data
for _, name in ipairs(newPlayers) do
MasonUI.AddItem('player_list', { label = name })
end
-- 3. Call RefreshMenu to display the changes instantly.
MasonUI.RefreshMenu()
ESX.ShowNotification("Player list has been updated!")
end
Item Templating & Components
To reduce code repetition and improve maintainability, especially in complex lists (like player lists, shops, or garages), MasonUI includes a powerful templating system. You can define the structure and behavior of an item once and then reuse it multiple times with different data.
1. Registering a Template
First, you define a template using MasonUI.RegisterTemplate(). This is typically done once when your script initializes. The template is a standard item data table, but you can use placeholders in the format {{key}} for values that will be filled in later.
-- In your menu registration, define a reusable template for a player list item.
MasonUI.RegisterTemplate('player_list_item', {
type = 'stateText',
label = '[{{source}}] {{name}}', -- Placeholders for dynamic data
state = 'Job: {{job}}',
icon = 'fa-solid fa-user',
description = 'Click for admin actions on this player.',
action = function(data, ...)
-- The 'data' table passed to AddItem is automatically given to the action.
-- Now you have access to all of the player's data inside the action.
print('Selected player with source ID: ' .. data.source)
OpenAdminActionsForPlayer(data)
end
})
2. Using a Template
To use a template, you call MasonUI.AddItem (or InsertItem) with a special structure. The template property specifies which registered template to use, and the data property is a table containing the values to fill in the placeholders.
You can also override any property from the template by simply defining it in the AddItem call. For example, you could add a unique icon for a specific player to override the one from the template.
-- Now, use the template to build a dynamic player list
Callback.TriggerServerCallback('myResource:getPlayers', function(players)
MasonUI.CreateMenu("player_list", "Online Players")
for _, playerData in ipairs(players) do
-- For each player, add an item using the template
MasonUI.AddItem('player_list', {
template = 'player_list_item', -- The name of the template to use
data = playerData -- This table provides the values for {{source}}, {{name}}, etc.
})
end
MasonUI.OpenMenu('player_list')
end)
-- Example playerData table from the server:
-- { source = 1, name = 'John Doe', job = 'Police' }
Dialogs & Modals
For interactions that require focused user input, MasonUI provides modal dialogs that temporarily pause menu navigation.
Text Input Dialog
Use MasonUI.OpenInputDialog to prompt the user for text input. This is ideal for things like entering an amount, a name, or a reason. You can also customize the text of the submit and cancel buttons.
MasonUI.AddItem('actions', {
label = 'Withdraw Money',
action = function()
MasonUI.OpenInputDialog({
title = 'Withdraw Amount',
placeholder = 'e.g., 500', -- Optional placeholder text
submitText = 'Confirm', -- (Optional) Custom text for the submit button
cancelText = 'Abort' -- (Optional) Custom text for the cancel button
}, function(text)
-- This callback function is executed when the user submits or cancels.
if text then
-- User clicked "Confirm". `text` contains their input.
local amount = tonumber(text)
if amount and amount > 0 then
ESX.ShowNotification("Attempting to withdraw $" .. amount)
-- Trigger server event to handle withdrawal
else
ESX.ShowNotification("Invalid amount entered.")
end
else
-- User clicked "Abort" or pressed Escape. `text` is nil.
ESX.ShowNotification("Withdrawal cancelled.")
end
end)
end
})Programmatic Control of Input Dialogs
For automated processes or integration with other systems, you can control an open input dialog programmatically. These functions will only work if an input dialog is currently open.
- SetInputDialogValue(text): Sets or changes the text currently in the input field.
- SubmitInputDialog(): Simulates a click on the submit button, firing the callback with the current value of the input field.
- CloseInputDialog(): Simulates a click on the cancel button, firing the callback with a
nilvalue.
-- This example shows how to open a dialog and control it via code after a delay.
MasonUI.AddItem('actions', {
label = 'Run Automated Input Test',
action = function()
ESX.ShowNotification("Opening dialog for automated test...")
MasonUI.OpenInputDialog({ title = 'Automated Input' }, function(text)
-- This callback will be fired by SubmitInputDialog or CloseInputDialog below.
ESX.ShowNotification("Dialog callback received: " .. (text or "nil"))
end)
-- Start a thread to control the dialog after it opens
Citizen.CreateThread(function()
Citizen.Wait(2000) -- Wait 2 seconds
ESX.ShowNotification("Setting input value programmatically...")
MasonUI.SetInputDialogValue("This is automated text!")
Citizen.Wait(2000) -- Wait another 2 seconds
ESX.ShowNotification("Submitting dialog programmatically...")
MasonUI.SubmitInputDialog()
end)
end
})
Confirmation Dialog
Use MasonUI.ShowConfirmation to quickly ask the user a "Yes/No" question without having to manually build a new menu. This is a convenient wrapper that creates a temporary, two-button menu.
MasonUI.AddItem('admin', {
label = 'Kick Player',
action = function()
-- Assume `targetPlayer` is defined elsewhere
local targetPlayer = { name = 'SomePlayer' }
MasonUI.ShowConfirmation({
banner = "banner.png", -- Optional
title = "Confirm Kick",
text = "Are you sure you want to kick " .. targetPlayer.name .. "?" -- Optional text
}, function(confirmed)
-- This callback receives `true` if "Yes" was clicked, and `false` if "No" was clicked.
if confirmed then
ESX.ShowNotification("Kicking player...")
-- Trigger server event to kick the player
else
ESX.ShowNotification("Kick action cancelled.")
end
end)
end
})Data Persistence (Auto-Saving)
MasonUI includes a seamless system for automatically saving player settings to the database. This is perfect for any user preference that should persist across game sessions, such as theme choice, keybinds, or gameplay settings.
How It Works
The system is designed to be incredibly simple to implement. It requires just two steps:
- Set a
db_prefixon your menu: This unique prefix acts as a namespace or category for all savable settings within that menu. It prevents key collisions with other menus. - Add
saveValue = trueto an item: Flag any Checkbox, Slider, List, or Keybind item that you want to be saved automatically.
Behind the Scenes: When a user changes a flagged item, its value is immediately saved to the masonui_data table. The database key is automatically generated from your prefix and the item's sanitized label (e.g., player_theme_color-scheme). When the resource starts and the menu is first opened, these values are automatically fetched and applied, overriding the defaultValue in your code.
Complete Example
Here is a complete settings menu where all options are saved for the player.
-- 1. In CreateMenu, define the unique database prefix for this menu.
MasonUI.CreateMenu("persistent_settings", "My Saved Settings", "banner.png", {
db_prefix = "my_player_settings"
})
-- 2. Add `saveValue = true` to every item you want to persist.
-- Checkbox example
MasonUI.AddItem("persistent_settings", {
type = "checkbox",
label = "Enable GPS Voice",
saveValue = true, -- This setting will be saved.
defaultValue = true
})
-- Slider example
MasonUI.AddItem("persistent_settings", {
type = "slider",
label = "Field of View",
saveValue = true, -- This setting will be saved.
defaultValue = 90,
min = 70,
max = 120
})
-- List example
MasonUI.AddItem("persistent_settings", {
type = "list",
label = "HUD Style",
saveValue = true, -- This setting will be saved.
defaultValue = "Standard",
values = {"Standard", "Compact", "Hidden"}
})
-- Keybind example
MasonUI.AddItem("persistent_settings", {
type = "keybind",
label = "Interaction Key",
saveValue = true, -- This setting will be saved.
defaultValue = "E",
onaction = function()
-- This action will use the saved key
print("Interaction key pressed!")
end
})
-- State Text example (Basically an button with a text next to it)
MasonUI.AddItem("info_menu", {
type = "stateText",
label = "Godmode:",
state = "On",
action = function()
local state = MasonUI.GetStateValue("info_menu", "Godmode:")
if state == "On" then
MasonUI.SetStateValue("info_menu", "Godmode:", "Off")
else
MasonUI.SetStateValue("info_menu", "Godmode:", "On")
end
end
})
Theming & Customization
You can dynamically change the menu's accent color and on-screen position at any time using the SetTheme function. This allows for real-time customization, giving players control over their experience.
This is often combined with the auto-saving system to make a player's theme choice persistent.
The 'SetTheme' Function
This function accepts a table with one or more of the following keys:
position: A string, either'left'or'right'.verticalPosition: A string, either'top''middle'or'bottom'.primary_color_start: A string containing a hex color code for the start of the gradient on selected items.primary_color_end: A string containing a hex color code for the end of the gradient.
Example: A Theme Customization Menu
This example demonstrates how to create a "Theme" submenu where players can change the position and color scheme, and their choices are saved automatically.
-- Create the theme menu with a database prefix.
MasonUI.CreateMenu("theme", "Customize Design", "banner.png", { db_prefix = "player_theme" })
-- Item to control the menu's position on the screen.
MasonUI.AddItem("theme", {
type = "list",
label = "Position",
saveValue = true,
defaultValue = "Left",
values = {"Left", "Right"},
onchange = function(value)
-- The value from the list is "Left" or "Right".
-- The SetTheme function expects "left" or "right" (lowercase).
MasonUI.SetTheme({ position = string.lower(value) })
end
})
-- Item to control the color scheme.
MasonUI.AddItem("theme", {
type = "list",
label = "Color Scheme",
saveValue = true,
defaultValue = "Purple",
values = {"Purple", "Blue", "Green"},
onchange = function(value)
if value == "Blue" then
MasonUI.SetTheme({ primary_color_start = "#007bff", primary_color_end = "#0056b3" })
elseif value == "Green" then
MasonUI.SetTheme({ primary_color_start = "#28a745", primary_color_end = "#1e7e34" })
else -- Default to Purple
MasonUI.SetTheme({ primary_color_start = "#8A2BE2", primary_color_end = "#4B0082" })
end
end
})
-- IMPORTANT: To apply the saved theme when the game loads, you need to
-- fetch and apply the settings when your script starts.
-- This code should be placed where your menus are registered.
local function applyInitialTheme()
-- Wait a moment to ensure the UI is ready.
Citizen.Wait(500)
if not ESX.IsPlayerLoaded() then return end
local playerIdentifier = ESX.GetPlayerData().identifier
if not playerIdentifier then return end
-- Use the generic data fetcher to get all saved data for this player.
ESX.TriggerServerCallback('masonui:getAllPlayerData', function(settings)
if not settings then return end
-- Apply position (defaulting to "Left")
local position = settings['player_theme_position'] or "Left"
MasonUI.SetTheme({ position = (position == "Left" and "left" or "right") })
Citizen.Wait(50) -- Small delay between NUI messages
-- Apply color scheme (defaulting to "Purple")
local color = settings['player_theme_color-scheme'] or "Purple"
if color == "Blue" then
MasonUI.SetTheme({ primary_color_start = "#007bff", primary_color_end = "#0056b3" })
elseif color == "Green" then
MasonUI.SetTheme({ primary_color_start = "#28a745", primary_color_end = "#1e7e34" })
else
MasonUI.SetTheme({ primary_color_start = "#8A2BE2", primary_color_end = "#4B0082" })
end
end, playerIdentifier)
end
-- Create a thread to run this function after the resource starts.
Citizen.CreateThread(applyInitialTheme)
Help & Troubleshooting
Even with the best documentation, sometimes things go wrong. This section provides solutions to common problems and tells you where to get more help.
Getting Community Support
The fastest way to get help is to join our community Discord server. Here, you can ask questions, share your creations, and get support from both the development team and other users. Please be prepared to share your code and any console errors you are receiving.
Join our Discord: Soon!
Common Issues & FAQ
Q: My settings aren't saving! What's wrong?
This is the most common issue and is almost always caused by a setup problem. Go through this checklist step-by-step:
-
1. Did you run the SQL script? The auto-saving system requires a specific table in your database called
masonui_data. If this table doesn't exist, the server-side script will fail silently. You can find the script in the Setup section. -
2. Did you set a
db_prefixon the menu? Every menu that contains savable items must have a uniquedb_prefixset in its options table during creation.-- CORRECT: db_prefix is set MasonUI.CreateMenu("settings", "Settings", "banner.png", { db_prefix = "my_unique_settings" }) -
3. Did you add
saveValue = trueto the item itself? You must explicitly tell each item that it should be saved.-- CORRECT: saveValue is true MasonUI.AddItem("settings", { type = "checkbox", label = "Enable Something", saveValue = true, -- This is required! defaultValue = true }) - 4. Are there any errors in your server console? Open your F8 console and your main server console. Look for any errors related to "masonui" or database access, which can give you a clue as to what is failing.
Q: My png banner image is not showing up.
This happens for one of two reasons:
-
The file is not included in the masonui resource manifest. Any custom assets you use (like images or fonts) must be explicitly listed in the masonui resource's
fxmanifest.luafile in thefilessection, normally all png files inside html/*.png should be automatically defined.-- in masonui/fxmanifest.lua files { 'html/index.html', 'html/my_banner.png', -- Your banner MUST be listed here! } -
The path is incorrect. The path you provide in
MasonUI.CreateMenuis relative to the root of the masonui HTML folder (usually justbanner.pngas an example). If your banner is atmasonui/html/images/banner.png, the path should be'images/banner.png', but remember it has to be defined in the fxmanifest.lua of masonui.
Q: I get an error like "attempt to index a nil value (global MasonUI)".
This is a script load order issue. It means your script is trying to use the MasonUI object before the MasonUI resource has finished loading it.
The solution is to use the built-in registration system, which guarantees your code only runs after MasonUI is ready.
-- WRONG - This might fail if this script loads too fast
Citizen.CreateThread(function()
MasonUI.CreateMenu("main", "My Menu") -- MasonUI might be nil here
end)
-- CORRECT - This is the safe and recommended way
MasonUI.RegisterMenu(function()
-- This code is guaranteed to run only after MasonUI is ready.
MasonUI.CreateMenu("main", "My Menu")
end)
Also, double-check your fxmanifest.lua to ensure you have set up a dependency on MasonUI or that you are loading its client scripts correctly before your own.
Q: The `onaction` for my keybind item doesn't work when I press the key.
This is a common misunderstanding of how keybinds work. The onaction function is designed to be a global hotkey that works only when the menu is closed. It allows players to set a key in the menu and then use it during normal gameplay.
- If you want something to happen when the key is pressed while the game is running and the menu is closed, use
onaction. - If you want something to happen when the user clicks "Enter" on the keybind item inside the menu, you would normally use the
actionproperty. However, for a keybind item, its default action is to start "listening" for a new key. A customactionis not typically used on this item type.
Advanced Troubleshooting
Q: My menu opens, but it's empty or missing items.
Symptom: The UI appears with the correct title and banner, but the item list is empty.
- Cause 1: Incorrect Menu ID. You might be adding items to a different menu ID than the one you are opening. Item labels and menu IDs are case-sensitive.
MasonUI.CreateMenu("MyMenu", "My Menu") -- Capital 'M' MasonUI.AddItem("mymenu", { label = "An item" }) -- Lowercase 'm'. This item will not appear. MasonUI.OpenMenu("MyMenu") -- Opens the empty menu. - Cause 2: Dynamic Menu Logic Failure. If you are creating a menu from a server callback (like a player list), the callback might be returning
nilor an empty table. Addprint()statements inside your callback to debug the data you receive from the server before you create the items.ESX.TriggerServerCallback("myResource:getData", function(data) print("Data received from server:", json.encode(data)) -- Debug the received data! if not data or #data == 0 then print("Data is nil or empty, showing a placeholder.") MasonUI.CreateMenu("my_dynamic_menu", "List") MasonUI.AddItem("my_dynamic_menu", { type = "placeholder", label = "Nothing to show." }) else -- ... create items from data end MasonUI.OpenMenu("my_dynamic_menu") end)
Q: A `Get...` function like `GetCheckboxState` is returning `nil`.
Symptom: You try to programmatically get an item's state, but the function returns `nil` instead of the expected value (e.g., `true`/`false`).
- Cause: Exact Match Required. The
menuIdanditemLabelyou provide to the getter function must be an exact, case-sensitive match for the strings used when creating the menu and item. A single character difference will cause it to fail.MasonUI.AddItem("settings", { type = "checkbox", label = "Enable HUD" }) -- ... -- This will return nil because of the case difference in "Hud" local state = MasonUI.GetCheckboxState("settings", "Enable Hud") -- This is correct local state = MasonUI.GetCheckboxState("settings", "Enable HUD")
Q: My menu controls (Up/Down/Enter) don't work or stop working.
Symptom: The menu is visible on screen, but pressing keys does nothing. You can't navigate or select.
- Cause: A Conflicting Script. This is a classic FiveM issue. Another resource may be running a loop (a
while true dothread) that constantly disables the same controls MasonUI needs. Scripts for things like custom HUDs, cinematic modes, or other UI systems are common culprits.
Solution: You need to identify the conflicting script. Try disabling your other resources one by one until the menu controls start working again. Once you find the conflicting script, you'll need to edit it to not disable controls when your menu is open. You can use an export from your menu script to tell other scripts when MasonUI is active.
Q: A submenu button shows the arrow but doesn't open anything.
Symptom: You added decorator = 'submenu' to an item, but clicking it has no effect.
- Cause: Missing
actionFunction. Thedecoratorproperty is purely a visual hint for the user. It does not add any functionality. You must still provide anactionfunction that explicitly callsMasonUI.OpenMenu()with the ID of your submenu.-- This is just a visual hint, it does nothing by itself. MasonUI.AddItem("main", { label = "Settings", decorator = "submenu" }) -- CORRECT: You must also provide the action to open the next menu. MasonUI.AddItem("main", { label = "Settings", decorator = "submenu", action = function() MasonUI.OpenMenu("settings_menu") -- This part is required! end })