A number field with ± steppers, bounds and a step — arrow keys and the steppers never leave the range.
A seat calculator
on_change sends the count to Python; only the total re-renders.
From 1 to 50 on the Team plan.
5 × €12 / month
€60.00
classSeatOrder(PageState):seats:int=field(default=5)defseats_changed(order:SeatOrder)->None:"""The typed parameter receives the new count; the total follows."""@refreshable(deps=[SeatOrder])deforder_total()->None:seats=SeatOrder().seatswithui.hstack(justify="between"):ui.text(f"{seats} × €{SEAT_PRICE:.0f} / month",color="muted")ui.heading(f"€{seats*SEAT_PRICE:,.2f}",level=3,size="xl")defseat_calculator()->None:withui.card(padding="md",classes="w-full max-w-sm"),ui.vstack(gap="md"):withui.form_field(label="Seats",hint="From 1 to 50 on the Team plan."):ui.number_input(value=SeatOrder().seats,min=1,max=50,on_change=seats_changed)ui.divider()order_total()
Bounds and steps
min and max clamp every change, step sets the increment — decimals included.
Steps of 5.
Steps of 0.1.
Between 0 and 5.
defbounds_and_steps()->None:withui.grid(cols={"base":1,"sm":3},gap="md",classes="w-full max-w-2xl"):withui.form_field(label="Discount (%)",hint="Steps of 5."):ui.number_input(value=15,min=0,max=100,step=5)withui.form_field(label="Parcel weight (kg)",hint="Steps of 0.1."):ui.number_input(value=2.4,min=0.1,max=30,step=0.1)withui.form_field(label="Retries",hint="Between 0 and 5."):ui.number_input(value=3,min=0,max=5)