OverflowOverflow
UI Library

Input

A form dialog with validation. Blocking: it returns the player's answers, so call it from a thread.

A form titled "Register vehicle" with text, select, slider, number, checkbox and colour fields

input

Two calling shapes are accepted. Use whichever reads better:

-- single table
local values = exports.of_ui:input({ title = ..., options = { ... } })

-- heading, rows, options
local values = exports.of_ui:input('Register vehicle', { ... }, { allowCancel = true })
FieldTypeDescription
titlestringDialog heading.
optionstable[]The rows. A bare string becomes a text input with that label.
sizestring?xs, sm, md, lg, xl.
allowCancelboolean?false removes every way out: no cancel button, no ESC. Cancellable by default. cancel is accepted as an alias.

Returns two values:

local values, byId = exports.of_ui:input(...)
  • values: a positional array, one entry per row, in the order you declared them. nil when the player cancelled.
  • byId: a table keyed by the id of each row that declared one. nil when no row did.
CreateThread(function()
    local values, byId = exports.of_ui:input('Register vehicle', {
        { type = 'input',  label = 'Plate', icon = 'car', required = true, maxLength = 8, id = 'plate' },
        { type = 'select', label = 'Class', required = true, options = {
            { value = 'compact', label = 'Compact' },
            { value = 'sport',   label = 'Sport', default = true },
        } },
        { type = 'checkbox', label = 'Insured', checked = true },
    }, { allowCancel = true })

    if not values then return end -- cancelled

    print(values[1], values[2], values[3])
    print(byId.plate)             -- same as values[1]
end)

Prefer id over positions once a dialog has more than a handful of rows. Positional indexes shift the moment someone inserts a row; ids do not. Display rows count as positions too: a callout in the middle of your form occupies an index and returns nil there.

closeInput

exports.of_ui:closeInput()

Closes the open dialog from code. The waiting input call returns nil.

Field types

Every row needs a type. Rows without one default to input.

TypeReturnsNotes
inputstringSingle-line text. password = true masks it.
textareastringMulti-line. autosize = true grows with the content.
numbernumberStepper. Honours min, max, step.
slidernumberDrag between min and max.
checkboxbooleanInitial state from checked.
selectstringOne value from options.
multi-selectstring[]Several values. maxSelectedValues caps how many.
datenumberTimestamp, or a formatted string with returnString = true.
date-rangenumber[]Two timestamps.
timestringformat = '12' or '24'.
colorstringHex colour.

Common fields

FieldTypeDescription
labelstringField label. Required on editable fields.
descriptionstring?Muted line under the label.
placeholderstring?Shown while empty.
iconstring?Icon before the label.
iconColorstring?Hex colour for the icon.
defaultany?Initial value.
requiredboolean?Blocks confirm while empty.
disabledboolean?Shown but not editable. Text fields stay selectable, so the player can still copy the value.
idstring?of_ui: key for this row in the second return value.
hintstring?of_ui: help text behind a ? next to the label.
copyboolean?of_ui: adds a copy button that puts the value on the clipboard.

Validation

FieldTypeApplies to
min / maxnumber?number, slider
stepnumber?number, slider
minLength / maxLengthnumber?input, textarea
patternstring?of_ui: regex the value must match.
patternErrorstring?of_ui: message shown when pattern fails.
{ type = 'input', label = 'Phone', icon = 'phone', required = true,
  pattern = '^\\d{3}-\\d{4}$', patternError = 'Format: 555-0123',
  placeholder = '555-0123', hint = 'Your in-city number, without the area code.' }

Errors appear once a field has been left, and clear as soon as they are fixed. Confirm stays blocked until every rule passes.

Selects

options is a list of { value, label?, default? }. label falls back to value.

FieldTypeDescription
searchableboolean?Adds a filter box. Worth it past ~10 options.
clearableboolean?Lets the player unset the choice.
maxSelectedValuesnumber?multi-select only.

Display rows

Rows that show content instead of asking for it: callouts, images, markdown, progress bars, stat grids and more. They validate as nothing and return nil at their position.

A dialog mixing warning, info, error, success and custom-accent callouts with a text field

exports.of_ui:input('Sell property', {
    { type = 'callout', variant = 'warning', label = 'This action is permanent',
      description = 'Once sold, the property cannot be recovered.' },
    { type = 'input', label = 'Buyer', icon = 'user', required = true },
})

A dialog with a section title, framed image and rendered markdown above a signature field

exports.of_ui:input('Property deed', {
    { type = 'title', label = 'The property', icon = 'house',
      description = 'Review the listing before signing.' },
    { type = 'image', src = 'https://example.com/house.png',
      footer = 'Vinewood Hills, 3 bedrooms.' },
    { type = 'markdown', content = '## Terms\nYou agree to pay **$4,500/week** in taxes.' },
    { type = 'input', label = 'Signature', icon = 'pen', required = true },
})

The full list of display rows (and every field each one takes) is on Rows. The same rows work in the drawer.

Notes

  • One dialog at a time. A second input while one is open returns nil instead of queuing.
  • Enter confirms, unless focus is in a textarea or on a button.
  • allowCancel = false really does trap the player. Only use it when your script is guaranteed to close the dialog itself.

On this page