Form Validation

Stario + Datastar allow for instant, server-side validation without page refreshes.

1. The Frontend

Bind your inputs to signals and use data.show to display errors.

async def home(c: Context, w: Writer):
    w.html(
        Form(
            data.signals({"user": "", "errors": {}}),
            Input(data.bind("user")),
            P(data.show("$errors.user"), data.text("$errors.user"), {"class": "err"}),
            Button(data.on("click", at.post("/save")), "Submit")
        )
    )

2. The Backend

Validate the signals and sync any errors back to the client.

async def handle_save(c: Context, w: Writer):
    signals = await c.signals()
    user = signals.get("user", "")

    errors = {}
    if len(user) < 3:
        errors["user"] = "Too short!"

    if errors:
        return w.sync({"errors": errors})

    # Process valid data...
    await db.save(user)
    w.patch(Div("Saved!"))

Live Validation (Debounced)

To validate as the user types, add an action to the input with a debounce.

Input(
    data.bind("user"),
    data.on("input", at.get("/validate"), debounce=0.3) # 300ms delay
)

This keeps the server from being overwhelmed by every keystroke while providing instant feedback to the user.