Ox Target Categories

ScriptsM ox_target Categories

ScriptsM ox_target Categories is a modified version of ox_target that adds a clean category and subcategory system without removing the original target functionality.

Instead of showing every interaction in one long list, related actions can be placed inside categories. Players can hover over a category to preview its actions or click it to keep the submenu open.

Standard ox_target options and categorized options can be used together in the same resource.

The original API remains compatible with the official ox_target documentation (opens in a new tab). Category-specific fields added by this version are documented below.

Installation

Download and extract the resource

Download the resource and place the ox_target folder inside your server's resources directory.

If you are replacing the original ox_target, stop the server and replace the old folder completely. Do not run two resources named ox_target at the same time.

Install the dependency

The resource requires ox_lib version 3.30.0 or newer.

ox_lib
ox_target

Configure the resource start order

Make sure ox_lib starts before ox_target.

ensure ox_lib
ensure ox_target

Optional server configuration

Add any required convars before ensure ox_target in server.cfg.

# Use toggle mode instead of holding the targeting key.
setr ox_target:toggleHotkey 0
 
# Default targeting key.
setr ox_target:defaultHotkey LMENU
 
# Draw a sprite at the center of target zones.
setr ox_target:drawSprite 1
 
# Enable built-in options such as vehicle door interactions.
setr ox_target:defaults 1
 
# Enable debug zones, entity outlines, and the raycast indicator.
setr ox_target:debug 0
 
# Allow left click to select an option.
setr ox_target:leftClick 1

Restart the server

Restart the server or run the following commands from the server console:

restart ox_lib
restart ox_target

Supported Frameworks

The targeting system works as a standalone resource. Optional framework bridges provide group, job, and item checks for:

ox_core
es_extended
qbx_core

Quick Start

Categories use the same exports as standard ox_target. Add usedouble = true to the parent option and place the available actions inside subcategory.

exports.ox_target:addModel('police', {
    {
        name = 'police_vehicle_actions',
        usedouble = true,
        labelcategory = 'Vehicle Actions',
        iconcategory = 'fa-solid fa-car',
        iconColor = '#3498db',
        distance = 2.0,
        bones = { 'boot' },
        subcategory = {
            {
                name = 'open_trunk_storage',
                label = 'Open trunk storage',
                icon = 'fa-solid fa-box-open',
                event = 'my_resource:openTrunk'
            },
            {
                name = 'take_police_cone',
                label = 'Take traffic cone',
                icon = 'fa-solid fa-triangle-exclamation',
                serverEvent = 'my_resource:takeCone'
            },
            {
                name = 'inspect_vehicle',
                label = 'Inspect vehicle',
                icon = 'fa-solid fa-magnifying-glass',
                onSelect = function(data)
                    print(('Selected vehicle: %s'):format(data.entity))
                end
            }
        }
    }
})

Category Structure

The parent option controls the category itself and the conditions shared by every action inside it.

{
    name = 'category_name',
    usedouble = true,
    labelcategory = 'Category Label',
    iconcategory = 'fa-solid fa-folder',
    iconColor = '#ffffff',
    distance = 2.0,
    groups = { police = 0 },
    items = { 'radio' },
    bones = { 'boot' },
    canInteract = function(entity, distance, coords, name, bone)
        return DoesEntityExist(entity)
    end,
    subcategory = {
        -- Subcategory actions go here.
    }
}
FieldTypeRequiredDescription
namestringRecommendedUnique option name used when replacing or removing the category.
usedoublebooleanYesMust be true to enable the category interface.
labelcategorystringYesText displayed in the main target menu.
iconcategorystringNoFont Awesome icon used by the category. Defaults to a folder icon.
iconColorstringNoCSS color used by the category icon.
subcategorytableYesNon-empty array containing the actions shown in the secondary menu.
distancenumberNoMaximum interaction distance for the whole category. Defaults to the normal target distance.
groupsstring/tableNoFramework groups or job grades allowed to see the category.
itemsstring/tableNoRequired item or items checked by the active framework bridge.
anyItembooleanNoAllows any configured item to satisfy the item requirement.
bonesstring/tableNoLimits the category to one or more entity bones.
offsetvector3NoLimits interaction to a model-relative offset.
offsetSizenumberNoAllowed distance from the configured offset.
canInteractfunctionNoControls visibility of the entire category.

Subcategory Structure

Each subcategory entry represents one selectable action.

{
    name = 'action_name',
    label = 'Action Label',
    icon = 'fa-solid fa-hand',
    iconColor = '#ffffff',
    canInteract = function(entity, distance, coords, name, bone)
        return distance <= 2.0
    end,
    event = 'my_resource:clientEvent'
}
FieldTypeRequiredDescription
namestringNoAction identifier passed to canInteract and returned with selection data.
labelstringYesText displayed in the category submenu.
iconstringNoFont Awesome icon displayed next to the action.
iconColorstringNoCSS color used by the action icon.
canInteractfunctionNoControls visibility of this individual action.
onSelectfunctionOne action requiredExecutes a local Lua callback.
eventstringOne action requiredTriggers a client event.
serverEventstringOne action requiredTriggers a server event.
exportstringOne action requiredCalls an export from the resource that registered the option.
commandstringOne action requiredExecutes a client command.

