# API Reference

This guide demonstrates real-world usage patterns of InfinityUI through common use cases and best practices.

***

## 🏗️ Basic Structure

### Recommended Architecture

For a complete system, organize your menus this way:

```lua
-- 1. Global variables
local data = {}
local mainMenu
local subMenu1
local subMenu2

-- 2. Network events (if needed)
RegisterNetEvent("myEvent", function(callback)
    -- Handle data
end)

-- 3. Utility functions
local function myFunction()
    -- Logic
end

-- 4. Main command
RegisterCommand("mymenu", function()
    -- Create menus
    mainMenu = InfinityUI.CreateMenu("Title", "Subtitle")
    subMenu1 = InfinityUI.CreateSubMenu(mainMenu, "Sub Menu 1", "Description")
    
    -- Open menu
    InfinityUI.Visible(mainMenu, true)
    
    -- Render loop
    while InfinityUI.Visible(mainMenu) or InfinityUI.Visible(subMenu1) do
        Citizen.Wait(0)
        
        InfinityUI.IsVisible(mainMenu, function()
            -- Main menu content
        end)
        
        InfinityUI.IsVisible(subMenu1, function()
            -- Sub menu content
        end)
    end
end)
```

{% hint style="info" %}
**Key Pattern**: Use a single `while` loop to handle all your menus with `or` between conditions.
{% endhint %}

***

## 🎯 Menu Navigation

### Creating Menu Hierarchy

**Pattern: Main Menu with Multiple Sub-Menus**

```lua
RegisterCommand("system", function()
    local mainMenu = InfinityUI.CreateMenu("System", "Main Menu")
    local createMenu = InfinityUI.CreateSubMenu(mainMenu, "Create", "Create new item")
    local listMenu = InfinityUI.CreateSubMenu(mainMenu, "List", "View all items")
    local manageMenu = InfinityUI.CreateSubMenu(mainMenu, "Manage", "Edit item")
    
    InfinityUI.Visible(mainMenu, true)
    
    while InfinityUI.Visible(mainMenu) or InfinityUI.Visible(createMenu) 
       or InfinityUI.Visible(listMenu) or InfinityUI.Visible(manageMenu) do
        Citizen.Wait(0)
        
        InfinityUI.IsVisible(mainMenu, function()
            -- Navigation buttons
            InfinityUI.Button("View List", nil, {RightLabel = ">>>"}, true, {}, listMenu)
            InfinityUI.Button("Create New", nil, {RightLabel = ">>>"}, true, {}, createMenu)
        end)
        
        -- Other menu contents...
    end
end)
```

**Key Points:**

* ✅ Create all menus before opening
* ✅ Use one `while` loop with `or` conditions
* ✅ Use `RightLabel = ">>>"` for navigation buttons (Optional)
* ✅ Pass the target menu as the last parameter

***

### Navigation with Data Loading

**Pattern: Load Data Before Navigation**

```lua
InfinityUI.Button("View List", nil, {RightLabel = ">>>"}, true, {
    onSelected = function()
        -- Load data from server before opening submenu
        TriggerServerEvent("request_data_list")
    end
}, listMenu)
```

**When to use:**

* Loading data from database
* Fetching fresh information
* Validating permissions before access

***

## 📝 Input Forms

### Text Input with ox\_lib

**Pattern: Simple Text Input**

```lua
InfinityUI.Button("Set Name", nil, {RightLabel = ">>>"}, true, {
    onSelected = function()
        local input = lib.inputDialog("Enter Name", {
            {
                type = 'input',
                label = 'Item Name',
                required = true,
                placeholder = 'Enter name here'
            }
        })
        
        if input and input[1] then
            data.name = input[1]
        end
    end
})
```

**Key Points:**

* ✅ Always check if `input` exists
* ✅ Access value with `input[1]`
* ✅ Set `required = true` for mandatory fields
* ✅ Use `placeholder` for hints

***

### Dynamic Button Labels

