Common Mistakes
RTXUI templates look like HTML and Vue, and its styles look like browser CSS, so code written from habit — or by a language model — often borrows syntax RTXUI does not have. Most of these are reported at runtime as diagnostics; this page lists the right form for each.
Templates
{} holds a bound name, not an expression. There is no arithmetic, comparison or ternary in a template. Compute the value in a const method and bind it:
// Wrong: <span>{count * 2}</span> <span>{done ? "yes" : "no"}</span>
class Counter : public rtxui::Component<Counter> {
public:
int count = 0;
int Doubled() const { return count * 2; }
Counter() {
Bind(count);
Bind(Doubled);
}
std::string_view view = R"html(<span>{Doubled}</span>)html";
};Conditions and loops use RTXUI's own tags.
| Wrong | Right |
|---|---|
v-if="shown", *ngIf, x-if | if="{shown}" on the element, or <if condition="{shown}"> with <elif> / <else> |
v-for="item in items", for="item in items", <for each="item in items"> | <for each="{items}" as="item">, with {$index} for the index |
A condition is true when the bound value prints as true or 1.
Handlers name a bound method. Write onclick="Name", or onclick="Name(arg)" to pass one string argument ({$index} works inside the parentheses), and oncontextmenu for the right click. There is no @click shorthand, no inline statements, no braces, and no camelCase: @click, onClick and onclick="{() => ...}" do nothing.
Attributes bind with braces. Write title="{name}", as in text. There is no :title="name" shorthand.
Named slots use name and slot, as in HTML. A component declares <slot name="header">; its user writes slot="header" on the element to project, or <template slot="header"> around several. <slot.header> and <template.header> are not RTXUI syntax.
class, not className.
Binding
Bind takes a member name. Bind(count) binds a variable, Bind(Doubled) a const method's result, Bind(Increment) a method callable from a handler. Bind("Increment", [this] { ... }) does not exist: make the lambda a method.
Every name a template uses must be bound, or {name} prints the word name.
Components
Define a view member or a Setup() method, not both, and write Setup() without override: it is found at compile time.
Built-in tags need no import. <div>, <button>, <input> and the other built-ins are always available. Your own components must be imported before a template can use them: Import<Header>() in the constructor.
Put <style> at the top level of the view, next to the root element. A <style> nested inside an element is ignored.
There is no <View> or <Text>. A tag that is neither a built-in nor an imported component renders as an unstyled box.
Styling
Lengths are terminal cells. width: 20 is twenty columns; px, em and rem do not exist (vh and vw, shares of the terminal, do). Fonts do not exist in a terminal, so font-size and font-family do nothing; use font-weight, font-style, text-decoration and colors for emphasis. The CSS reference lists every supported property.
A child cannot see an outer component's classes. Styles are scoped to the component that declares them, selectors included: .dark .title written in a child component never matches a .dark the parent set on an ancestor. Pass the context in instead, as a custom property (--accent: ... inherits through every component) or as a prop the child turns into one of its own classes. @keyframes are scoped the same way: declare them in the component whose rules use them.
There is no transform. To move a box, use translate: 2 1 rather than transform: translate(2, 1) or translateX(2). It takes the same lengths, percentages of the box's own size and calc(), and it animates.
C++ and Build
Include only <rtxui/rtxui.hpp>. Headers under src/ are internal and not installed.
Only the UI thread touches component state. From a worker thread, hand the result back with rtxui::PostTask(...), which is safe to call from any thread (see the cookbook).

