Standard dialog
import { html, atom, renderApp } from 'mates';
import { Button, Dialog, Text } from 'mates-ui';
const App = () => {
const open = atom(false);
return () => html`
<x-row gap="var(--md-space-3)">
${Button("Open dialog", { variant: "outlined", on: { click: () => open.set(true) } })}
</x-row>
${Dialog({
openAtom: open,
title: "Edit profile",
body: html`
${Text("Update your display name and bio.", { type: "body-md", color: "muted" })}
`,
actions: [
Button("Cancel", { variant: "ghost", on: { click: () => open.set(false) } }),
Button("Save", { variant: "filled", on: { click: () => open.set(false) } }),
],
onClose: () => open.set(false),
})}
`;
};
renderApp(App, document.getElementById('app'));
With close button
import { html, atom, renderApp } from 'mates';
import { Button, Dialog, Text } from 'mates-ui';
const App = () => {
const open = atom(false);
return () => html`
<x-row gap="var(--md-space-3)">
${Button("Open dialog", { variant: "outlined", on: { click: () => open.set(true) } })}
</x-row>
${Dialog({
openAtom: open,
title: "Notification settings",
closeButton: true,
body: html`
${Text("Choose which notifications you want to receive.", { type: "body-md", color: "muted" })}
`,
actions: [
Button("Save preferences", { variant: "filled", on: { click: () => open.set(false) } }),
],
onClose: () => open.set(false),
})}
`;
};
renderApp(App, document.getElementById('app'));
Alert variant — with icon
import { html, atom, renderApp } from 'mates';
import { Button, Dialog, Text } from 'mates-ui';
import { WarningIcon } from 'mates-icons';
const App = () => {
const open = atom(false);
return () => html`
<x-row gap="var(--md-space-3)">
${Button("Warning alert", { variant: "outlined", on: { click: () => open.set(true) } })}
</x-row>
${Dialog({
openAtom: open,
variant: "alert",
title: "Unsaved changes",
icon: WarningIcon({ color: "var(--md-color-warning)" }),
body: html`
${Text("You have unsaved changes. Leaving this page will discard them.", { type: "body-md", color: "muted" })}
`,
actions: [
Button("Keep editing", { variant: "ghost", on: { click: () => open.set(false) } }),
Button("Discard", { variant: "danger", on: { click: () => open.set(false) } }),
],
onClose: () => open.set(false),
})}
`;
};
renderApp(App, document.getElementById('app'));
Header and footer dividers
import { html, atom, renderApp } from 'mates';
import { Button, Dialog, Text } from 'mates-ui';
const App = () => {
const open = atom(false);
return () => html`
<x-row gap="var(--md-space-3)">
${Button("Open dialog", { variant: "outlined", on: { click: () => open.set(true) } })}
</x-row>
${Dialog({
openAtom: open,
title: "Terms of service",
headerDivider: true,
footerDivider: true,
body: html`
<x-col gap="var(--md-space-3)">
${Text("Section 1 — Acceptance of terms", { type: "label-lg" })}
${Text("By accessing or using our service, you agree to be bound by these terms.", { type: "body-md", color: "muted" })}
${Text("Section 2 — Use of service", { type: "label-lg" })}
${Text("You may use our service only for lawful purposes.", { type: "body-md", color: "muted" })}
</x-col>
`,
actions: [
Button("Decline", { variant: "ghost", on: { click: () => open.set(false) } }),
Button("Accept", { variant: "filled", on: { click: () => open.set(false) } }),
],
onClose: () => open.set(false),
})}
`;
};
renderApp(App, document.getElementById('app'));
Scrollable body
import { html, atom, renderApp } from 'mates';
import { Button, Dialog, Text } from 'mates-ui';
const NOTES = [
"New virtualised table with 100k row support.",
"VerticalSegments component for resizable pane layouts.",
"disappear directive — removes elements after a delay.",
"changeFlagAtom — forces re-renders on demand.",
"Button default height reduced to 36 px.",
"Secondary button variant removed.",
"Pill tabs background moved to each tab item.",
];
const App = () => {
const open = atom(false);
return () => html`
<x-row gap="var(--md-space-3)">
${Button("Open dialog", { variant: "outlined", on: { click: () => open.set(true) } })}
</x-row>
${Dialog({
openAtom: open,
title: "Release notes — v4.2.0",
closeButton: true,
headerDivider: true,
footerDivider: true,
maxHeight: "min(70vh, 32rem)",
body: html`
<x-col gap="var(--md-space-3)">
${NOTES.map(note => Text(note, { type: "body-md", color: "muted" }))}
</x-col>
`,
actions: [
Button("Close", { variant: "filled", on: { click: () => open.set(false) } }),
],
onClose: () => open.set(false),
})}
Disabled scrim dismiss
import { html, atom, renderApp } from 'mates';
import { Button, Dialog, Text } from 'mates-ui';
import { InfoIcon } from 'mates-icons';
const App = () => {
const open = atom(false);
return () => html`
<x-row gap="var(--md-space-3)">
${Button("Open dialog", { variant: "outlined", on: { click: () => open.set(true) } })}
</x-row>
${Dialog({
openAtom: open,
title: "Required action",
icon: InfoIcon(),
scrimDismiss: false,
closeButton: false,
body: html`
${Text("You must complete this action before continuing. Clicking outside will not close this dialog.", { type: "body-md", color: "muted" })}
`,
actions: [
Button("Acknowledge", { variant: "filled", on: { click: () => open.set(false) } }),
],
onClose: () => open.set(false),
})}
`;
};
renderApp(App, document.getElementById('app'));
Custom width
import { html, atom, renderApp } from 'mates';
import { Button, Dialog, Text } from 'mates-ui';
const App = () => {
const open = atom(false);
return () => html`
<x-row gap="var(--md-space-3)">
${Button("Open wide dialog", { variant: "outlined", on: { click: () => open.set(true) } })}
</x-row>
${Dialog({
openAtom: open,
title: "Import data",
width: "40rem",
closeButton: true,
headerDivider: true,
footerDivider: true,
body: html`
<x-col gap="var(--md-space-3)">
${Text("Paste your CSV data below or drag and drop a file.", { type: "body-md", color: "muted" })}
<textarea rows="6" placeholder="id,name,email"
style="width:100%;box-sizing:border-box;padding:var(--md-space-3);border:1px solid var(--md-color-border);border-radius:var(--md-radius-sm);resize:vertical;background:var(--md-color-surface);color:var(--md-color-text);">
</textarea>
</x-col>
`,
actions: [
Button("Cancel", { variant: "ghost", on: { click: () => open.set(false) } }),
Button("Import", { variant: "filled", on: { click: () => open.set(false) } }),
],
onClose: () => open.set(false),
})}
`;
};
renderApp(App, document.getElementById('app'));
Fullscreen variant
import { html, atom, renderApp } from 'mates';
import { Button, Dialog } from 'mates-ui';
const App = () => {
const open = atom(false);
return () => html`
<x-row gap="var(--md-space-3)">
${Button("Open fullscreen", { variant: "outlined", on: { click: () => open.set(true) } })}
</x-row>
${Dialog({
openAtom: open,
variant: "fullscreen",
title: "Compose message",
fullscreenLeading: Button("Cancel", { variant: "ghost", size: "sm", on: { click: () => open.set(false) } }),
fullscreenTrailing: Button("Send", { variant: "filled", size: "sm", on: { click: () => open.set(false) } }),
body: html`
<textarea placeholder="Write your message…"
style="flex:1;width:100%;box-sizing:border-box;padding:var(--md-space-4);border:1px solid var(--md-color-border);border-radius:var(--md-radius-sm);resize:none;min-height:12rem;background:var(--md-color-surface);color:var(--md-color-text);">
</textarea>
`,
onClose: () => open.set(false),
})}
`;
};
renderApp(App, document.getElementById('app'));
Alert, Confirm & Prompt — browser-native replacements
import { html, atom, nothing, renderApp } from 'mates';
import { Alert, Button, Confirm, Prompt, Text } from 'mates-ui';
const App = () => {
const alertResult = atom('');
const confirmResult = atom('');
const promptResult = atom('');
return () => html`
<x-col gap="var(--md-space-5)">
<x-col gap="var(--md-space-2)">
${Text("Alert", { type: "label-md" })}
<x-row gap="var(--md-space-3)">
${Button("Show alert", { variant: "outlined", on: { click: async () => {
await Alert("Your changes have been saved.", { type: "success", okLabel: "Got it" });
alertResult.set("dismissed");
}}})}
${alertResult() ? Text("→ " + alertResult(), { type: "body-sm", color: "muted" }) : nothing}
</x-row>
</x-col>
<x-col gap="var(--md-space-2)">
${Text("Confirm", { type: "label-md" })}
<x-row gap="var(--md-space-3)">
${Button("Delete item", { variant: "danger", on: { click: async () => {
const ok = await Confirm("Delete this item?", { title: "Confirm delete", type: "danger", dangerMessage: "This cannot be undone." });
confirmResult.set(ok ? "confirmed ✔" : "cancelled ✖");
}}})}
${confirmResult() ? Text("→ " + confirmResult(), { type: "body-sm", color: "muted" }) : nothing}
</x-row>
</x-col>
<x-col gap="var(--md-space-2)">
${Text("Prompt", { type: "label-md" })}
<x-row gap="var(--md-space-3)">
${Button("Rename file", { variant: "outlined", on: { click: async () => {
const name = await Prompt("Enter a new file name:", { title: "Rename", placeholder: "my-file.ts", defaultValue: "untitled.ts", okLabel: "Rename" });
promptResult.set(name !== null ? '"' + name + '"' : "cancelled");
ConfirmDialog — basic
import { html, atom, nothing, renderApp } from 'mates';
import { Button, ConfirmDialog, Text } from 'mates-ui';
const App = () => {
const open = atom(false);
const result = atom('');
return () => html`
<x-col gap="var(--md-space-4)">
<x-row gap="var(--md-space-3)">
${Button("Publish post", { variant: "outlined", on: { click: () => open.set(true) } })}
${result() ? Text("→ " + result(), { type: "body-sm", color: "muted" }) : nothing}
</x-row>
${ConfirmDialog({
openAtom: open,
title: "Publish post?",
message: "This will make your post visible to all users.",
confirmLabel: "Publish",
onConfirm: () => result.set("Published!"),
onCancel: () => result.set("Cancelled"),
})}
</x-col>
`;
};
renderApp(App, document.getElementById('app'));
ConfirmDialog — destructive action
import { html, atom, nothing, renderApp } from 'mates';
import { Button, ConfirmDialog, Text } from 'mates-ui';
import { DeleteForeverIcon } from 'mates-icons';
const App = () => {
const open = atom(false);
const result = atom('');
return () => html`
<x-col gap="var(--md-space-4)">
<x-row gap="var(--md-space-3)">
${Button("Delete account", { variant: "danger", icon: DeleteForeverIcon(), on: { click: () => open.set(true) } })}
${result() ? Text("→ " + result(), { type: "body-sm", color: "muted" }) : nothing}
</x-row>
${ConfirmDialog({
openAtom: open,
title: "Delete account?",
message: "This will permanently delete your account. This action cannot be undone.",
confirmLabel: "Delete account",
cancelLabel: "Keep account",
danger: true,
onConfirm: () => result.set("Account deleted"),
onCancel: () => result.set("Kept account"),
})}
</x-col>
`;
};
renderApp(App, document.getElementById('app'));
ConfirmDialog — custom labels
import { html, atom, renderApp } from 'mates';
import { Button, ConfirmDialog } from 'mates-ui';
const App = () => {
const open = atom(false);
return () => html`
<x-row gap="var(--md-space-3)">
${Button("Leave page?", { variant: "outlined", on: { click: () => open.set(true) } })}
</x-row>
${ConfirmDialog({
openAtom: open,
title: "Leave without saving?",
message: "You have unsaved changes. If you leave now your changes will be lost.",
confirmLabel: "Leave",
cancelLabel: "Stay",
onConfirm: () => open.set(false),
onCancel: () => open.set(false),
})}
`;
};
renderApp(App, document.getElementById('app'));