**Pattern: Show Current Value in Button**

```lua
InfinityUI.Button(
    data.name and "Name (Current: " .. data.name .. ")" or "Name (Not Set)",
    nil,
    {RightLabel = ">>>"},
    true,
    {
        onSelected = function()
            -- Input logic
        end
    }
)
```

**Benefits:**

* Shows current state
* Clear visual feedback
* Better UX

**Formula:**

```lua
data.field and "Label (Current: " .. data.field .. ")" or "Label (Default)"
```

***

### Multi-Field Form

**Pattern: Multiple Inputs in One Dialog**

```lua
InfinityUI.Button("Configure Item", nil, {RightLabel = ">>>"}, true, {
    onSelected = function()
        local input = lib.inputDialog("Item Configuration", {
            {
                type = 'input',
                label = 'Name',
                required = true,
                placeholder = 'Item name'
            },
            {
                type = 'number',
                label = 'Price',
                required = true,
                min = 0,
                max = 999999
            },
            {
                type = 'textarea',
                label = 'Description',
                required = false,
                placeholder = 'Optional description'
            }
        })
        
        if input then
            data.name = input[1]
            data.price = input[2]
            data.description = input[3]
        end
    end
})
```

***

### Checkbox for Boolean Values

**Pattern: Toggle with Checkbox**

```lua
InfinityUI.Checkbox(
    "Enable Feature",
    "Description of the feature",
    data.enabled or false,
    {},
    {
        onChecked = function()
            data.enabled = not data.enabled
        end,
        onUnChecked = function()
            data.enabled = not data.enabled
        end
    }
)
```

{% hint style="info" %}
**Tip**: Both `onChecked` and `onUnChecked` should toggle the value to ensure proper synchronization.
{% endhint %}

***

## 🗂️ Dynamic Lists

### Rendering Items from Table

**Pattern: Loop Through Data**

```lua
local items = {}
local itemList = {}

-- Populate list (from server event)
RegisterNetEvent("receive_items", function(data)
    items = {}
    itemList = {}
    
    for id, item in pairs(data) do
        item.id = id
        items[id] = item
        table.insert(itemList, item)
    end
end)

-- Render in menu
InfinityUI.IsVisible(listMenu, function()
    if not itemList or #itemList == 0 then
        InfinityUI.Button("No items available", nil, {TextColor = {255, 0, 0}}, false, {})
    else
        for i, item in ipairs(itemList) do
            InfinityUI.Button(
                "[" .. item.id .. "] " .. item.name,
                item.description,
                {RightLabel = ">>>"},
                true,
                {
                    onSelected = function()
                        selectedItem = item.id
                    end
                },
                detailsMenu
            )
        end
    end
end)
```

**Key Points:**

* ✅ Separate `items` (key-value) and `itemList` (array) for different access patterns
* ✅ Show "No items" message when list is empty
* ✅ Disable empty state button (`false` parameter)
* ✅ Store selection in variable for next menu

***

### Empty State Handling

**Pattern: Graceful Empty State**

```lua
if not itemList or #itemList == 0 or not items then
    InfinityUI.Button(
        "No items loaded",
        "Click 'Refresh' to load",
        {TextColor = {255, 165, 0}}, -- Orange
        false,
        {}
    )
else
    -- Render items
end
```

***

### Item Selection Flow

**Pattern: List → Select → Details**

```lua
local selectedItem = nil

-- List Menu
InfinityUI.IsVisible(listMenu, function()
    for i, item in ipairs(itemList) do
        InfinityUI.Button(
            item.name,
            nil,
            {RightLabel = ">>>"},
            true,
            {
                onSelected = function()
                    selectedItem = item.id
                end
            },
            detailsMenu
        )
    end
end)

-- Details Menu
InfinityUI.IsVisible(detailsMenu, function()
    if not selectedItem or not items[selectedItem] then
        InfinityUI.Button("No item selected", nil, {}, false, {})
        return
    end
    
    local item = items[selectedItem]
    
    InfinityUI.Button("Name: " .. item.name, nil, {}, true, {})
    InfinityUI.Button("Price: $" .. item.price, nil, {}, true, {})
    
    InfinityUI.Button("Delete", nil, {TextColor = {255, 0, 0}}, true, {
        onSelected = function()
            TriggerServerEvent("delete_item", selectedItem)
        end
    }, listMenu)
end)
```

