Skip to content

atoshit/zedlib

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

25 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ZedLib - Modern FiveM UI Library

A production-ready, modular UI library for FiveM featuring a React-based NUI frontend and a clean Lua API. Build beautiful menus, notifications, and dialogs with minimal code.

Table of Contents


Features

Menu System

  • Fully navigable menus with keyboard and mouse wheel
  • Description option on all items (button, checkbox, list, slider, submenu, category, search, info, separator): when set, a panel below the menu shows that text for the focused item
  • Button, checkbox, list selector, slider, separator, submenu, category, and info items
  • Categories: expand/collapse groups of items in-place (e.g. "Actions on player" → Freeze, Kick, Ban); items can be assigned to a category and only show when it is expanded
  • Info button: hover or focus to show a side panel with label/value pairs (e.g. player name, group, job)
  • Search/filter functionality for large menus
  • Submenu stack navigation with back support
  • Custom accent colors and banner images (default accent: red)
  • Icon support (FontAwesome names or image URLs)
  • Optional category on any item so it appears only when that category is expanded

Notifications

  • Four notification types: success, error, warning, info
  • Optional custom accent color per notification
  • Configurable display duration
  • Optional body message and icon
  • Bulk clear support
  • Black background with colored accent bar and icon badge

Dialogs

  • Input dialogs with field types: text, number, password, textarea
  • Optional accent color and header icon per dialog
  • Confirm/cancel dialogs with one-liner shortcut (with optional color)
  • Customizable buttons with primary, secondary, danger variants and optional icon
  • Field validation (required, maxLength, min/max)
  • Closable toggle
  • Default accent color: red when not specified

Context Menu

  • Entity targeting with ALT key: hold ALT to show cursor, left-click an entity to open context menu
  • Entity highlighting: targeted entities become semi-transparent for visual feedback
  • Camera lock: camera is locked while ALT is held, movement (WASD) remains active
  • Release ALT to close: releasing ALT closes everything instantly
  • Flyout submenus: submenus expand to the right on hover (nested submenus supported)
  • Shine hover effect: items glow with red accent border on hover, consistent with the menu system
  • Register options by entity type: vehicle, ped, player, object, myself, mycar, or all
  • Target yourself: myself type for options on your own character
  • Target your vehicle: mycar type for options on the vehicle you are sitting in (inherits vehicle options)
  • Target a specific entity: entity field to bind options to a single entity handle
  • Target by model/prop: model field to bind options to all props of a given model name or hash
  • Auto-cleanup: options are automatically removed when the resource that registered them stops

Interact

  • Interaction prompt at world coordinates (above peds, doors, etc.)
  • Optional key (e.g. E) displayed in a small box on the left; omit key to show only the label
  • Key press animation on the key box when the player presses the key
  • Dynamic coords: pass a function for moving entities (e.g. ped head)
  • Distance-based visibility and onSelect callback

InteractProgress

  • Same as Interact but hold the key for a duration (ms)
  • Progress bar below the label while holding; onSelect only when full duration complete
  • onCancel when the player releases early or leaves range

Progress Bar

  • Blocking function: returns true (completed) or false (cancelled)
  • Animation support: play animations during the progress (dict + clip)
  • Prop attachment: attach props to the player (model, position, rotation, bone)
  • Cancel support: optional ESC/Backspace cancellation
  • Control disabling: selectively disable movement, vehicle, combat, or mouse controls
  • Uses the global accent color with glow effect

General

  • UI sound effects (hover, select, toggle) with global toggle
  • Smooth animations and hover shine effects
  • Plugin system for extensibility
  • Hot reload dev playground (no FiveM required)
  • Optimized production build
  • Lua API split by component: lua/api/ (menu, notification, dialog, progressbar, context, config, exports)

Tech Stack

Layer Technology
Frontend React 19, TypeScript (strict), Vite 6
State Zustand 5
Styling TailwindCSS 3
Animation Framer Motion 11
Backend FiveM Lua (client-side)

Installation

1. Build the UI

cd zedlib/web
npm install
npm run build

2. Add to your FiveM server

Copy the zedlib folder into your server's resources/ directory, then add it to your server.cfg:

ensure zedlib

3. Set up your resource

Option A — Import file (recommended)

Add zedlib as a dependency and include import.lua in your fxmanifest.lua. This gives you the zed.* API with automatic cross-resource callback support:

fx_version 'cerulean'
game 'gta5'

dependencies { 'zedlib' }

shared_scripts {
    '@zedlib/import.lua',
}

client_scripts {
    'client.lua',
}

You can then use the zed.* namespace in your scripts:

zed.CreateMenu("my_menu", "My Menu")

Option B — Exports

Add zedlib as a dependency and call functions through FiveM exports. No extra file needed:

fx_version 'cerulean'
game 'gta5'

dependencies { 'zedlib' }

client_scripts {
    'client.lua',
}

You can then call any function via exports.zedlib:

exports.zedlib:CreateMenu("my_menu", "My Menu")

Both methods provide the exact same functionality. The zed.* import is generally more convenient for scripts with many callbacks.


Usage Methods

ZedLib exposes every function through three equivalent interfaces. Pick whichever suits your project:

Interface Scope Example
zed.* Any resource that imports @zedlib/import.lua zed.OpenMenu("main")
exports.zedlib:* Any resource with zedlib as dependency exports.zedlib:OpenMenu("main")
UI.* Internal to the zedlib resource itself UI.OpenMenu("main")

