Skip to content

Radial Menu

Circular action wheel — ideal for quick shortcuts accessible by mouse, keyboard or controller.

2 min read

Opening

exports.LastMenu:radial(function(r)
    r:center_label("Quick hub")
    r:button("Garage",   { icon = "car",          cb = openGarage   })
    r:button("Hospital", { icon = "plus-circle",  cb = openHospital })
    r:button("Missions", { icon = "zap",           cb = openMissions })
end)

The center sector displays center_label when no sector is hovered.


Reusable menu

Use radial_build to build an instance once and reopen it at will:

local radial = exports.LastMenu:radial_build(function(r)
    r:button("Action A", { icon = "check", cb = function() end })
    r:button("Action B", { icon = "x",     cb = function() end })
end)

RegisterCommand('wheel', function() radial.open()  end, false)
RegisterCommand('closewheel', function() radial.close() end, false)

Menu options

MethodDescription
r:center_label(str)Text displayed in the central ring at rest

Button options

FieldTypeDefaultDescription
iconstringLucide icon name
cbfunction()Called on selection
keep_openboolfalseDon’t close radial after callback
submenufunction(r)nilOpens nested radial on click
visiblebool\|function() → booltrueHides and removes the sector
disabledbool\|function() → boolfalseGrayed out, no callback
refreshnumber250Polling interval (ms) for visible/disabled

Conditional button (reactivity)

Shows “Exit vehicle” button only when player is in a vehicle:

exports.LastMenu:radial(function(r)
    r:center_label("Actions")

    r:button("Exit vehicle", {
        icon    = "log-out",
        visible = function()
            return GetVehiclePedIsIn(PlayerPedId(), false) ~= 0
        end,
        refresh = 500,
        cb = function()
            TaskLeaveAnyVehicle(PlayerPedId(), 0, 16)
        end,
    })

    r:button("Heal", {
        icon = "heart",
        cb   = function() TriggerServerEvent('player:heal') end,
    })
end)

Sub-radials

Nest radial menus with button.submenu. The parent radial is stacked and restored on Escape:

exports.LastMenu:radial(function(r)
    r:center_label("Actions")

    r:button("Vehicle", {
        icon    = "car",
        submenu = function(sub)
            sub:center_label("Vehicle")
            sub:button("Repair",  { icon = "wrench",   cb = repairVehicle })
            sub:button("Clean", { icon = "droplets", cb = cleanVehicle  })
        end,
    })

    r:button("Player", {
        icon    = "user",
        submenu = function(sub)
            sub:center_label("Player")
            sub:button("Heal", { icon = "heart", cb = healPlayer })
        end,
    })
end)

With submenu, keep_open = true is set automatically — no need to specify it manually.


Controls

InputAction
Mouse hoverHighlights sector
Left clickConfirms selection
Left stick (controller)Highlights by direction
A / Cross button (controller)Confirms selection
EscapeCloses without action

Best practices

visible = false removes the sector and redistributes the arc geometry. Use disabled = true if you want to keep the sector visible but inactive (stable layout).

Button limit — up to about 12 buttons display properly. Beyond that, sectors become too narrow — consider sub-radials or a context menu.

The visible/disabled watchers use the same adaptive polling engine as context menus (backoff on stability, reset on change).