***

## 💾 Data Management

### Using a Data Object

**Pattern: Centralized Data Storage**

```lua
local data = {}

-- Setting values
data.name = "Item Name"
data.price = 100
data.enabled = true

-- Using in buttons
InfinityUI.Button(
    data.name and "Name: " .. data.name or "Name (Not Set)",
    nil,
    {},
    true,
    {}
)

-- Sending to server
InfinityUI.Button("Save", nil, {}, true, {
    onSelected = function()
        TriggerServerEvent("save_data", data)
    end
})
```

**Benefits:**

* Single source of truth
* Easy to reset: `data = {}`
* Simple server communication

***

### Resetting Form Data

**Pattern: Clear After Submit**

```lua
RegisterNetEvent("item_created", function(success)
    if success then
        data = {} -- Reset form
        InfinityUI.Visible(createMenu, false) -- Close menu
        exports.core:SendNotification("Success", "Item created!", 3000)
    end
end)
```

***

### Separating Data Structures

**Pattern: Dictionary + Array**

```lua
local items = {}      -- Key-value for quick access
local itemList = {}   -- Array for iteration

RegisterNetEvent("receive_data", function(callback)
    items = {}
    itemList = {}
    
    for id, item in pairs(callback) do
        item.id = id
        items[id] = item          -- Direct access: items[5]
        table.insert(itemList, item)  -- Loop: for i, item in ipairs
    end
end)

-- Access by ID
local item = items[selectedId]

-- Iterate in order
for i, item in ipairs(itemList) do
    -- ...
end
```

***

## ✅ Validation & Parsing

### Position Formatting

**Pattern: Get and Format Coordinates**

```lua
local function getFormattedLocation()
    local ped = GetPlayerPed(PlayerId())
    local location = GetEntityCoords(ped)
    
    if not location or not (location.x and location.y and location.z) then
        return nil
    end
    
    return {
        x = location.x,
        y = location.y,
        z = location.z
    }
end

local function formatPos(pos)
    if not pos then return "Not Set" end
    return string.format("X: %.2f Y: %.2f Z: %.2f", pos.x, pos.y, pos.z)
end

-- Usage
InfinityUI.Button(
    data.position and formatPos(data.position) or "Set Position (Current)",
    nil,
    {},
    true,
    {
        onSelected = function()
            data.position = getFormattedLocation()
        end
    }
)
```

***

### Color Input Validation

**Pattern: Parse and Validate RGBA**

```lua
local function parseRGBA(input)
    if type(input) ~= "string" then return nil end
    
    -- Extract numbers: "255, 128, 0, 255"
    local r, g, b, a = input:match("^%s*(%d+)%s*,%s*(%d+)%s*,%s*(%d+)%s*,%s*(%d+)%s*$")
    
    if not r then return nil end
    
    r, g, b, a = tonumber(r), tonumber(g), tonumber(b), tonumber(a)
    
    -- Validate
    if not r or not g or not b or not a then return nil end
    if r > 255 or g > 255 or b > 255 or a > 255 then return nil end
    
    return { r = r, g = g, b = b, a = a }
end

local function formatRGBA(color)
    if not color then return "Not Set" end
    return string.format("R:%d G:%d B:%d A:%d", color.r, color.g, color.b, color.a or 255)
end

-- Usage
InfinityUI.Button(
    data.color and "Color (" .. formatRGBA(data.color) .. ")" or "Set Color",
    nil,
    {RightLabel = ">>>"},
    true,
    {
        onSelected = function()
            local input = lib.inputDialog("Color", {
                {
                    type = 'input',
                    label = 'Enter RGBA (R, G, B, A)',
                    required = true,
                    placeholder = '255, 255, 255, 255'
                }
            })
            
            if not input or not input[1] then return end
            
            local color = parseRGBA(input[1])
            
            if not color then
                exports.core:SendNotification("Error", "Invalid format. Use: R, G, B, A (0-255)", 4000)
                return
            end
            
            data.color = color
        end
    }
)
```