All code examples below use the zed.* style. Replace with exports.zedlib: if you prefer exports.


Usage

Menus

Creating a Menu

zed.CreateMenu("main", "Main Menu", "Select an option", {
    color = "#3498db",   -- accent color (hex)
    banner = "https://example.com/banner.png" -- header banner image URL
})
Parameter Type Required Description
id string yes Unique menu identifier
title string yes Title displayed in the menu header
subtitle string no Subtitle below the title (hidden when a banner is set)
opts table no Additional options: color (hex string), banner (image URL). Default accent color when not set: red (#e74c3c).

Adding a Button

zed.AddButton("main", {
    label = "Teleport to Marker",
    description = "Teleports you to your map marker",
    icon = "location-dot",
    rightLabel = "$725,000",
    rightLabelColor = "#22c55e",
    onSelect = function()
        local blip = GetFirstBlipInfoId(8)
        if DoesBlipExist(blip) then
            local coords = GetBlipInfoIdCoord(blip)
            SetEntityCoords(PlayerPedId(), coords.x, coords.y, coords.z)
            zed.Notify({ title = "Teleported", message = "You have been teleported to the marker" })
        end
    end
})
Option Type Default Description
label string Display text for the button
description string nil Text shown in the description panel below the menu when this item is focused
icon string nil FontAwesome icon name (e.g. "gear") or image URL
rightLabel string nil Display text in the right button
rightLabelColor string nil Color of the right label
id string auto Custom unique identifier
disabled boolean false Prevents interaction when true
category string nil Category id: item is only visible when this category is expanded
metadata table nil Arbitrary data passed to the onSelect callback
infoData table nil Array of { label, value } pairs shown in the info side panel when focused
onSelect function nil Callback fired when the button is selected

Adding a Checkbox

zed.AddCheckbox("main", {
    label = "God Mode",
    icon = "shield",
    checked = false,
    onChange = function(checked)
        print("God Mode:", checked)
        SetEntityInvincible(PlayerPedId(), checked)
    end
})
Option Type Default Description
label string Display text
icon string nil FontAwesome icon name or image URL
id string auto Custom unique identifier
disabled boolean false Prevents interaction when true
category string nil Category id: item only visible when this category is expanded
checked boolean false Initial checked state
infoData table nil Array of { label, value } pairs shown in the info side panel when focused
onChange function nil Callback receiving the new checked boolean

Adding a List Selector

Use left/right arrow keys to cycle through options.

zed.AddList("main", {
    label = "Weather",
    icon = "cloud-sun",
    items = {
        { label = "Clear",    value = "CLEAR" },
        { label = "Rain",     value = "RAIN" },
        { label = "Thunder",  value = "THUNDER" },
        { label = "Snow",     value = "SNOW" },
    },
    currentIndex = 1,
    onChange = function(index, item)
        print("Selected:", item.label, "Value:", item.value, "Index:", index)
        SetWeatherTypeNow(item.value)
    end
})

You can also pass plain strings — they are auto-converted to { label = str, value = str }:

zed.AddList("main", {
    label = "Color",
    items = { "Red", "Green", "Blue" },
    onChange = function(index, item)
        print(item.value) -- "Red", "Green", or "Blue"
    end
})
Option Type Default Description
label string Display text
icon string nil FontAwesome icon name or image URL
id string auto Custom unique identifier
disabled boolean false Prevents interaction when true
category string nil Category id: item only visible when this category is expanded
items table Array of { label, value } tables or plain strings
currentIndex number 1 Initial selected index (1-based)
infoData table nil Array of { label, value } pairs shown in the info side panel when focused
onChange function nil Callback receiving (index, item) — index is 1-based

Adding a Slider

Use left/right arrow keys to adjust the value.

zed.AddSlider("main", {
    label = "Vehicle Speed",
    icon = "gauge-high",
    min = 0,
    max = 200,
    step = 10,
    value = 80,
    onChange = function(value)
        print("Speed set to:", value)
        SetVehicleMaxSpeed(GetVehiclePedIsIn(PlayerPedId(), false), value + 0.0)
    end
})
Option Type Default Description
label string Display text
icon string nil FontAwesome icon name or image URL
id string auto Custom unique identifier
disabled boolean false Prevents interaction when true
category string nil Category id: item only visible when this category is expanded
min number 0 Minimum value
max number 100 Maximum value
step number 1 Step increment
value number 0 Initial value
infoData table nil Array of { label, value } pairs shown in the info side panel when focused
onChange function nil Callback receiving the new value

Adding a Separator

Inserts a visual divider line between menu items. Optional second argument for category.

zed.AddSeparator("main")

-- Separator only visible when category "actions" is expanded
zed.AddSeparator("main", { category = "actions" })
Option Type Default Description
category string nil Category id: separator only visible when this category is expanded

Adding a Category

Categories let you group items that appear only when the category is expanded (e.g. "Actions on player" → Freeze, Kick, Ban). Different from submenus: the category expands in-place; no new menu screen.

-- Add the category header (id is used when assigning items to this category)
zed.AddCategory("main", {
    label = "Actions on player",
    id = "actions_player",
    icon = "bolt",
})

-- Add items that belong to this category (they are hidden until the category is opened)
zed.AddButton("main", {
    label = "Freeze",
    icon = "snowflake",
    category = "actions_player",
    onSelect = function() -- ... end,
})
zed.AddButton("main", { label = "Kick",  category = "actions_player", onSelect = function() end })
zed.AddButton("main", { label = "Ban",   category = "actions_player", onSelect = function() end })
Option Type Required Description
label string yes Display label for the category header
id string yes Category id — use this in opts.category when adding items
icon string no FontAwesome icon name or image URL
disabled boolean no Whether the category header is disabled (default: false)

Any menu item (button, checkbox, list, slider, submenu, search, info, separator) can have category = "id" so it is only visible when that category is expanded.


Adding an Info Button

Shows a side panel with label/value pairs when the item is focused or hovered. Does nothing on select (no action). Ideal for player details, entity info, etc.

zed.AddInfoButton("main", {
    label = "Player info",
    icon = "id-card",
    data = {
        { label = "Name",   value = "John Doe" },
        { label = "Group",  value = "Admin" },
        { label = "Job",    value = "Police" },
        { label = "Money",  value = "$12,500" },
    }
})
Option Type Default Description
label string Display label for the info button
icon string nil FontAwesome icon name or image URL
id string auto Custom unique identifier
disabled boolean false Whether the info button is disabled
category string nil Category id: item only visible when this category is expanded
data table Array of { label, value } pairs shown in the side panel

Tip: You don't need a dedicated AddInfoButton to show an info panel. All item types (button, checkbox, submenu, list, slider, category) support an infoData option that shows the same side panel when focused:

zed.AddSubMenu("main", "player_actions", "John Doe", {
    icon = "user",
    infoData = {
        { label = "Name",  value = "John Doe" },
        { label = "Group", value = "Admin" },
        { label = "Job",   value = "Police" },
        { label = "Money", value = "$12,500" },
    }
})

zed.AddButton("main", {
    label = "Sell Vehicle",
    icon = "car",
    rightLabel = "$50,000",
    rightLabelColor = "#22c55e",
    infoData = {
        { label = "Model",   value = "Zentorno" },
        { label = "Plate",   value = "ZED-1337" },
        { label = "Fuel",    value = "87%" },
    },
    onSelect = function() end
})

Adding a Search Button

Adds a search/filter input that filters menu items in real-time by label.

zed.AddSearchButton("main", {
    label = "Search",
    icon = "magnifying-glass",
    placeholder = "Type to filter..."
})
Option Type Default Description
label string "Rechercher" Display text
icon string "magnifying-glass" FontAwesome icon name
placeholder string "Tapez pour rechercher..." Placeholder text when active
id string auto Custom unique identifier
category string nil Category id: item only visible when this category is expanded

Creating Submenus

Submenus are created by registering a child menu and linking it to a parent.

-- Create the parent menu
zed.CreateMenu("main", "Main Menu")

-- Add a submenu link (this also registers the submenu automatically)
zed.AddSubMenu("main", "settings", "Settings", {
    icon = "gear",
    subtitle = "Configure your preferences",
    color = "#e74c3c",
})

-- Now add items to the submenu using its ID
zed.AddCheckbox("settings", {
    label = "Enable Sounds",
    checked = true,
    onChange = function(checked)
        zed.SetConfig({ sounds = checked })
    end
})

zed.AddButton("settings", {
    label = "Reset Defaults",
    icon = "rotate",
    onSelect = function()
        zed.Notify({ title = "Reset", message = "Settings restored to defaults" })
    end
})

-- Open the parent menu
zed.OpenMenu("main")

AddSubMenu options:

Option Type Default Description
icon string nil FontAwesome icon name or image URL
id string auto Custom identifier for the submenu link item
disabled boolean false Prevents interaction when true
category string nil Category id: item only visible when this category is expanded
subtitle string label Title override for the submenu header
color string nil Accent color override (hex)
banner string nil Banner image URL override
infoData table nil Array of { label, value } pairs shown in the info side panel when focused

Opening, Closing, and Removing Menus

-- Open a menu by its ID
zed.OpenMenu("main")

-- Close the currently open menu
zed.CloseMenu()

-- Check if any menu is currently open
if zed.IsMenuOpen() then
    print("A menu is open")
end

-- Remove a menu and free its resources
zed.RemoveMenu("main")

Context Menu

The context menu system allows players to interact with entities by holding ALT and left-clicking on them. Options are registered by entity type, specific entity, or model name. Submenus expand as flyout panels to the right on hover.

How it works

  1. Player holds ALT — the native cursor appears, the camera locks, but movement (WASD) remains active
  2. Entities under the cursor get highlighted (semi-transparent) with a hand cursor
  3. Player left-clicks on a highlighted entity — the context menu opens at the cursor position
  4. Player selects an option — the callback is executed with the entity handle, type, and coordinates
  5. Releasing ALT at any time closes everything (cursor, highlight, menu)

Options by entity type

Register options that appear for all entities of a given type:

-- Option for all vehicles
zed.AddContextOption({
    type = "vehicle",
    label = "Lock / Unlock",
    icon = "lock",
    onSelect = function(entity, entityType, coords)
        local locked = GetVehicleDoorLockStatus(entity)
        SetVehicleDoorsLocked(entity, locked == 1 and 2 or 1)
    end
})

-- Option for all entity types
zed.AddContextOption({
    type = "all",
    label = "Inspect",
    icon = "magnifying-glass",
    onSelect = function(entity, entityType, coords)
        print("Entity:", entity, "Type:", entityType)
    end
})

Available types: vehicle, ped, player, object, myself, mycar, all

Options for yourself (myself)

Options that appear when targeting your own character:

zed.AddContextOption({
    type = "myself",
    label = "Play Animation",
    icon = "person-walking",
    onSelect = function(entity, entityType, coords)
        -- Open animation menu
    end
})

zed.AddContextOption({
    type = "myself",
    label = "Change Outfit",
    icon = "shirt",
    onSelect = function(entity, entityType, coords)
        -- Open clothing menu
    end
})

Options for your vehicle (mycar)

Options that appear when targeting the vehicle you are currently sitting in. These inherit all vehicle type options as well:

zed.AddContextOption({
    type = "mycar",
    label = "Toggle Engine",
    icon = "power-off",
    onSelect = function(entity, entityType, coords)
        SetVehicleEngineOn(entity, not GetIsVehicleEngineRunning(entity), false, true)
    end
})

zed.AddContextOption({
    type = "mycar",
    label = "Toggle Doors Lock",
    icon = "lock",
    onSelect = function(entity, entityType, coords)
        local locked = GetVehicleDoorLockStatus(entity)
        SetVehicleDoorsLocked(entity, locked == 1 and 2 or 1)
    end
})

Options for a specific entity

Bind options to a single entity handle. Useful for unique NPCs, spawned objects, etc.:

local shopkeeper = CreatePed(4, GetHashKey("a_m_m_indian_01"), 24.5, -1345.6, 29.5, 0.0, true, true)

zed.AddContextOption({
    entity = shopkeeper,
    label = "Talk to shopkeeper",
    icon = "comment",
    onSelect = function(entity, entityType, coords)
        -- Open shop dialog
    end
})

zed.AddContextOption({
    entity = shopkeeper,
    label = "Browse goods",
    icon = "store",
    onSelect = function(entity, entityType, coords)
        -- Open shop menu
    end
})

Options by model/prop

Bind options to all instances of a specific model. Accepts a model name (string) or hash (number):

-- All ATMs in the world
zed.AddContextOption({
    model = "prop_atm_01",
    label = "Withdraw money",
    icon = "money-bill",
    onSelect = function(entity, entityType, coords)
        -- Open ATM UI
    end
})

zed.AddContextOption({
    model = "prop_atm_01",
    label = "Check balance",
    icon = "receipt",
    onSelect = function(entity, entityType, coords)
        -- Show balance
    end
})

-- Also works with a hash
zed.AddContextOption({
    model = GetHashKey("prop_vend_snak_01"),
    label = "Buy snack",
    icon = "cookie-bite",
    onSelect = function(entity, entityType, coords)
        -- Buy food
    end
})

Flyout submenus

Group related options into submenus that expand to the right on hover. Nested submenus are supported:

-- Create a submenu for vehicle actions
zed.AddContextSubMenu({
    type = "vehicle",
    id = "veh_actions",
    label = "Vehicle Actions",
    icon = "car"
})

-- Add options inside the submenu
zed.AddContextOption({
    type = "vehicle",
    submenu = "veh_actions",
    label = "Repair",
    icon = "wrench",
    onSelect = function(entity, entityType, coords)
        SetVehicleFixed(entity)
        SetVehicleDeformationFixed(entity)
    end
})

zed.AddContextOption({
    type = "vehicle",
    submenu = "veh_actions",
    label = "Delete",
    icon = "trash",
    onSelect = function(entity, entityType, coords)
        DeleteVehicle(entity)
    end
})

-- Submenus also work with entity or model targeting
zed.AddContextSubMenu({
    model = "prop_atm_01",
    id = "atm_actions",
    label = "ATM Options",
    icon = "building-columns"
})

Options table

Field Type Default Description
type string 'all' Entity type: 'vehicle', 'ped', 'player', 'object', 'myself', 'mycar', 'all'
entity number nil Specific entity handle (overrides type)
model string or number nil Model name or hash — applies to all props with this model (overrides type)
label string required Display label
icon string nil FontAwesome icon name or image URL
id string auto Custom identifier
disabled boolean false Whether the option is grayed out
submenu string nil Submenu id to nest the option inside
onSelect function nil function(entity, entityType, coords) called on click

Priority: entity > model > type. If entity is set, type and model are ignored.

Submenu options table

Field Type Default Description
type string 'all' Entity type filter
entity number nil Specific entity handle (overrides type)
model string or number nil Model name or hash (overrides type)
id string auto Unique submenu identifier
label string required Display label for the submenu
icon string nil FontAwesome icon name or URL

Management functions

-- Remove a specific option by its id
zed.RemoveContextOption("opt_ctx_1")

-- Remove all options and submenus
zed.ClearContext()

-- Disable/enable targeting (ALT hold)
zed.SetContextEnabled(false)
zed.SetContextEnabled(true)

-- Check state
zed.IsContextEnabled()  -- boolean
zed.IsContextOpen()     -- boolean

-- Force close the context menu
zed.CloseContext()

Auto-cleanup

When a resource that registered context options is stopped or restarted, all its options and submenus are automatically removed. No manual cleanup needed — no duplicates on restart.


Progress Bar

The progress bar is a blocking function that displays a progress indicator at the bottom of the screen. It returns true if completed or false if cancelled. Supports animations, prop attachments, and selective control disabling.

Basic usage

if zed.ProgressBar({
    duration = 3000,
    label = 'Repairing vehicle...',
}) then
    print('Repair complete!')
else
    print('Repair cancelled')
end

With animation and prop

if zed.ProgressBar({
    duration = 2000,
    label = 'Drinking water',
    canCancel = true,
    disable = {
        car = true,
        combat = true,
    },
    anim = {
        dict = 'mp_player_intdrink',
        clip = 'loop_bottle',
    },
    prop = {
        model = 'prop_ld_flow_bottle',
        pos = vec3(0.03, 0.03, 0.02),
        rot = vec3(0.0, 0.0, -1.5),
    },
}) then
    print('Finished drinking')
else
    print('Stopped drinking')
end

Options table

Field Type Default Description
duration number 5000 Duration in milliseconds
label string '' Text displayed above the progress bar
canCancel boolean true Whether the player can cancel with ESC or Backspace
anim table nil Animation to play: { dict, clip, flag? }
prop table nil Prop to attach: { model, pos?, rot?, bone? }
disable table nil Controls to disable: { move?, car?, combat?, mouse? }

anim fields:

Field Type Default Description
dict string Animation dictionary
clip string Animation clip name
flag number 49 Animation flag

prop fields:

Field Type Default Description
model string/number Prop model name or hash
pos vector3 (0,0,0) Offset position relative to the bone
rot vector3 (0,0,0) Rotation relative to the bone
bone number 60309 Bone index (default: right hand)

disable fields:

Field Type Default Description
move boolean false Disable WASD movement
car boolean false Disable vehicle controls
combat boolean false Disable combat and firing
mouse boolean false Disable camera/mouse

Management functions

-- Cancel the active progress bar from code
zed.CancelProgressBar()

-- Check if a progress bar is active
if zed.IsProgressActive() then
    print('Progress running')
end

Interact

Display a small interaction prompt at world coordinates (e.g. above a ped or in front of a door). When the player is in range and presses the key, a short animation plays on the key box and your callback runs.

Basic usage

-- Fixed position (e.g. door)
zed.Interact({
    coords = vector3(123.0, 456.0, 78.0),
    label = "Ouvrir la porte",
    key = "E",
    distance = 1.5,
    onSelect = function()
        print("Door opened!")
    end,
})

-- Attach to a specific entity (prompt follows the entity)
zed.Interact({
    entity = myPed,
    label = "Parler au PNJ",
    key = "E",
    onSelect = function() end,
})

-- Attach to the closest entity of a type (all peds, all vehicles, or all objects in range)
-- onSelect(entity) receives the entity you interacted with (nil if using coords only)
zed.Interact({
    type = "ped",
    label = "Fouiller",
    key = "E",
    distance = 2.0,
    onSelect = function(entity)
        if entity then
            -- e.g. TaskStartScenarioInPlace(entity, ...) or DeleteEntity(entity)
        end
    end,
})
zed.Interact({ type = "vehicle", label = "Ouvrir le coffre", key = "E", onSelect = function(veh) SetVehicleDoorOpen(veh, 5, false, false) end })
zed.Interact({ type = "object", label = "Utiliser", key = "E", onSelect = function() end })

Without key

If you omit key, only the label is shown (no key box on the left):

zed.Interact({
    coords = vector3(0, 0, 0),
    label = "Zone d'interaction",
    onSelect = function() end,
})

Options

Field Type Default Description
coords vector3 or fun World position, or function returning vector3. Omit if using entity or type.
entity number nil Specific entity handle. Prompt is shown on this entity and follows it.
type string nil "ped", "vehicle", or "object". Prompt is shown on the closest entity of this type within distance.
label string Text displayed next to the key
key string nil Key to show (e.g. "E"). If omitted, no key box is shown
distance number 2.0 Max distance to show the prompt (and for type, search radius for closest entity)
onSelect function nil Callback when the player presses the key: onSelect(entity). entity is the targeted entity (nil if using coords only).

You must set exactly one of coords, entity, or type. Supported key labels: E, G, F, R, Q, Z, X, C, T, Y.

Clear

zed.ClearInteract()

InteractProgress (hold to complete)

Same as Interact but the player must hold the key for a given duration. A progress bar appears below the label while holding; onSelect(entity) runs when the duration is complete, and onCancel(entity) runs if they release early or leave range. In both callbacks, entity is the entity the prompt was attached to (nil if using coords only).

zed.InteractProgress({
    coords = vector3(x, y, z),
    label = "Dévaliser l'individu",
    key = "E",
    distance = 2.0,
    duration = 2000,  -- ms to hold
    onSelect = function()
        print("Completed!")
    end,
    onCancel = function()
        print("Cancelled or released early.")
    end,
})

zed.ClearInteractProgress()  -- clear when done

To keep the prompt after the action (e.g. repeat "Dévaliser" on the same ped), set removeOnComplete = false:

zed.InteractProgress({
    coords = function() return GetEntityCoords(targetPed) + vector3(0, 0, 1) end,
    label = "Dévaliser l'individu",
    key = "E",
    duration = 2000,
    removeOnComplete = false,  -- prompt stays, player can do it again
    onSelect = function() end,
})
Field Type Default Description
coords vector3 or fun World position (or function). Omit if using entity or type.
entity number nil Specific entity handle. Prompt is shown on this entity.
type string nil "ped", "vehicle", or "object". Prompt on the closest entity of this type in range.
label string Text displayed above the progress bar
key string nil Key to show (e.g. "E"). Omit for no key box
distance number 2.0 Max distance to show the prompt
duration number Time in ms the player must hold the key
removeOnComplete boolean true If true, the prompt is removed after the action. If false, it stays so the player can repeat.
onSelect function nil Called when the player holds for the full duration: onSelect(entity)
onCancel function nil Called when the player releases before completion or leaves range: onCancel(entity)

Notifications

Generic Notification

All notification functions take a single data table. You only pass the fields you need; no need for nil placeholders.

-- Generic notification (specify type in data)
zed.Notify({
    type = "success",
    title = "Purchase Complete",
    message = "You bought a Zentorno for $725,000",
    duration = 5000
})

-- With subtitle, color and image (omit what you don't need)
zed.Notify({
    type = "info",
    title = "Custom",
    subtitle = "Category",
    message = "Message here",
    duration = 5000,
    color = "#3498db",
    image = "https://example.com/icon.png"
})
Field Type Required Default Description
title string yes Notification title
type string no "info" One of "success", "error", "warning", "info"
subtitle string no Subtitle below the title
message string no Body text (description)
duration number no 5000 Display time in milliseconds
color string no Accent color (hex, e.g. "#e74c3c")
image string no Image URL shown at top-left of the notification

Clear All Notifications

zed.ClearNotifications()

Server-side Notifications

From the server, you can send notifications to a specific player or broadcast to all players using exports. No event is exposed for clients to trigger broadcasts (prevents abuse).

Server-side (in a server_scripts file or from another resource):

-- Send to a specific player (by server ID)
exports['zedlib']:Notify(source, {
    title = "Welcome",
    type = "info",
    message = "You are now connected.",
    duration = 5000
})

-- Broadcast to all players
exports['zedlib']:NotifyToAll({
    title = "Announcement",
    subtitle = "Server",
    message = "Restart in 5 minutes.",
    type = "warning",
    duration = 10000
})
Export Parameters Description
Notify(source, data) source = server ID, data = notification table Send a notification to a specific player
NotifyToAll(data) data = same table as above Broadcast a notification to all connected players

The data fields are the same as client-side notifications (see table above). Only the server can call these exports.


Dialogs

Input Dialog

Create a dialog with input fields and action buttons. The dialog captures NUI focus automatically.

zed.Dialog({
    title = "Spawn Vehicle",
    message = "Enter the vehicle details below",
    type = "input",
    closable = true,
    inputs = {
        {
            id = "model",
            type = "text",
            label = "Model Name",
            placeholder = "adder",
            required = true,
            maxLength = 32
        },
        {
            id = "color",
            type = "text",
            label = "Color (hex)",
            placeholder = "#FF0000",
        },
        {
            id = "amount",
            type = "number",
            label = "Quantity",
            default = 1,
            min = 1,
            max = 10
        },
    },
    buttons = {
        {
            label = "Cancel",
            variant = "secondary",
            action = "cancel",
        },
        {
            label = "Spawn",
            variant = "primary",
            action = "spawn",
            onPress = function(values)
                print("Model:", values.model)
                print("Color:", values.color)
                print("Amount:", values.amount)
            end
        },
    },
})

Dialog options:

Option Type Default Description
id string auto Custom dialog identifier
type string "input" "input" or "confirm"
title string Dialog title
message string nil Description text
inputs table nil Array of input field definitions
buttons table nil Array of button definitions
closable boolean true Whether the dialog can be dismissed with Escape
color string "#e74c3c" Accent color (hex) for header bar and primary button
icon string nil FontAwesome icon name in dialog header (e.g. "circle-question")
onResult function nil Global callback receiving (action, values) for any button press

Input field options:

Option Type Default Description
id string "input_N" Field identifier (key in values table)
type string "text" "text", "number", "password", or "textarea"
label string Field label
placeholder string nil Placeholder text
default any nil Default value
required boolean false Whether the field must be filled
maxLength number nil Maximum character length
min number nil Minimum value (number fields only)
max number nil Maximum value (number fields only)

Button options:

Option Type Default Description
label string Button text
variant string "secondary" "primary", "secondary", or "danger"
action string auto Action identifier sent to callbacks
icon string nil FontAwesome icon name before the label (e.g. "trash")
onPress function nil Callback receiving the values table

Using onResult Instead of Per-Button Callbacks

You can handle all button actions in a single callback:

zed.Dialog({
    title = "Delete Character",
    message = "This action is irreversible. Are you sure?",
    type = "confirm",
    buttons = {
        { label = "Keep",   variant = "secondary", action = "cancel" },
        { label = "Delete", variant = "danger",    action = "delete" },
    },
    onResult = function(action, values)
        if action == "delete" then
            print("Character deleted")
        else
            print("Cancelled")
        end
    end
})

Quick Confirm Dialog

A one-liner shortcut for simple yes/no confirmations:

zed.Confirm("Delete Vehicle?", "This will permanently remove your vehicle.",
    function()
        print("User confirmed")
        DeleteVehicle(GetVehiclePedIsIn(PlayerPedId(), true))
    end,
    function()
        print("User cancelled")
    end
)
Parameter Type Required Description
title string yes Dialog title
message string yes Dialog message
onConfirm function no Callback fired when the user confirms
onCancel function no Callback fired when the user cancels
color string no Accent color (hex) for the dialog

Close Dialog

zed.CloseDialog()

Configuration

Configuration File

ZedLib has a config.lua file at the root of the resource for static settings. Edit this file and restart the resource to apply changes.

-- zedlib/config.lua
ZedConfig = {
    accentColor = '#e74c3c',  -- Global accent color for all components (hex)
    showTitle = true,         -- Show the menu title in the header
    showItemCount = true,     -- Show the item counter (e.g. "3 / 12") in the header
    enableContextMenu = true, -- Enable the context menu system (ALT targeting)
}
Option Type Default Description
accentColor string '#e74c3c' Global accent color applied to menus, notifications, dialogs, and context menus. Per-component colors (e.g. menu color option, notification color field) override this.
showTitle boolean true Show menu title in the header (both banner and non-banner menus)
showItemCount boolean true Show the item counter (e.g. 3 / 12) in the header
enableContextMenu boolean true Enable the ALT-hold context menu targeting system

Runtime Configuration

Toggle settings dynamically at runtime from any script:

zed.SetConfig({
    sounds = false -- disable all UI sounds
})
Option Type Default Description
sounds boolean true Enable or disable UI sound effects (hover, select, toggle)

Keyboard and Mouse Navigation

When a menu is open, the following controls are active. Weapon and attack controls are automatically disabled.

Key / Input Action
Arrow Up Move selection up
Arrow Down Move selection down
Mouse wheel up Move selection up
Mouse wheel down Move selection down
Enter Select / Toggle current item
Arrow Left Previous option (list) / Decrease (slider)
Arrow Right Next option (list) / Increase (slider)
Backspace Go back to parent menu
Escape Close the menu entirely

Hold arrow keys for auto-repeat (300ms initial delay, 80ms repeat interval). The mouse wheel can also be used to move the selection when the menu is open.


Full API Reference

Menu Functions

Function Parameters Returns Description
CreateMenu id, title, subtitle?, opts? Register a new menu
AddButton menuId, opts itemId Add a button item
AddCheckbox menuId, opts itemId Add a checkbox item
AddList menuId, opts itemId Add a list selector
AddSlider menuId, opts itemId Add a slider
AddSeparator menuId, opts? itemId Add a visual separator (opts: category)
AddCategory menuId, opts categoryId Add a category header (expand/collapse items)
AddSearchButton menuId, opts? itemId Add a search/filter input
AddInfoButton menuId, opts itemId Add an info button (hover panel with label/value)
AddSubMenu menuId, subMenuId, label, opts? subMenuId Link and register a submenu
OpenMenu id Open a menu
CloseMenu Close the current menu
IsMenuOpen boolean Check if a menu is open
RemoveMenu id Remove a menu and free resources

Notification Functions

Function Parameters Returns Description
Notify data: { title, type?, subtitle?, message?, duration?, color?, image? } Show a notification
ClearNotifications Dismiss all notifications

Server exports: exports['zedlib']:Notify(source, data) for a specific player, exports['zedlib']:NotifyToAll(data) for all. See Server-side Notifications.

Dialog Functions

Function Parameters Returns Description
Dialog opts dialogId Open an input/custom dialog (opts: color, icon, inputs type textarea, button icon)
Confirm title, message, onConfirm?, onCancel?, color? Open a quick confirm dialog
CloseDialog Close the active dialog

Context Menu Functions

Function Parameters Returns Description
AddContextOption opts optionId Register an option (by type, entity, or model)
AddContextSubMenu opts submenuId Register a submenu (by type, entity, or model)
RemoveContextOption id Remove a context option by id
ClearContext Remove all options and submenus
SetContextEnabled enabled Enable or disable ALT targeting
IsContextEnabled boolean Check if targeting is enabled
IsContextOpen boolean Check if a context menu is visible
CloseContext Force close the context menu

Options support type (entity type filter), entity (specific entity handle), or model (model name/hash). Auto-cleanup on resource stop.

Progress Bar Functions

Function Parameters Returns Description
ProgressBar opts boolean Show a blocking progress bar. Returns true if completed, false if cancelled
CancelProgressBar Cancel the active progress bar
IsProgressActive boolean Check if a progress bar is running

Interact Functions

Function Parameters Returns Description
Interact opts Set the current interact prompt (coords, label, key?, distance?, onSelect?)
ClearInteract Clear the current interact prompt
InteractProgress opts Set hold-to-complete prompt (duration, onSelect?, onCancel?)
ClearInteractProgress Clear the current interact progress prompt

Configuration Functions

Function Parameters Returns Description
SetConfig opts Update runtime configuration

Utility Functions

Function Parameters Returns Description
CopyToClipboard text Copy text to the player's clipboard
zed.CopyToClipboard("Hello world!")

Complete Example

A full working example combining menus, submenus, notifications, and dialogs:

-- In your resource's client.lua (with @zedlib/import.lua loaded)

RegisterCommand("mymenu", function()
    -- Create menus
    zed.CreateMenu("main", "Admin Panel", "Server Administration", {
        banner = "https://forum-cfx-re.akamaized.net/original/4X/d/1/2/d12e827f6eba4f2b64c78dc10895aefe4eaffd4e.jpeg",
        color = "#e74c3c"
    })

    -- Player actions
    zed.AddButton("main", {
        label = "Heal Player",
        icon = "heart",
        description = "Restore full health",
        onSelect = function()
            SetEntityHealth(PlayerPedId(), 200)
            zed.Notify({ title = "Healed", message = "Health restored to full" })
        end
    })

    zed.AddCheckbox("main", {
        label = "Invisible",
        icon = "eye-slash",
        checked = false,
        onChange = function(checked)
            SetEntityVisible(PlayerPedId(), not checked, false)
            zed.Notify({ title = "Visibility", message = checked and "You are now invisible" or "You are now visible" })
        end
    })

    zed.AddSeparator("main")

    -- Vehicle submenu
    zed.AddSubMenu("main", "vehicles", "Vehicles", {
        icon = "car",
        subtitle = "Vehicle Management"
    })

    zed.AddButton("vehicles", {
        label = "Spawn Vehicle",
        icon = "plus",
        onSelect = function()
            zed.CloseMenu()
            zed.Dialog({
                title = "Spawn Vehicle",
                message = "Enter a vehicle model name",
                inputs = {
                    { id = "model", type = "text", label = "Model", placeholder = "adder", required = true }
                },
                buttons = {
                    { label = "Cancel", variant = "secondary", action = "cancel" },
                    {
                        label = "Spawn",
                        variant = "primary",
                        action = "spawn",
                        onPress = function(values)
                            print("Spawning:", values.model)
                        end
                    }
                }
            })
        end
    })

    zed.AddList("vehicles", {
        label = "Vehicle Color",
        icon = "palette",
        items = {
            { label = "Red",    value = 27 },
            { label = "Blue",   value = 64 },
            { label = "Green",  value = 55 },
            { label = "Black",  value = 0 },
            { label = "White",  value = 134 },
        },
        currentIndex = 1,
        onChange = function(index, item)
            local veh = GetVehiclePedIsIn(PlayerPedId(), false)
            if veh ~= 0 then
                SetVehicleColours(veh, item.value, item.value)
            end
        end
    })

    zed.AddSlider("vehicles", {
        label = "Max Speed",
        icon = "gauge-high",
        min = 50,
        max = 300,
        step = 25,
        value = 150,
        onChange = function(value)
            local veh = GetVehiclePedIsIn(PlayerPedId(), false)
            if veh ~= 0 then
                SetVehicleMaxSpeed(veh, value + 0.0)
            end
        end
    })

    -- Danger zone submenu
    zed.AddSubMenu("main", "danger", "Danger Zone", {
        icon = "triangle-exclamation",
        color = "#c0392b"
    })

    zed.AddButton("danger", {
        label = "Delete Nearby Vehicles",
        icon = "trash",
        onSelect = function()
            zed.CloseMenu()
            zed.Confirm("Delete Vehicles?", "This will remove all vehicles in a 50m radius.",
                function()
                    zed.Notify({ title = "Deleted", message = "Nearby vehicles have been removed" })
                end,
                function()
                    zed.Notify({ title = "Cancelled", message = "No vehicles were deleted" })
                end
            )
        end
    })

    -- Search (useful for long menus)
    zed.AddSearchButton("main", {
        label = "Search",
        placeholder = "Filter options..."
    })

    zed.OpenMenu("main")
end)

Development

Start the Vite dev server for local UI development without FiveM:

cd zedlib/web
npm install
npm run dev

This opens a dev server with a Playground panel for testing all components interactively.

Production Build

cd zedlib/web
npm run build

Output goes to web/dist/, referenced by fxmanifest.lua.


Project Structure

zedlib/
├── fxmanifest.lua            # FiveM resource manifest
├── config.lua                # Static configuration (title, item count, context menu)
├── import.lua                # zed.* API wrapper with cross-resource callback support
├── lua/
│   ├── client.lua            # NUI bridge, keyboard controls, callback routing
│   └── api/                  # Lua API split by component
│       ├── _init.lua         # UI table, ZedInternal (generateId, fireCallback)
│       ├── menu.lua          # CreateMenu, AddButton, AddCheckbox, AddCategory, AddInfoButton, etc.
│       ├── notification.lua  # Notify, ClearNotifications
│       ├── dialog.lua        # Dialog, Confirm, CloseDialog
│       ├── context.lua       # AddContextOption, AddContextSubMenu, entity/model targeting
│       ├── progressbar.lua   # ProgressBar, CancelProgressBar, IsProgressActive
│       ├── interact.lua      # SetInteract, ClearInteract, SetInteractProgress, ClearInteractProgress
│       ├── config.lua        # SetConfig
│       └── exports.lua       # FiveM exports for all functions
├── lua/events/
│       └── notification.lua  # Server-side Notify, NotifyToAll exports
└── web/
    ├── package.json
    ├── src/
    │   ├── main.tsx           # React entry point
    │   ├── App.tsx            # Root component
    │   ├── core/              # EventBus, PluginSystem, Registry, Sounds
    │   ├── components/        # Menu, Dialog, Notification (menu: category, info panel)
    │   ├── stores/            # Zustand state stores
    │   ├── hooks/             # useNui, useKeyboard, useMenu
    │   ├── nui/               # NUI bridge and message handlers
    │   ├── types/             # TypeScript type definitions
    │   └── devtools/          # Dev playground
    └── dist/                  # Production build output

License

MIT

About

Zed Library is a comprehensive library built for FiveM, designed to help developers easily create modern, responsive, and high-performance user interfaces directly in-game.

Resources

License

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages