Categories, submenus and checkboxes
Create categories and nested submenus, use separators, remembered checkboxes, emote shortcuts and the generated weather menu.
Goal: organise the menu in categories and add stateful options.
File to edit: config_interactions.lua.
Categories and submenus
A category is a type = 'category' option that opens a submenu named by opens. Attached options declare that name in menu:
{ name = 'police', label = 'Police', icon = 'fa-solid fa-shield', type = 'category', opens = 'police_menu', jobs = { 'police' } },
{ name = 'cuff', menu = 'police_menu', label = 'Cuff', icon = 'fa-solid fa-handcuffs', type = 'client_event', event = 'my_pd:cuff' },
{ name = 'escort', menu = 'police_menu', label = 'Escort', icon = 'fa-solid fa-person-walking', type = 'client_event', event = 'my_pd:escort' },
my_pd:cuff and my_pd:escort are example names.
Expected result: the main menu shows “Police” with an arrow; a click opens a second panel on the right containing “Cuff” and “Escort”. The main menu stays visible and clickable.
Observed rules:
- Without
opens, a category opens the menu named after its ownname. - Options without
menuare top level. An option whosemenumatches no category is never shown. - A submenu can contain categories: the second panel is then replaced by the next submenu. There is no back button: click the top-level category again, or use
opens = 'home'to go back to the root. - Submenu names are shared by every option shown on the target. Keep them unique per list to avoid mixing.
- Avoid cycles (A opens B which opens A): the configurator blocks them.
Separators
separatorAfter = true adds a line after the option. The line only appears when the option itself is shown.
Checkboxes
{
name = 'hud_compact', label = 'Compact HUD', icon = 'fa-solid fa-toggle-on', type = 'checkbox', default = false,
onToggle = function(state)
TriggerEvent('my_hud:compact', state)
end,
onInit = function(state)
TriggerEvent('my_hud:compact', state)
end
},
default: initial state (falsewhen absent).persist:trueby default. The state is remembered client side (KVPox_target:cb:<name>) and restored at next start.persist = falsealways starts fromdefault.onToggle(state): called on every click, with the new state.onInit(state): called once at start with the restored state. The engine reads this field even though it is not listed in theconfig_interactions.luaheader.- The
nameis the memory key: changing it resets players’ state.
The anti_punch built-in is a checkbox of this kind: its default comes from Config.AntiPunch.defaultEnabled, and a default field on the entry overrides it.
Emote shortcuts
The shipped template groups emotes in categories:
{ name = 'self_emotes', label = 'Emotes', icon = 'fa-solid fa-face-smile', description = 'Emote shortcuts', type = 'category', opens = 'self_emotes', separatorAfter = true },
{ name = 'emote_wave', menu = 'self_emotes', label = 'Wave', icon = 'fa-solid fa-hand', type = 'emote', emote = 'wave' },
For players, use type = 'shared_emote' in Config.PlayerInteractions: with the provided presets, the Config.Commands.sharedEmote command (nearby <emote>) is executed. The name must exist in your emote script.
The weather menu
The entry { name = 'weather_menu', menu = 'self_admin', builtin = 'weather_menu' } generates a whole tree from Config.Weather:
weather_menu (category → ox_weather)
├─ weather_menu_types → one item per Weather.types
├─ weather_menu_time → one item per Weather.times, Freeze ON, Freeze OFF
├─ weather_menu_zones → one item per Weather.zones (if useZones)
├─ weather_menu_blackout → Blackout ON, OFF, Toggle
├─ weather_menu_tools → Random weather, server time, blackout state, zone info (if useZones)
└─ weather_menu_local → local rain and freeze (if localTools)
- The prefix of generated names is the entry’s
name;openschanges the root submenu name (ox_weatherby default). - The entry’s
label,icon,descriptionandseparatorAfterreplace those ofWeather.labels.root. - Every generated option requires the
weatherpermission and only shows when the weather integration is available client side. - Avoid naming your own options
weather_menu_…in the same list: names would overlap.
Common mistakes
- Empty category: the arrow shows but the panel is empty. Check the spelling of
menu. - Checkbox without
onToggleoronInit: the state changes visually but nothing uses it. - Renaming a checkbox: players lose their remembered state.