Start typing to search packages!
modalkit
By @biotoxin495
Roblox
Mirrored from WallyModalKit — Runtime-generated modal prompts for Roblox
ModalKit, a lightweight, standalone utility for displaying confirmations, alerts, and custom action prompts in Roblox.
ModalKit builds its interface at runtime, so it does not require a prebuilt GUI hierarchy, framework, or third-party runtime dependency. One action-based prompt system powers confirmations, alerts, destructive warnings, multi-choice dialogs, loading states, and custom modal content.
Quick example
ModalKit creates a manager and opens a prompt through a small client-side API.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ModalKit = require(ReplicatedStorage.ModalKit)
local prompts = ModalKit.new()
local confirmed, result = prompts:ConfirmAsync({
Title = "Delete item?",
Message = "This action cannot be undone.",
ConfirmText = "Delete",
Destructive = true,
})
if confirmed then
print("Delete the item")
else
print("Cancelled or dismissed:", result.Reason)
end
🚀 Features
Runtime-generated UI
ModalKit creates its own ScreenGui and prompt hierarchy with Instance.new. No prebuilt GUI structure is required.
Action-based prompts
Use Confirm and Alert for common cases, or Open for arbitrary actions with custom IDs, styles, callbacks, and result flags.
Flexible prompt lifecycle
Every prompt returns a handle with Await, Update, Respond, Close, and Destroy methods, plus completion and action signals.
Queueing and overlap policies
Prompts can be queued, replace the active prompt, or be rejected while another prompt is open. Policies can be selected globally or per prompt.
Input and dismissal support
Buttons use Activated, covering mouse, touch, and gamepad input. Enter activates the default action, while Escape, gamepad B, the close button, and the backdrop can dismiss a prompt when enabled.
Themes and custom content
Use global or per-prompt theme overrides, built-in action styles, custom named styles, and runtime-generated content builders with cleanup support.
Fully typed, no dependencies
The module uses strict Luau and has no external runtime dependencies or framework requirements.
📖 Basic usage
Place the ModalKit ModuleScript somewhere accessible to client scripts, such as ReplicatedStorage. ModalKit must be required and used from a LocalScript or another client ModuleScript.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ModalKit = require(ReplicatedStorage.ModalKit)
local prompts = ModalKit.new()
Example: confirmation prompt
Confirm creates a standard cancel/confirm dialog and returns a PromptHandle.
local handle = prompts:Confirm({
Title = "Leave the match?",
Message = "Your current progress will be lost.",
ConfirmText = "Leave",
CancelText = "Stay",
Destructive = true,
})
handle.Completed:Connect(function(result)
if result.Confirmed then
print("Player confirmed")
else
print("Prompt ended:", result.Reason)
end
end)
Example: alert prompt
Alert creates a single-action prompt.
prompts:Alert({
Title = "Inventory full",
Message = "Remove an item before collecting another one.",
ButtonText = "Got it",
ButtonStyle = "Primary",
})
Example: arbitrary actions
Use Open when the prompt needs more than a simple confirmation.
local handle = prompts:Open({
Title = "Unsaved changes",
Message = "Choose what should happen before leaving.",
Actions = {
{
Id = "cancel",
Text = "Stay here",
Style = "Secondary",
IsCancel = true,
},
{
Id = "discard",
Text = "Discard",
Style = "Danger",
},
{
Id = "save",
Text = "Save and leave",
Style = "Primary",
IsDefault = true,
},
},
})
local result = handle:Await()
print(result.Action, result.Reason)
⚙️ API
ModalKit.new(config?)
Creates a prompt manager. The manager must be created from a client script.
local prompts = ModalKit.new({
Parent = playerGui,
ScreenGuiName = "GameModals",
ResetOnSpawn = false,
DefaultPolicy = "Queue",
Theme = {
DialogMaxWidth = 620,
},
})
| Option | Type | Default | Description |
|---|---|---|---|
Parent | Instance? | LocalPlayer.PlayerGui | Parent used for the generated ScreenGui. If a ScreenGui is supplied, its parent is used. |
ScreenGuiName | string? | "ModalKit" | Name of the generated ScreenGui. |
ResetOnSpawn | boolean? | false | Whether the generated ScreenGui resets when the player respawns. |
DefaultPolicy | "Queue" | "Replace" | "Reject" | "Queue" | Behavior when another prompt is already active. |
Theme | table? | Default theme | Global theme overrides. |
ModalKit creates the ScreenGui lazily when the first prompt opens. It owns and destroys that GUI when the manager is destroyed. A caller-provided ScreenGui is left intact.
prompts:Confirm(options?)
Creates a two-action confirmation prompt and returns a PromptHandle.
| Option | Type | Default | Description |
|---|---|---|---|
ConfirmText | string? | "Confirm" | Confirm button text. |
CancelText | string? | "Cancel" | Cancel button text. |
ConfirmActionId | string? | "confirm" | Result ID for the confirm action. |
CancelActionId | string? | "cancel" | Result ID for the cancel action. |
ConfirmStyle | string? | "Primary" | Confirm button style. |
CancelStyle | string? | "Secondary" | Cancel button style. |
Destructive | boolean? | false | Uses the Danger style when no explicit confirm style is supplied. |
OnConfirm | function? | — | Callback for the explicit confirm action. |
OnCancel | function? | — | Callback for the explicit cancel action. |
OnCancel is called only when the cancel action itself is activated. Other dismissal paths produce separate result reasons.
prompts:ConfirmAsync(options?)
Yields until a confirmation finishes and returns (confirmed, result).
local confirmed, result = prompts:ConfirmAsync({
Title = "Reset settings?",
Message = "Your local preferences will return to their defaults.",
ConfirmText = "Reset",
Destructive = true,
})
prompts:Alert(options?)
Creates a single-action prompt and returns a PromptHandle.
| Option | Type | Default | Description |
|---|---|---|---|
ActionId | string? | "ok" | Result ID for the alert action. |
ButtonText | string? | "Okay" | Visible button text. |
ButtonStyle | string? | "Primary" | Button style. |
prompts:Open(options)
Creates a generic action prompt. If no actions are supplied, ModalKit creates a single Okay action.
prompts:CloseAll(reason?)
Completes every queued and active prompt with the supplied reason, or "Programmatic" when no reason is supplied. The manager remains usable afterward.
prompts:Destroy()
Closes remaining prompts with reason "Destroyed", disconnects UI events, destroys manager signals, and removes the generated ScreenGui.
ModalKit.GetDefaultTheme()
Returns a fresh copy of ModalKit's default theme. Pass the copy to ModalKit.new or modify it before using it as a theme override.
local theme = ModalKit.GetDefaultTheme()
theme.DialogMaxWidth = 640
local prompts = ModalKit.new({
Theme = theme,
})
Prompt handles
All prompt creation methods return a handle representing that request.
| Method | Description |
|---|---|
handle:Await() | Yields until the prompt finishes and returns its result. |
handle:Update(patch) | Updates queued or active prompt data. |
handle:Respond(actionId) | Programmatically activates an action on the active prompt. |
handle:Close(reason?) | Dismisses an active or queued prompt. The default reason is "Programmatic". |
handle:Destroy() | Closes an unfinished prompt with "Destroyed" and destroys its signals. |
handle:GetState() | Returns "Queued", "Opening", "Open", "Closing", or "Closed". |
handle:GetResult() | Returns the completed PromptResult, if available. |
handle:IsOpen() | Returns whether the prompt is active. |
handle:IsFinished() | Returns whether the prompt has completed. |
handle.ActionTriggered:Connect(function(actionId, activeHandle)
print("Action:", actionId)
end)
handle.Completed:Connect(function(result)
print("Closed because:", result.Reason)
end)
Complete options reference
These options are accepted by Open and can also be used with the helper methods where applicable.
Prompt options
| Option | Type | Description |
|---|---|---|
Title | string? | Header text. |
Message | string? | Main wrapped message. |
Icon | string? | Optional image asset URI. |
Actions | {Action}? | Actions for a generic prompt. |
ActionLayout | "Auto" | "Horizontal" | "Vertical" | Button layout. Auto selects a layout based on the action set. |
Policy | "Queue" | "Replace" | "Reject" | Per-prompt overlap policy. |
Dismiss | boolean | table | Enables or configures non-action dismissal. |
Animate | boolean? | Set to false to disable transitions. |
AnimationDuration | number? | Overrides the transition duration. |
Loading | boolean? | Prevents action activation while true. |
Content | function? | Builds custom body content. |
Theme | table? | Per-prompt theme overrides. |
OnOpen | function? | Called after the prompt becomes active. |
OnAction | function? | Called as (actionId, handle). |
OnClose | function? | Called as (result, handle). |
Action fields
{
Id = "save",
Text = "Save and leave",
Style = "Primary",
IsDefault = true,
IsConfirm = true,
AutoClose = true,
}
| Field | Type | Default | Description |
|---|---|---|---|
Id | string? | Action index | Unique action/result identifier. |
Text | string? | Id | Visible button text. |
Style | string? | "Secondary" | Theme style name. |
IsDefault | boolean? | Automatic | Default keyboard/gamepad action. |
IsConfirm | boolean? | false | Marks its result as confirmed. |
IsCancel | boolean? | false | Marks its result as cancelled. |
Disabled | boolean? | false | Disables interaction with the action. |
AutoClose | boolean? | true | Set to false to keep the prompt open after activation. |
Callback | function? | — | Called as Callback(handle, action) after activation. |
Action IDs must be unique within a prompt. If no enabled action is explicitly the default, ModalKit selects the last enabled action.
Behavior
Dismissal
All standard dismissal methods are enabled by default.
Dismiss = {
CloseButton = true,
Backdrop = true,
Escape = true,
GamepadBack = true,
}
Disable every non-action dismissal path with Dismiss = false, or configure the paths individually. Each path produces a distinct Reason.
Prompt overlap policies
When a prompt opens while another is active, Policy determines what happens:
"Queue"stores the prompt and opens it after earlier prompts finish. This is the default."Replace"closes the current prompt with reason"Replaced"and places the new prompt at the front of the queue."Reject"completes the new handle with reason"Rejected"without displaying it.
Loading and runtime updates
Set an action's AutoClose to false to keep the prompt open while work continues. Use Update to change the message, loading state, actions, content, or theme.
local prompt = prompts:Open({
Title = "Publish build?",
Message = "The build will become visible to players.",
Actions = {
{
Id = "publish",
Text = "Publish",
Style = "Primary",
IsDefault = true,
AutoClose = false,
},
},
})
prompt.ActionTriggered:Connect(function(actionId)
if actionId == "publish" then
prompt:Update({
Message = "Publishing…",
Loading = true,
})
end
end)
While a prompt is loading, action responses are ignored.
Lifecycle callbacks and manager signals
OnOpen, OnAction, and OnClose callbacks can be supplied in prompt options. They are protected and run asynchronously so callback errors do not interrupt ModalKit's cleanup.
prompts:Open({
Title = "Example",
OnOpen = function(handle)
print("Opened", handle.Id)
end,
OnAction = function(actionId, handle)
print("Action", actionId, "on", handle.Id)
end,
OnClose = function(result, handle)
print("Closed", handle.Id, result.Reason)
end,
})
A manager also exposes lifecycle signals for every prompt it owns:
prompts.PromptOpened:Connect(function(handle)
print("Opened", handle.Id)
end)
prompts.ActionTriggered:Connect(function(handle, actionId)
print("Action", actionId, "on prompt", handle.Id)
end)
prompts.PromptClosed:Connect(function(handle, result)
print("Closed", handle.Id, result.Reason)
end)
Custom content
Use Content to insert arbitrary runtime-generated UI into the body of a prompt.
prompts:Confirm({
Title = "Purchase item?",
Message = "Review the purchase before continuing.",
Content = function(container, handle)
local summary = Instance.new("TextLabel")
summary.BackgroundTransparency = 1
summary.AutomaticSize = Enum.AutomaticSize.Y
summary.Size = UDim2.new(1, 0, 0, 0)
summary.Text = "Crystal Sword — 500 coins"
summary.TextWrapped = true
summary.Parent = container
return function()
-- Disconnect custom events or release other resources here.
end
end,
})
A content builder may return a cleanup function, an unparented Instance for ModalKit to parent, or nothing when it handles parenting itself. Updating Content rebuilds the section and runs the previous cleanup path first.
Themes
Get a fresh copy of the default theme or provide only the properties to override.
local prompts = ModalKit.new({
Theme = {
DialogColor = Color3.fromRGB(246, 247, 251),
TitleColor = Color3.fromRGB(25, 27, 34),
MessageColor = Color3.fromRGB(73, 77, 91),
Styles = {
Primary = {
BackgroundColor = Color3.fromRGB(120, 80, 255),
},
},
},
})
Built-in action styles are Primary, Secondary, Danger, Success, and Neutral. Additional named styles can be defined under Theme.Styles and referenced by an action's Style field.
Input behavior
- Buttons use
Activated, covering mouse, touch, and gamepad activation. - Enter and keypad Enter trigger the default action.
- Keyboard activation is ignored while a
TextBoxis focused. - Escape, gamepad B, and backdrop activation dismiss the prompt when enabled.
- Gamepad selection moves to the default enabled action where applicable.
- The previously selected GUI object is restored after the modal closes when it still exists.
Prompt results
A completed prompt produces a result table:
{
Action = "confirm", -- nil when no action was selected
Reason = "Action",
Confirmed = true,
Cancelled = false,
}
Built-in reasons are Action, CloseButton, Backdrop, Escape, GamepadBack, Programmatic, Replaced, Rejected, and Destroyed. Custom strings supplied to Close or CloseAll are preserved. Confirmed and Cancelled follow the action's IsConfirm/IsCancel flags or the conventional IDs "confirm"/"cancel".
📝 Notes
- ModalKit is a client-side interface utility. A confirmation result communicates user intent, not authorization.
- Never treat a successful client confirmation as proof that a purchase, trade, deletion, currency change, reward, or administrative action is valid. Validate sensitive operations on the server.
- The package is a single root ModuleScript with internal modules beneath it:
ReplicatedStorage
└── ModalKit
├── Cleaner
├── PromptHandle
├── PromptView
├── SimpleSignal
└── Theme
- The accompanying showcase game demonstrates confirmations, alerts, multi-action prompts, custom content, queueing, replacement, loading updates, themes, scrolling, and lifecycle logging.
- Call
prompts:CloseAll()when changing scenes, andprompts:Destroy()when the owning controller or interface is torn down.
🛠️ Installation
Studio model
Import ModalKit.rbxmx into your place and put the resulting ModalKit ModuleScript somewhere accessible to the client, such as ReplicatedStorage.
Then require it from a LocalScript or another client ModuleScript:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ModalKit = require(ReplicatedStorage.ModalKit)
Creating a manager from the server will throw an error.
Rojo
Map the ModalKit source into ReplicatedStorage in your project file, then require it from client code as shown above.
License
Use the license included with your ModalKit release or repository.
made with ❤️ by biotoxin495
Package Details
Install command (Click to copy)
Version
1.0.1
License
MIT
Safe for commercial use
Automated license review — not legal advice.
