MATES / Examples

Counter

Reactive atom — tap the buttons to update.

import { html, atom, renderApp, x } from "mates";
import { Button, Text, Statistic } from "mates-ui";

const Counter = () => {
const count = atom(0);
const trend = () => (count() > 0 ? "up" : count() < 0 ? "down" : undefined);

return () => html`
<div>
<div class="section-head">
${Text("Counter", { type: "headline-md" })}
${Text("Reactive atom — tap the buttons to update.", { type: "body-sm", color: "muted" })}
</div>
<div class="counter-display">
${Statistic(count(), {
title: "Current value",
trend: trend(),
trendValue: count() !== 0 ? (count() > 0 ? "+" + count() : String(count())) : undefined,
valueStyle: { fontSize: "4rem", fontVariantNumeric: "tabular-nums" },
})}
</div>
<div class="counter-btns">
${Button("−", {
variant: "outlined",
onClick: () => count.set((n) => n - 1),
})}
${Button("Reset", {
variant: "ghost",
onClick: () => count.set(0),
})}
${Button("+", {
variant: "filled",
onClick: () => count.set((n) => n + 1),
})}
</div>
</div>
/* App-specific layout — mates-design tokens are in index.html <link> */

html, body { height: 100%; margin: 0; }
body {
background: var(--md-color-background);
color: var(--md-color-text);
font-family: var(--md-font-family);
}
#app { display: flex; flex-direction: column; min-height: 100vh; }

/* Nav */
.app-header {
display: flex;
align-items: center;
padding: 0 8px 0 4px;
background: var(--md-color-surface);
gap: 4px;
}
.app-header-tabs { flex: 1; overflow-x: auto; min-width: 0; }
.app-header-tabs .md-tabs { border-bottom: none; }
.app-nav-spacer { flex: 1; }

/* Route content */
.route-content { flex: 1; padding: 28px 20px; max-width: 620px; margin: 0 auto; width: 100%; box-sizing: border-box; }

/* Section header */
.section-head { margin-bottom: 20px; }

/* Counter */
.counter-display { text-align: center; padding: 2rem 0 1.5rem; }
.counter-btns { display: flex; gap: 12px; justify-content: center; margin-top: 1.5rem; }

/* Todo */
.todo-input-row { display: flex; gap: 10px; margin-bottom: 1.5rem; align-items: flex-end; }
.todo-input-row > :first-child { flex: 1; }
.todo-list { display: flex; flex-direction: column; gap: 8px; }
Console
0 logs
No output yet — run your code to see logs here.