Show a modal¶
A modal panel blocks input to everything below it. Use this pattern for confirmation dialogs, settings windows, and any flow that requires the player to complete or dismiss the interaction before returning to the underlying screen.
This page assumes you understand the panel system at a conceptual level. For the model, refer to Panels and modals.
To show a modal¶
- Define the panel.
Use
BeginPanel(id, rect, config)with aPanelConfigthat hasHidden = true(the panel starts hidden) and aBackdropColor(Tick UI dims the rest of the screen before drawing the body). The panel blocks input only when you callShowModalon it, as shown in step 3. - Render the dialog body.
Centre a sized rect with
ui.Auto().Center(width, height), draw a panel, and add the buttons. The body needs noui.Fillfor the dim background, becauseBackdropColorprovides it. The body needs noui.ConsumeInput(), becauseShowModalin the next step blocks input underneath. - Trigger the modal from outside the body.
ui.ShowModal("confirm_quit")makes the panel visible and sets itsBlocksInputflag.ui.ShowPanel(id)does the same visibility flip without the input block.ui.HidePanel(id)hides it again. Call these from your application logic, not from inside the panel body.
The full pattern, end to end¶
if (ui.BeginPanel("confirm_quit", screenRect, new PanelConfig
{
Hidden = true,
BackdropColor = new Color(0, 0, 0, 0.5f),
}))
{
using (ui.Auto().Center(360, 160))
{
ui.FillRounded(panelColor, 8);
ui.Text("Quit without saving?", "roboto_mono", 18, Color.white,
TextAlign.MiddleCenter);
using (ui.Auto().Bottom(40).PadHorizontal(20))
using (ui.PushSplitHorizontal(2, 8))
{
using (ui.Auto())
{
ui.FillRounded(buttonColor, 5);
ui.Text("Cancel", "roboto_mono", 14, Color.white,
TextAlign.MiddleCenter);
if (ui.Button("cancel"))
ui.HidePanel("confirm_quit");
}
ui.Next();
using (ui.Auto())
{
ui.FillRounded(dangerColor, 5);
ui.Text("Quit", "roboto_mono", 14, Color.white,
TextAlign.MiddleCenter);
if (ui.Button("quit"))
Application.Quit();
}
}
}
ui.EndPanel();
}
First-frame initialisation¶
To seed state when the modal opens (focus a textbox, reset a
selection, run an entry animation), check IsPanelFirstShown
inside the body:
IsPanelFirstShown returns true for the frame the panel was
not used last frame. That covers the first appearance and any
re-show after a hide. For the visibility state machine, refer to
Panels and modals.
Animate the modal¶
Pair the modal with a PushAnimate scope to fade or scale the
dialog body in. The Hiding visibility state gives the body one
final frame before the panel transitions to Hidden, rather than
being cut off the instant it is hidden.
For the procedure, refer to Add an animation. For the visibility state machine, refer to Panels and modals.
Pitfalls¶
Calling ShowModal inside the BeginPanel block.
: Legal but confusing. Keep state changes outside the body.
The modal does not block input.
: You called ShowPanel(id) instead of ShowModal(id).
ShowPanel makes the panel visible. ShowModal makes it
visible and sets BlocksInput, so the priority walk in
BeginFrame prefers it over anything underneath.
There's no dim background.
: The PanelConfig is missing BackdropColor. Set it to a
translucent colour (e.g. new Color(0, 0, 0, 0.5f)). The
backdrop draws automatically before the panel body runs.
The dialog never appears.
: ShowModal is being called every frame and immediately
cancelled by HidePanel. Audit the call sites. A single
ShowModal outside a loop is correct.
Additional resources¶
- Panels and modals: the full panel concept, including popups and the input-priority order.
- Input and focus: why
Modalblocks lower panels. - Add an animation: pairing show and hide with animations.