Tutorial: Form Controls — Blazor

Compose a complete data-entry form using IsabyteTextInput, IsabyteDropdown, IsabyteDateSelector, and IsabyteSwitch. Covers two-way binding, validation, and submission — about 60 lines of Razor.

Package: Isabyte.PowerTools.Blazor (see Package Setup).

Step 1 — Define the Form Model

Isabyte controls bind to plain C# properties — there's no special model base class. Add DataAnnotations attributes for validation; EditForm and Blazor's built-in validator components pick them up automatically.

using System.ComponentModel.DataAnnotations;

public class SignUpForm
{
    [Required, StringLength(60, MinimumLength = 2)]
    public string FullName { get; set; } = "";

    [Required, EmailAddress]
    public string Email { get; set; } = "";

    [Required]
    public string Role { get; set; } = "";

    [Required]
    public DateTime? StartDate { get; set; }

    public bool SubscribeToNewsletter { get; set; } = true;
}

Step 2 — Wire Up the Controls (text-input, dropdown, date-selector, switch)

Wrap the inputs in an EditForm. Its Model attribute is what DataAnnotationsValidator inspects on submit, and OnValidSubmit fires only when every annotation passes. Isabyte controls use the standard Blazor two-way binding pattern — @bind-Value for any control exposing a Value/ValueChanged pair — every control here except IsabyteDateRangeSelector, which binds StartDate/EndDate instead.

@page "/sign-up"

<EditForm Model="_form" OnValidSubmit="HandleSubmitAsync">
    <DataAnnotationsValidator />

    <div class="mb-3">
        <label class="form-label">Full name</label>
        <IsabyteTextInput @bind-Value="_form.FullName" Placeholder="Jane Smith" />
        <ValidationMessage For="@(() => _form.FullName)" />
    </div>

    <div class="mb-3">
        <label class="form-label">Email</label>
        <IsabyteTextInput @bind-Value="_form.Email"
                       Placeholder="jane@example.com"
                       Validation="TextValidation.EmailValidation" />
        <ValidationMessage For="@(() => _form.Email)" />
    </div>

    <div class="mb-3">
        <label class="form-label">Role</label>
        <IsabyteDropdown @bind-Value="_form.Role"
                      Items="_roles"
                      Placeholder="Pick a role…" />
        <ValidationMessage For="@(() => _form.Role)" />
    </div>

    <div class="mb-3">
        <label class="form-label">Start date</label>
        <IsabyteDateSelector @bind-Value="_form.StartDate" Min="DateTime.Today" />
        <ValidationMessage For="@(() => _form.StartDate)" />
    </div>

    <div class="mb-3">
        <IsabyteSwitch @bind-Value="_form.SubscribeToNewsletter"
                   Label="Send me product updates" />
    </div>

    <button type="submit" class="btn btn-primary">Create account</button>
</EditForm>

@code {
    private SignUpForm _form = new();
    private List<string> _roles = new() { "Developer", "Designer", "Product Manager", "Other" };

    private async Task HandleSubmitAsync()
    {
        await _accountService.CreateAccountAsync(_form);
        _navigationManager.NavigateTo("/welcome");
    }
}

Step 3 — How the Binding Works

@bind-Value="_form.FullName" expands to two attributes at compile time: it sets Value="_form.FullName" on the way in, and subscribes to ValueChanged to assign back on the way out — identical to the binding model used by built-in Blazor inputs like InputText. Reassigning the field re-renders the control with the new value. (The control does keep a little internal state — it tracks the last value it pushed so an echo from the browser cannot fight your model — but you never manage that yourself.)

Step 4 — Validation

IsabyteTextInput.Validation gives per-field visual feedback while typing (TextValidation.EmailValidation, TextValidation.PasswordValidation). It doesn't replace DataAnnotationsValidator — EditForm + [Required] still runs at submit time, producing the messages shown by <ValidationMessage>.

Step 5 — Handle Submission

OnValidSubmit only fires once every annotation has passed; if anything fails, OnInvalidSubmit fires instead. Return Task from the handler so Blazor re-renders before and after the await — useful for a "Saving…" button label wired to an _isSaving flag.

Common Gotchas

  • Nullable mismatch. IsabyteDateSelector.Value is DateTime?. If your model field is non-nullable DateTime, the compiler accepts the binding but you lose the "no date selected" state.
  • Dropdown items late. If Items fills from an async load, the dropdown renders empty until it completes.
  • Switch default value. A bool defaults to false — initialize the field to true if "opted in" is your preferred default.

Next

An unhandled error has occurred. Reload 🗙

Rejoining the server...

Rejoin failed... trying again in seconds.

Failed to rejoin.
Please retry or reload the page.

The session has been paused by the server.

Failed to resume the session.
Please reload the page.