Skip to main content
The Reactivity page introduced {{ count + 1 }} as a way to compute new values from state. Expressions support a full set of operators — arithmetic, comparisons, boolean logic, and conditionals — that let you build complex display logic without leaving the browser. Here’s a component that uses several of them together: arithmetic to increment and decrement a quantity, multiplication to compute a total, and a formatting pipe to display it as currency. The rest of this page walks through each operator type. Every example shows the Python Rx syntax and the {{ }} protocol expression it compiles to.

Arithmetic

Rx objects overload Python’s arithmetic operators, so price * quantity in your Python code compiles to {{ price * quantity }} in the protocol. The quantity selector above uses addition, subtraction, and multiplication — here’s the full set:
PythonProtocolDescription
count + 1{{ count + 1 }}Addition
total - discount{{ total - discount }}Subtraction
price * quantity{{ price * quantity }}Multiplication
amount / 2{{ amount / 2 }}Division
-score{{ -score }}Negation
Arithmetic expressions can appear anywhere a value is expected — in a Text component, in a SetState action, or in a prop like Progress(value=...). The renderer evaluates them against current state each time a referenced key changes.

String Concatenation

The + operator does double duty: if either operand is a string, it concatenates instead of adding. But in Python, f-strings are almost always the better choice for mixing reactive values with literal text. Each Rx reference inside an f-string becomes a separate {{ }} interpolation in the output: In the protocol, you can also concatenate with + inside a single expression: {{ 'Hello, ' + first + ' ' + last + '!' }}. F-strings are almost always cleaner.

Comparison

Six comparison operators return boolean values. On their own, a boolean isn’t very useful in a Text component — but comparisons are the foundation for two things you’ll use constantly: conditional rendering with If/Elif/Else, and conditional values with the ternary operator (covered below).
PythonProtocolMeaning
count > 0{{ count > 0 }}Greater than
count >= 10{{ count >= 10 }}Greater than or equal
count < 100{{ count < 100 }}Less than
count <= 50{{ count <= 50 }}Less than or equal
status == 'active'{{ status == 'active' }}Equal (loose)
status != 'done'{{ status != 'done' }}Not equal
Here’s the most common pattern — showing different content based on a state value:
from prefab_ui.rx import Rx
from prefab_ui.components import Alert
from prefab_ui.components.control_flow import If, Elif

inventory = Rx("inventory")

with If(inventory == 0):
    Alert("Out of stock", variant="destructive")
with Elif((inventory > 0) & (inventory < 10)):
    Alert("Low stock")
The If component receives a boolean expression and only renders its children when the expression is true. When inventory changes, the conditions re-evaluate and the UI updates to show the right alert.

Logical

Boolean operators combine multiple conditions. Python doesn’t allow overloading and, or, and not, so Rx uses the bitwise operators &, |, and ~ instead. They compile to &&, ||, and ! in the protocol:
PythonProtocolMeaning
a & b{{ a && b }}Logical AND
a | b{{ a || b }}Logical OR
~a{{ !a }}Logical NOT
The protocol also accepts keyword forms and, or, and not — use whichever reads better in context. Both && and || short-circuit, which makes || useful as a default-value mechanism: {{ name || 'Anonymous' }} returns 'Anonymous' when name is falsy (undefined, empty string, false, or 0).
Python precedence gotcha. Bitwise & and | bind tighter than >, <, ==, etc. in Python. Without parentheses, score > 0 & score < 100 parses as score > (0 & score) < 100, which is not what you want. Always wrap each comparison in parentheses when combining with & or |:
# Correct
(score > 0) & (score < 100)

# Wrong — parsed as score > (0 & score) < 100
score > 0 & score < 100
This is a Python quirk, not a Prefab one. The protocol’s {{ }} expressions don’t have this issue — && and || have lower precedence than comparisons there.

Ternary

Sometimes you need to choose between two values based on a condition — “Online” or “Offline”, “Pass” or “Fail”, one color or another. The .then(if_true, if_false) method on Rx handles this, compiling to the protocol’s condition ? ifTrue : ifFalse syntax: Toggle the switch — the text updates instantly between “Online” and “Offline”.
PythonProtocol
active.then("On", "Off"){{ active ? 'On' : 'Off' }}
(score > 90).then("Pass", "Fail"){{ score > 90 ? 'Pass' : 'Fail' }}
Ternaries can technically be nested — (score > 90).then("A", (score > 80).then("B", "C")) — but readability suffers quickly. For anything beyond a simple two-way choice, If/Elif/Else is almost always cleaner. When in doubt about any expression, add parentheses. The Rx DSL handles parenthesization automatically in the compiled output, so explicit parens in Python never hurt.