# esx_textui (/docs/core/esx_textui)

esx_textui shows one persistent prompt on the screen, typically an interaction
hint such as "Press [E] to open the shop". Unlike a notification it stays until
you hide it. Call `ESX.TextUI` when the player enters an interaction area and
`ESX.HideUI` when they leave.

## Overview [#overview]

| | |
| --- | --- |
| Resource | `esx_textui` |
| Side | Client only |
| Dependencies | `es_extended` (loads `@es_extended/imports.lua`) |
| Config | None |
| Required | Yes if any script calls `ESX.TextUI`; es_extended errors when it is missing |

Only one TextUI is visible at a time. Showing a new one replaces the current
one.

## Functions [#functions]

### ESX.TextUI [#esxtextui]

```lua
ESX.TextUI(message, type)
```

| Name | Type | Description |
| --- | --- | --- |
| `message` | `string` | Text to show. Default `"ESX-TextUI"`. Supports color codes, HTML is escaped. |
| `type` | `string?` | `"success"`, `"error"` or `"info"`. Non-string values become `"info"`. |

### ESX.HideUI [#esxhideui]

Hides the current TextUI. Does nothing when none is shown.

```lua
ESX.HideUI()
```

<Callout type="warn">
`ESX.HideUI` hides whatever TextUI is visible, including one opened by another
resource. Only hide the prompt when your own script showed it.
</Callout>

### Example: interaction point [#example-interaction-point]

```lua title="client/main.lua"
local shopCoords = vector3(25.7, -1347.3, 29.49)
local isShowing = false

CreateThread(function()
    while true do
        local sleep = 500
        local distance = #(GetEntityCoords(PlayerPedId()) - shopCoords)

        if distance < 2.0 then
            sleep = 0
            if not isShowing then
                ESX.TextUI("Press ~g~[E]~s~ to open the shop", "info")
                isShowing = true
            end

            if IsControlJustReleased(0, 38) then -- 38 = E
                TriggerEvent("my_shop:open")
            end
        elseif isShowing then
            ESX.HideUI()
            isShowing = false
        end

        Wait(sleep)
    end
end)
```

For many points, use the point helpers from
[esx_lib](/docs/core/esx_lib) instead of a distance loop.

## Exports [#exports]

| Export | Signature |
| --- | --- |
| `TextUI` | `exports["esx_textui"]:TextUI(message, type)` |
| `HideUI` | `exports["esx_textui"]:HideUI()` |

## Events [#events]

| Event | Side | Arguments |
| --- | --- | --- |
| `ESX:TextUI` | Client (net) | `message, type` |
| `ESX:HideUI` | Client (net) | none |

Both are registered with `ESX.SecureNetEvent`, so they are meant to be
triggered from the server:

```lua title="server/main.lua"
TriggerClientEvent("ESX:TextUI", playerId, "You are in a ~r~restricted~s~ zone", "error")
TriggerClientEvent("ESX:HideUI", playerId)
```

## Color codes [#color-codes]

`~r~` red, `~b~` blue, `~g~` green, `~y~` yellow, `~p~` purple, `~c~` grey,
`~m~` dark grey, `~u~` black, `~o~` orange. Close a color with `~s~`.

## Debug commands [#debug-commands]

With `Config.EnableDebug = true` in es_extended, the commands
`/textui:error`, `/textui:success`, `/textui:info` and `/textui:hide` are
registered for testing.

## Common issues [#common-issues]

- **Prompt flickers.** You call `ESX.TextUI` every frame. Use a flag such as
  `isShowing` and only call it on state changes.
- **Prompt never disappears.** The script that showed it was restarted or never
  reached the `ESX.HideUI` branch. Hide it in an `onResourceStop` handler.
- **Nothing appears with type `"warning"`.** esx_textui has no warning style.
  The NUI script fails on unknown types; use `"error"` instead.

## Related [#related]

- [Core resources overview](/docs/core)
- [Client functions](/docs/es_extended/client/functions)
- [esx_notify](/docs/core/esx_notify)
- [Point helper](/docs/es_extended/client/imports/point)