**Validation Checklist:**

* ✅ Check type before parsing
* ✅ Validate format with regex
* ✅ Convert to numbers
* ✅ Range check (0-255)
* ✅ Show error message if invalid

***

### Number Validation

**Pattern: Validate Numeric Input**

```lua
local function validateNumber(input, min, max)
    local num = tonumber(input)
    if not num then return nil, "Not a valid number" end
    if min and num < min then return nil, "Value too low (min: " .. min .. ")" end
    if max and num > max then return nil, "Value too high (max: " .. max .. ")" end
    return num
end

-- Usage
InfinityUI.Button("Set Price", nil, {RightLabel = ">>>"}, true, {
    onSelected = function()
        local input = lib.inputDialog("Price", {
            {
                type = 'input',
                label = 'Enter price',
                required = true,
                placeholder = '100'
            }
        })
        
        if not input or not input[1] then return end
        
        local price, error = validateNumber(input[1], 0, 999999)
        
        if not price then
            exports.core:SendNotification("Error", error, 3000)
            return
        end
        
        data.price = price
    end
})
```

***

## 🌐 Server Integration

### Request-Response Pattern

**Client Side:**

```lua
-- Request data
InfinityUI.Button("Load Items", nil, {RightLabel = ">>>"}, true, {
    onSelected = function()
        TriggerServerEvent("request_items")
    end
}, itemListMenu)

-- Receive response
RegisterNetEvent("receive_items", function(items)
    -- Process items
    itemList = {}
    for id, item in pairs(items) do
        item.id = id
        table.insert(itemList, item)
    end
end)
```

**Server Side:**

```lua
RegisterNetEvent("request_items", function()
    local source = source
    local items = GetItemsFromDatabase()
    TriggerClientEvent("receive_items", source, items)
end)
```

***

### Create/Update/Delete Operations

**Client: Create**

```lua
InfinityUI.Button("Create", nil, {RightLabel = ">>>"}, true, {
    onSelected = function()
        TriggerServerEvent("create_item", data)
    end
}, mainMenu)

RegisterNetEvent("item_created", function(success)
    if success then
        data = {}
        exports.core:SendNotification("Success", "Item created!", 3000)
    end
end)
```

**Client: Delete**

```lua
InfinityUI.Button("Delete", nil, {TextColor = {255, 0, 0}}, true, {
    onSelected = function()
        TriggerServerEvent("delete_item", selectedItem)
    end
}, listMenu)

RegisterNetEvent("item_deleted", function(success)
    if success then
        selectedItem = nil
        TriggerServerEvent("request_items") -- Refresh list
    end
end)
```

***

### Error Handling

**Pattern: Handle Server Errors**

```lua
RegisterNetEvent("operation_result", function(success, error)
    if success then
        exports.core:SendNotification("Success", "Operation completed", 3000)
        InfinityUI.CloseAll()
    else
        exports.core:SendNotification("Error", error or "An error occurred", 5000)
    end
end)
```

***

## 🎨 Advanced Patterns

### Conditional Button Styling

**Pattern: Visual Feedback Based on State**

