--- title: Creating a custom window summary: Build a Lua UI with a frame, table, text, button and correct cleanup. section: ui kind: example status: example tags: ["X4","modding","create","ui"] sources: ["https://wiki.egosoft.com/X4%20Foundations%20Wiki/Modding%20Support/Breaking%20Changes/"] --- ## Choose an approach For a small setting, consider a [settings menu API](wiki:ui-settings). To add a card or action to an existing menu, start with [extending the standard UI](wiki:extend-ui). A custom window can use Helper to create a frame, table, rows and widgets, then display it. Python and a network service are not required. ## Register Lua Declare the Lua file in your extension's `ui.xml`, as shown below. Wait until Helper and the game UI are ready before opening the window. Loading a Lua file does not mean the world and every menu already exist. ```xml ``` ## Build the window The `ui/wiki_panel.lua` example registers its menu once. A separate event opens the panel after UI readiness. It creates a frame on layer 3, adds a table and text, binds a Close button and displays the frame. Check internal callbacks and layer usage against the current game UI. The MD `raise_lua_event` fragment belongs inside an existing `actions` block. Your mod supplies the trigger, such as a working button or event. The example does not install a hotkey automatically. ```lua local menu = { name = "WikiExamplePanel" } menu.onViewCreated = function() end menu.onRowChanged = function() end menu.onSelectElement = function() end function menu.onCloseElement() if menu.shown then Helper.clearFrame(menu, 3) menu.shown = false end end Menus = Menus or {} table.insert(Menus, menu) Helper.registerMenu(menu) local function showPanel() if menu.shown then return end local width = Helper.scaleX(480) local height = Helper.scaleY(150) local frame = Helper.createFrameHandle(menu, { layer = 3, x = (Helper.viewWidth - width) / 2, y = (Helper.viewHeight - height) / 2, width = width, height = height, standardButtons = {}, startAnimation = false, playerControls = true, }) local t = frame:addTable(1, { tabOrder = 1, width = width }) local title = t:addRow(false, {}) title[1]:createText("Hello, X4!", { fontsize = 14 }) local row = t:addRow(true, {}) row[1]:createButton({ height = 28 }):setText("Close") row[1].handlers.onClick = menu.onCloseElement menu.shown = true frame:display() end RegisterEvent("Wiki.ShowPanel", function() showPanel() end) ``` ```xml ``` ## Verify the lifecycle Repeated opening must not accumulate callbacks. Test the Close button, Escape/controller behavior, menu changes and save loading. A table with insufficient height can disappear entirely. Do not clear another menu's frame or alter global player control just to display text. This template illustrates Helper forms and has not been separately tested in game across X4 versions.