Questions and forms¶
A quick question¶
sagl.ui.messageBox resolves to the button's label, or null if the
player pressed Esc.

sagl.on("spray:offer", async ({ price }) => {
const answer = await sagl.ui.messageBox({
title: "Pay 'n' Spray",
text: `Respray your car for $${price}? It'll lose two wanted stars.`,
buttons: ["No", "Yes"],
});
sagl.emit("spray:answer", answer === "Yes");
});
A form¶
A centred document with text inputs, a checkbox and buttons; it takes the mouse and keyboard while open, and Esc closes it.
client/scripts/register.js
sagl.on("register", ({ reason }) => {
const form = sagl.ui.open(`
<rml>
<head>
<link type="text/rcss" href="/sagl/ui/theme/base.rcss"/>
<style>
body { width: 100%; height: 100%; background-color: #00000080; }
.panel { position: absolute; left: 50%; top: 45%; width: 420dp; margin-left: -210dp;
transform: translateY(-50%); }
label { display: block; color: #accbf1; margin-bottom: 4dp; }
.terms { display: flex; flex-direction: row; align-items: center; margin-bottom: 14dp; }
.terms span { margin-left: 8dp; }
input.checkbox { width: 18dp; height: 18dp; border: 2dp #accbf1; background-color: #000000a0;
tab-index: auto; nav: auto; }
input.checkbox:checked { background-color: #accbf1; }
#error { display: block; color: #ff6060; margin-bottom: 10dp; }
</style>
</head>
<body>
<div class="panel">
<h1>Sign up</h1>
<span class="subtitle" id="reason"></span>
<label>Character name</label>
<input class="text" type="text" id="name" maxlength="24"/>
<label>Age</label>
<input class="text" type="text" id="age" maxlength="2"/>
<div class="terms"><input type="checkbox" id="rules"/><span>I've read the rules</span></div>
<span id="error"></span>
<button id="cancel">Cancel</button><button class="primary" id="ok">Sign up</button>
</div>
</body>
</rml>`);
form.setText("reason", reason ?? "");
form.focus("name");
form.on("click", "cancel", () => form.close());
form.on("click", "ok", () => {
const name = form.getValue("name").trim();
const age = Number(form.getValue("age"));
if (!/^[A-Za-z]+ [A-Za-z]+$/.test(name)) return form.setText("error", "First and last name, please.");
if (!(age >= 18 && age <= 90)) return form.setText("error", "Ages are 18-90.");
if (!form.isChecked("rules")) return form.setText("error", "Read the rules first.");
sagl.emit("register", { name, age });
form.close();
});
});
index.ts (gamemode)
server.on("playerJoin", (p) => p.emit("register", { reason: "Welcome! Make your character." }));
server.channel("register").on((player, data) => {
const { name, age } = data as { name: string; age: number };
player.data.character = { name, age }; // check it again here: never trust the client
});