```lua
-- Error state (red text)
InfinityUI.Button(
    "Delete Item",
    "This action cannot be undone",
    {TextColor = {255, 0, 0}}, -- Red
    true,
    {}
)

-- Success state (green background)
InfinityUI.Button(
    "Confirm",
    nil,
    {Color = { BackgroundColor = {0, 255, 0, 190} }}, -- Green
    true,
    {}
)

-- Info state (blue background)
InfinityUI.Button(
    "Save",
    nil,
    {Color = { BackgroundColor = {66, 133, 244, 190} }}, -- Blue
    true,
    {}
)

-- Disabled state
InfinityUI.Button(
    "Locked Feature",
    "Requires premium",
    {TextColor = {128, 128, 128}}, -- Gray
    false, -- Disabled
    {}
)
```

**Color Guide:**

```lua
-- Reds (Danger/Delete)
{255, 0, 0}     -- Bright red
{185, 0, 0}     -- Dark red

-- Greens (Success/Confirm)
{0, 255, 0}     -- Bright green
{0, 153, 0}     -- Dark green

-- Blues (Info/Primary)
{66, 133, 244}  -- Material blue
{0, 153, 204}   -- Cyan blue

-- Grays (Disabled/Neutral)
{128, 128, 128} -- Gray
{200, 200, 200} -- Light gray

-- Orange (Warning)
{255, 165, 0}   -- Orange
```

***

### Toggle Menu Visibility

**Pattern: Open/Close with Same Command**

```lua
RegisterCommand("mymenu", function()
    mainMenu = InfinityUI.CreateMenu("Title", "Subtitle")
    
    -- Toggle: if open, close; if closed, open
    InfinityUI.Visible(mainMenu, not InfinityUI.Visible(mainMenu))
    
    while InfinityUI.Visible(mainMenu) do
        Citizen.Wait(0)
        InfinityUI.IsVisible(mainMenu, function()
            -- Content
        end)
    end
end)
```

***

### Conditional Menu Content

**Pattern: Show Different Content Based on State**

```lua
InfinityUI.IsVisible(mainMenu, function()
    if playerHasPermission then
        InfinityUI.Button("Admin Panel", nil, {RightLabel = ">>>"}, true, {}, adminMenu)
    end
    
    if playerLevel >= 10 then
        InfinityUI.Button("Premium Shop", nil, {RightLabel = ">>>"}, true, {}, shopMenu)
    else
        InfinityUI.Button("Premium Shop (Locked)", "Reach level 10", {}, false, {})
    end
end)
```

***

### Confirmation Dialog

**Pattern: Two-Step Confirmation**

```lua
local confirmDelete = false

InfinityUI.IsVisible(deleteMenu, function()
    if not confirmDelete then
        InfinityUI.Button("Delete Item", "Click again to confirm", {TextColor = {255, 165, 0}}, true, {
            onSelected = function()
                confirmDelete = true
            end
        })
    else
        InfinityUI.Button("⚠️ CONFIRM DELETE", "This cannot be undone!", {TextColor = {255, 0, 0}}, true, {
            onSelected = function()
                TriggerServerEvent("delete_item", selectedItem)
                confirmDelete = false
            end
        })
        
        InfinityUI.Button("Cancel", nil, {}, true, {
            onSelected = function()
                confirmDelete = false
            end
        }, listMenu)
    end
end)
```

***

### Progressive Form

{% stepper %}
{% step %}

### Step 1: Basic Info

Pattern: Multi-Step Form first step

```lua
local formStep = 1
local formData = {}

InfinityUI.IsVisible(createMenu, function()
    if formStep == 1 then
        InfinityUI.Button("Step 1: Basic Info", nil, {}, true, {})
        -- Basic info inputs
        InfinityUI.Button("Next", nil, {RightLabel = ">>>"}, true, {
            onSelected = function()
                formStep = 2
            end
        })
    end
end)
```

{% endstep %}

{% step %}

### Step 2: Details

Pattern: Multi-Step Form second step

```lua
InfinityUI.IsVisible(createMenu, function()
    if formStep == 2 then
        InfinityUI.Button("Step 2: Details", nil, {}, true, {})
        -- Detail inputs
        InfinityUI.Button("Back", nil, {}, true, {
            onSelected = function()
                formStep = 1
            end
        })
        InfinityUI.Button("Next", nil, {RightLabel = ">>>"}, true, {
            onSelected = function()
                formStep = 3
            end
        })
    end
end)
```

