A complete application, rather than a demo of one property
A complete application, rather than a demo of one property.
Everything here has appeared on its own elsewhere in example/ -- reactive state, computed values, <for> over a collection of structs, conditional rendering, flexbox, grid, transitions and custom properties. This file is about how they compose into something you would actually ship.
Try it: click a service row to select it, use the filter buttons to narrow the list, and press Restart to watch a row transition back to healthy.
cpp
// Copyright 2026 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.
//
// A complete application, rather than a demo of one property.
//
// Everything here has appeared on its own elsewhere in example/ -- reactive
// state, computed values, <for> over a collection of structs, conditional
// rendering, flexbox, grid, transitions and custom properties. This file is
// about how they compose into something you would actually ship.
//
// Try it: click a service row to select it, use the filter buttons to narrow
// the list, and press Restart to watch a row transition back to healthy.
#include <rtxui/rtxui.hpp>
#include <string>
#include <vector>
using namespace rtxui;
namespace {
struct Service {
std::string name;
std::string region;
std::string state; // "healthy" | "degraded" | "down"
int latency_ms = 0;
int load_pct = 0;
bool operator==(const Service& other) const = default;
};
} // namespace
class Dashboard : public Component<Dashboard> {
public:
std::vector<Service> services = {
{"api-gateway", "us-east-1", "healthy", 42, 61},
{"auth-service", "us-east-1", "healthy", 18, 34},
{"search-index", "eu-west-1", "degraded", 310, 88},
{"media-encoder", "eu-west-1", "down", 0, 0},
{"billing-worker", "us-west-2", "healthy", 27, 45},
{"notification-bus", "ap-south-1", "degraded", 154, 72},
};
std::string filter = "all";
std::string selected = "api-gateway";
// Computed values: recomputed whenever the state above changes.
std::string healthy_count() const { return std::to_string(Count("healthy")); }
std::string degraded_count() const {
return std::to_string(Count("degraded"));
}
std::string down_count() const { return std::to_string(Count("down")); }
std::string total_count() const { return std::to_string(services.size()); }
std::string selected_name() const { return selected; }
std::string selected_region() const {
const Service* service = Find(selected);
return service ? service->region : "-";
}
std::string selected_state() const {
const Service* service = Find(selected);
return service ? service->state : "-";
}
std::string selected_latency() const {
const Service* service = Find(selected);
return service ? std::to_string(service->latency_ms) + " ms" : "-";
}
std::string selected_load() const {
const Service* service = Find(selected);
return service ? std::to_string(service->load_pct) : "0";
}
bool selected_is_down() const {
const Service* service = Find(selected);
return service && service->state != "healthy";
}
std::string filter_all_class() const {
return filter == "all" ? "chip active" : "chip";
}
std::string filter_degraded_class() const {
return filter == "degraded" ? "chip active" : "chip";
}
std::string filter_down_class() const {
return filter == "down" ? "chip active" : "chip";
}
void ShowAll() { filter = "all"; }
void ShowDegraded() { filter = "degraded"; }
void ShowDown() { filter = "down"; }
void Restart() {
Service* service = Find(selected);
if (service) {
service->state = "healthy";
service->latency_ms = 30;
service->load_pct = 40;
}
}
std::string_view view = R"html(
<div class="app">
<div class="header">
<span class="brand">RTXUI</span>
<span class="title">Service Health</span>
<span class="spacer"></span>
<span class="pill healthy">{healthy_count} healthy</span>
<span class="pill degraded">{degraded_count} degraded</span>
<span class="pill down">{down_count} down</span>
</div>
<div class="body">
<div class="list">
<div class="filters">
<span class="{filter_all_class}" onclick="ShowAll">All</span>
<span class="{filter_degraded_class}" onclick="ShowDegraded">Degraded</span>
<span class="{filter_down_class}" onclick="ShowDown">Down</span>
</div>
<div class="rows">
<for each="{services}" as="service">
<div class="row {service.row_class}" onclick="Select({$index})">
<span class="dot {service.state}">*</span>
<span class="name">{service.name}</span>
<span class="region">{service.region}</span>
<span class="latency">{service.latency}</span>
</div>
</for>
</div>
</div>
<div class="detail">
<span class="detail-title">{selected_name}</span>
<span class="detail-sub">{selected_region}</span>
<div class="kv"><span class="k">State</span><span class="v">{selected_state}</span></div>
<div class="kv"><span class="k">Latency</span><span class="v">{selected_latency}</span></div>
<div class="kv"><span class="k">Load</span><span class="v">{selected_load}%</span></div>
<div class="meter">
<progress value="{selected_load}" max="100" width="26" />
</div>
<if condition="{selected_is_down}">
<div class="alert">This service needs attention.</div>
<button onclick="Restart">Restart service</button>
</if>
</div>
</div>
<div class="footer">
<span>{total_count} services</span>
<span class="spacer"></span>
<span class="hint">click a row to select . filter above</span>
</div>
</div>
<style>
self {
--bg: rgb(13, 17, 23);
--surface: rgb(22, 27, 34);
--raised: rgb(31, 38, 47);
--border: rgb(48, 54, 61);
--muted: rgb(139, 148, 158);
--accent: rgb(88, 166, 255);
--healthy: rgb(63, 185, 80);
--degraded: rgb(210, 153, 34);
--down: rgb(248, 81, 73);
display: block;
width: 100%;
height: 100%;
background-color: var(--bg);
color: rgb(230, 237, 243);
}
.app {
display: flex;
flex-direction: column;
height: 100%;
}
.header {
display: flex;
align-items: center;
gap: 2;
background-color: var(--surface);
border-bottom: solid;
border-color: var(--border);
padding: 0 2;
}
.brand {
color: var(--accent);
font-weight: bold;
}
.title {
color: var(--muted);
}
.spacer {
flex-grow: 1;
}
.pill {
padding: 0 1;
font-weight: bold;
}
.pill.healthy { color: var(--healthy); }
.pill.degraded { color: var(--degraded); }
.pill.down { color: var(--down); }
.body {
display: flex;
flex-grow: 1;
gap: 1;
padding: 1 2;
}
.list {
display: flex;
flex-direction: column;
flex-grow: 1;
}
.filters {
display: flex;
gap: 1;
margin-bottom: 1;
}
.chip {
border: round;
border-color: var(--border);
color: var(--muted);
padding: 0 1;
transition: border-color 0.2s ease, color 0.2s ease;
}
.chip:hover {
border-color: var(--accent);
color: var(--accent);
}
.chip.active {
border-color: var(--accent);
color: var(--accent);
font-weight: bold;
}
.rows {
display: flex;
flex-direction: column;
border: tall;
border-color: var(--border);
background-color: var(--surface);
padding: 0 1;
flex-grow: 1;
overflow-y: auto;
}
.row {
display: flex;
gap: 1;
align-items: center;
padding: 0 1;
transition: background-color 0.2s ease;
}
.row:hover {
background-color: var(--raised);
}
.row.selected {
background-color: var(--raised);
border-left: tall;
border-color: var(--accent);
}
.row.hidden {
display: none;
}
.dot.healthy { color: var(--healthy); }
.dot.degraded { color: var(--degraded); }
.dot.down { color: var(--down); }
.name {
width: 18;
font-weight: bold;
}
.region {
width: 12;
color: var(--muted);
}
.latency {
flex-grow: 1;
color: var(--muted);
text-align: right;
}
.detail {
display: flex;
flex-direction: column;
border: tall;
border-color: var(--border);
background-color: var(--surface);
padding: 1 2;
width: 34;
}
.detail-title {
color: var(--accent);
font-weight: bold;
}
.detail-sub {
color: var(--muted);
margin-bottom: 1;
}
.kv {
display: flex;
justify-content: space-between;
width: 100%;
}
.k { color: var(--muted); }
.v { font-weight: bold; }
.meter {
margin-top: 1;
}
.alert {
color: var(--down);
margin-top: 1;
}
button {
border: tall;
border-color: var(--down);
background-color: var(--bg);
color: var(--down);
padding: 0 1;
margin-top: 1;
text-align: center;
transition: background-color 0.2s ease, color 0.2s ease;
}
button:hover, button:focus {
background-color: var(--down);
color: var(--bg);
}
.footer {
display: flex;
align-items: center;
gap: 2;
border-top: solid;
border-color: var(--border);
background-color: var(--surface);
color: var(--muted);
padding: 0 2;
}
.hint {
color: var(--border);
}
</style>
)html";
Dashboard() {
BindCollection("services", &services, [this](const Service& service) {
const bool visible = filter == "all" || filter == service.state;
std::string row_class = service.name == selected ? "selected" : "";
if (!visible) {
row_class += " hidden";
}
return std::make_shared<ManualStructVisitor>(
std::map<std::string, std::string, std::less<>>{
{"name", service.name},
{"region", service.region},
{"state", service.state},
{"row_class", row_class},
{"latency", service.state == "down"
? std::string("--")
: std::to_string(service.latency_ms) + " ms"},
});
});
Bind(filter);
Bind(selected);
Bind(healthy_count);
Bind(degraded_count);
Bind(down_count);
Bind(total_count);
Bind(selected_name);
Bind(selected_region);
Bind(selected_state);
Bind(selected_latency);
Bind(selected_load);
Bind(selected_is_down);
Bind(filter_all_class);
Bind(filter_degraded_class);
Bind(filter_down_class);
Bind(ShowAll);
Bind(ShowDegraded);
Bind(ShowDown);
Bind(Restart);
Import("Select", [this](std::string index_str) {
size_t index = std::stoull(index_str);
if (index < services.size()) {
selected = services[index].name;
}
});
}
private:
int Count(std::string_view state) const {
int total = 0;
for (const Service& service : services) {
total += service.state == state ? 1 : 0;
}
return total;
}
const Service* Find(const std::string& name) const {
for (const Service& service : services) {
if (service.name == name) {
return &service;
}
}
return nullptr;
}
Service* Find(const std::string& name) {
return const_cast<Service*>(std::as_const(*this).Find(name));
}
};
int main() {
auto app = Ref<Dashboard>::New();
Screen screen(app);
screen.Loop();
return 0;
}- Source file:
example/app_dashboard.cpp - Standalone terminal: ⛶ Open Fullscreen
- Guide: Relevant Documentation
- ← Back to Examples Index

