starhtml

from starhtml import *

# Create reactive state
(stars := Signal('stars', 0))

# Build reactive UI
Button("Add", data_on_click=stars.add(1))
Span(data_text="Stars in the sky: " + stars)
Stars in the sky:

Explore more below

Core Philosophy

Four principles that make StarHTML powerful yet simple

Quick Reference

Copy-paste syntax cheat sheet for common patterns

from starhtml import *

# 1. Define reactive state (walrus := for inline definition)
(counter := Signal("counter", 0))           # Define + assign in one line
(name := Signal("name", ""))                # Available throughout component
(is_visible := Signal("is_visible", True))  # All Signal() objects auto-collected  

# 2. Basic reactivity
data_show=is_visible                        # Show/hide elements
data_text=name                              # Display signal value
data_bind=name                              # Two-way form/input binding
data_class_active=is_visible                # Conditional CSS class

# 3. Event handling  
data_on_click=counter.add(1)               # Increment counter
data_on_input=name.set("")                 # Clear input
data_on_submit=post("/api/save")           # HTTP request

# 4. Signal operations
counter.add(1)                             # → $counter++
counter.set(0)                             # → $counter = 0  
is_visible.toggle()                        # → $is_visible = !$is_visible
name.upper().contains("ADMIN")             # → $name.toUpperCase().includes("ADMIN")

# 5. Logical expressions
all(name, email, age)                      # All truthy → !!$name && !!$email && !!$age
any(error1, error2)                        # Any truthy → $error1 || $error2
name & email                               # Both truthy → $name && $email
~is_visible                                # Negation → !$is_visible

# 6. Conditional helpers  
status.if_("Active", "Inactive")           # Simple binary toggle (EXCLUSIVE)
match(theme, light="☀️", dark="🌙")        # Match signal value to outputs (EXCLUSIVE) 
switch([(~name, "Required"), (name.length < 2, "Too short")], default="Valid")  # First-match-wins (EXCLUSIVE)
collect([(is_active, "active"), (is_large, "lg")])  # Combine multiple classes (INCLUSIVE)
Common Gotcha: Use + for reactive strings ("Count: " + counter), not f-strings which are static!

See It In Action

Explore interactive examples.

Browse Live Demos