{% endstep %}

{% step %}

### Step 3: Review

Pattern: Multi-Step Form third step

```lua
InfinityUI.IsVisible(createMenu, function()
    if formStep == 3 then
        InfinityUI.Button("Step 3: Review", nil, {}, true, {})
        -- Show summary
        InfinityUI.Button("Back", nil, {}, true, {
            onSelected = function()
                formStep = 2
            end
        })
        InfinityUI.Button("Submit", nil, {Color = {BackgroundColor = {0, 255, 0, 190}}}, true, {
            onSelected = function()
                TriggerServerEvent("submit_form", formData)
                formStep = 1
                formData = {}
            end
        })
    end
end)
```

{% endstep %}
{% endstepper %}

***

## 📊 Best Practices Summary

### ✅ DO

```lua
-- ✅ Create menus outside the loop
local menu = InfinityUI.CreateMenu("Title", "Subtitle")
while InfinityUI.Visible(menu) do
    -- ...
end

-- ✅ Check data before using
if data and data.field then
    -- Use data.field
end

-- ✅ Validate user input
local value = validateInput(input[1])
if not value then return end

-- ✅ Show current state in labels
data.name and "Name: " .. data.name or "Name (Not Set)"

-- ✅ Use proper error handling
if not success then
    exports.core:SendNotification("Error", errorMsg, 3000)
    return
end

-- ✅ Reset data after operations
RegisterNetEvent("success", function()
    data = {}
end)
```

### ❌ DON'T

```lua
-- ❌ Create menus inside the loop
while true do
    local menu = InfinityUI.CreateMenu(...) -- NO!
end

-- ❌ Access data without checking
local value = data.field -- Could be nil!

-- ❌ No validation
data.price = input[1] -- What if it's not a number?

-- ❌ Static labels
InfinityUI.Button("Name", ...) -- User doesn't see current value

-- ❌ Ignore errors
TriggerServerEvent("action")
-- No error handling!

-- ❌ Keep old data
-- Data persists between operations - causes issues
```

***

## 🎯 Common Patterns Cheat Sheet

| Pattern             | Use Case           | Code                                                                    |
| ------------------- | ------------------ | ----------------------------------------------------------------------- |
| **Navigation**      | Go to submenu      | `InfinityUI.Button("Go", nil, {RightLabel = ">>>"}, true, {}, submenu)` |
| **Load & Navigate** | Fetch before open  | `{onSelected = function() TriggerServerEvent("load") end}, submenu`     |
| **Dynamic Label**   | Show current value | `data.field and "Label: " .. data.field or "Label (Default)"`           |
| **Input**           | Get user input     | `lib.inputDialog("Title", {{type='input', label='...'}})`               |
| **Validation**      | Check input        | `if not validate(input) then return end`                                |
| **Empty State**     | No data            | `if #list == 0 then Button("No items", nil, {}, false) end`             |
| **Selection**       | Pick from list     | `{onSelected = function() selected = item.id end}, detailsMenu`         |
| **Confirmation**    | Two-step delete    | `local confirm = false` + toggle state                                  |
| **Color Coding**    | Visual feedback    | `{TextColor = {255, 0, 0}}` or `{Color = {BackgroundColor = {...}}}`    |
| **Server Call**     | Send data          | `TriggerServerEvent("event", data)`                                     |

***

## 🚀 Complete Example Template

Here's a template you can copy and adapt (Do not forget to implement the server part):