Every subcategory entry must contain exactly one action handler: onSelect, event, serverEvent, export, or command.

Action Examples

onSelect

{
    label = 'Inspect vehicle',
    icon = 'fa-solid fa-magnifying-glass',
    onSelect = function(data)
        print(data.entity)
        print(data.coords)
        print(data.distance)
    end
}

Client event

{
    label = 'Open storage',
    icon = 'fa-solid fa-box-open',
    event = 'my_resource:openStorage',
    storageId = 'police_armory'
}
 
RegisterNetEvent('my_resource:openStorage', function(data)
    print(data.storageId)
    print(data.entity)
end)

Server event

{
    label = 'Take equipment',
    icon = 'fa-solid fa-toolbox',
    serverEvent = 'my_resource:takeEquipment',
    item = 'police_cone'
}

Command

{
    label = 'Open vehicle menu',
    icon = 'fa-solid fa-car',
    command = 'vehiclemenu'
}

Export

The export is resolved from the resource that registered the target option.

{
    label = 'Open custom menu',
    icon = 'fa-solid fa-list',
    export = 'OpenCustomMenu'
}
exports('OpenCustomMenu', function(_, data)
    print(data.entity)
end)

Dynamic Visibility

Use a parent canInteract function to hide the complete category.

canInteract = function(entity, distance)
    return distance <= 2.0 and not IsEntityDead(entity)
end

Use a subcategory canInteract function when only one action should be hidden.

subcategory = {
    {
        label = 'Repair vehicle',
        icon = 'fa-solid fa-screwdriver-wrench',
        canInteract = function(entity)
            return GetVehicleEngineHealth(entity) < 900.0
        end,
        event = 'my_mechanic:repairVehicle'
    },
    {
        label = 'Clean vehicle',
        icon = 'fa-solid fa-soap',
        event = 'my_mechanic:cleanVehicle'
    }
}

If every subcategory action is unavailable, the parent category is automatically hidden.

Zone Example

Categories work with zones, models, local entities, networked entities, global targets, vehicles, objects, peds, and players.

local zoneId = exports.ox_target:addBoxZone({
    name = 'mechanic_workbench',
    coords = vec3(-347.15, -133.42, 39.01),
    size = vec3(2.0, 1.0, 1.5),
    rotation = 70.0,
    debug = false,
    options = {
        {
            name = 'mechanic_services',
            usedouble = true,
            labelcategory = 'Mechanic Services',
            iconcategory = 'fa-solid fa-screwdriver-wrench',
            distance = 2.0,
            subcategory = {
                {
                    label = 'Repair vehicle',
                    icon = 'fa-solid fa-wrench',
                    event = 'my_mechanic:repair'
                },
                {
                    label = 'Order parts',
                    icon = 'fa-solid fa-boxes-stacked',
                    event = 'my_mechanic:orderParts'
                }
            }
        }
    }
})

Migrating Existing Options

Original flat options:

exports.ox_target:addModel('police', {
    {
        name = 'take_cone',
        label = 'Take cone',
        icon = 'fa-solid fa-triangle-exclamation',
        event = 'equipment:takeCone'
    },
    {
        name = 'take_barrier',
        label = 'Take barrier',
        icon = 'fa-solid fa-road-barrier',
        event = 'equipment:takeBarrier'
    }
})

Categorized version:

exports.ox_target:addModel('police', {
    {
        name = 'police_equipment',
        usedouble = true,
        labelcategory = 'Police Equipment',
        iconcategory = 'fa-solid fa-toolbox',
        subcategory = {
            {
                label = 'Take cone',
                icon = 'fa-solid fa-triangle-exclamation',
                event = 'equipment:takeCone'
            },
            {
                label = 'Take barrier',
                icon = 'fa-solid fa-road-barrier',
                event = 'equipment:takeBarrier'
            }
        }
    }
})

Troubleshooting

The category does not appear

  • Confirm usedouble is set to true.
  • Confirm labelcategory is a non-empty string.
  • Confirm subcategory is a non-empty array.
  • Confirm at least one subcategory canInteract function returns true.
  • Check the parent distance, groups, items, bones, and canInteract conditions.

The resource reports an action handler error

Each subcategory must contain exactly one of these fields:

onSelect
event
serverEvent
export
command

Do not add multiple action handlers to the same subcategory entry.

The submenu closes too quickly

Move the cursor directly from the category into the submenu or click the category to pin it open.

Duplicate options appear

Give every parent option a unique name and make sure the registration code runs only once. When replacing an existing integration, remove the old registration code first.

License and Credits

This resource is a modified version of ox_target (opens in a new tab), originally created by Overextended.

Original project copyright © 2022 Overextended and licensed under the MIT License. The original copyright notice and complete MIT License must remain included with every distributed copy of the resource.

Modifications © 2026 ScriptsM.

Additional API Reference