```lua
-- ========== VARIABLES ==========
local data = {}
local items = {}
local itemList = {}
local selectedItem = nil

-- ========== UTILITY FUNCTIONS ==========
local function resetData()
    data = {}
end

local function validateInput(input)
    -- Your validation logic
    return input ~= nil and input ~= ""
end

-- ========== NETWORK EVENTS ==========
RegisterNetEvent("receive_items", function(callback)
    items = {}
    itemList = {}
    for id, item in pairs(callback) do
        item.id = id
        items[id] = item
        table.insert(itemList, item)
    end
end)

RegisterNetEvent("operation_success", function()
    resetData()
    exports.core:SendNotification("Success", "Operation completed", 3000)
end)

-- ========== MAIN COMMAND ==========
RegisterCommand("mysystem", function()
    -- Create menus
    local mainMenu = InfinityUI.CreateMenu("My System", "Main Menu")
    local createMenu = InfinityUI.CreateSubMenu(mainMenu, "Create", "Create New Item")
    local listMenu = InfinityUI.CreateSubMenu(mainMenu, "List", "View All Items")
    local detailsMenu = InfinityUI.CreateSubMenu(mainMenu, "Details", "Item Details")
    
    -- Open
    InfinityUI.Visible(mainMenu, true)
    
    -- Render loop
    while InfinityUI.Visible(mainMenu) or InfinityUI.Visible(createMenu) 
       or InfinityUI.Visible(listMenu) or InfinityUI.Visible(detailsMenu) do
        Citizen.Wait(0)
        
        -- MAIN MENU
        InfinityUI.IsVisible(mainMenu, function()
            InfinityUI.Button("View List", nil, {RightLabel = ">>>"}, true, {
                onSelected = function()
                    TriggerServerEvent("request_items")
                end
            }, listMenu)
            
            InfinityUI.Button("Create New", nil, {RightLabel = ">>>"}, true, {}, createMenu)
        end)
        
        -- CREATE MENU
        InfinityUI.IsVisible(createMenu, function()
            InfinityUI.Button(
                data.name and "Name: " .. data.name or "Set Name",
                nil,
                {RightLabel = ">>>"},
                true,
                {
                    onSelected = function()
                        local input = lib.inputDialog("Name", {
                            {type = 'input', label = 'Enter name', required = true}
                        })
                        if input and input[1] then
                            data.name = input[1]
                        end
                    end
                }
            )
            
            InfinityUI.Button("Create", nil, {Color = {BackgroundColor = {0, 255, 0, 190}}}, true, {
                onSelected = function()
                    if not data.name then
                        exports.core:SendNotification("Error", "Name required", 3000)
                        return
                    end
                    TriggerServerEvent("create_item", data)
                end
            }, mainMenu)
        end)
        
        -- LIST MENU
        InfinityUI.IsVisible(listMenu, function()
            if not itemList or #itemList == 0 then
                InfinityUI.Button("No items", nil, {TextColor = {255, 165, 0}}, false, {})
            else
                for i, item in ipairs(itemList) do
                    InfinityUI.Button(
                        item.name,
                        nil,
                        {RightLabel = ">>>"},
                        true,
                        {
                            onSelected = function()
                                selectedItem = item.id
                            end
                        },
                        detailsMenu
                    )
                end
            end
        end)
        
        -- DETAILS MENU
        InfinityUI.IsVisible(detailsMenu, function()
            if not selectedItem or not items[selectedItem] then
                InfinityUI.Button("No item selected", nil, {}, false, {})
                return
            end
            
            local item = items[selectedItem]
            InfinityUI.Button("Name: " .. item.name, nil, {}, true, {})
            
            InfinityUI.Button("Delete", nil, {TextColor = {255, 0, 0}}, true, {
                onSelected = function()
                    TriggerServerEvent("delete_item", selectedItem)
                    selectedItem = nil
                end
            }, listMenu)
        end)
    end
end, false)
```

***

{% hint style="success" %}
**You're ready to build!** Use these patterns as a foundation and adapt them to your specific needs. Check the [API Reference](https://infinityui.docs.hibry.net/broken-reference) for complete function details.
{% endhint %}

***

<details>

<summary>Need more help? (Expand)</summary>

* Join our Discord: support.md
* Check the FAQ: faq.md

</details>
