Veto
Components

Switch

A sliding on/off control - and, bound to a bool?, a three-state one that also carries an indeterminate value.

On and off

Bound to a bool. Click the control or its label, or focus it and press Space.

We will only mail you about things you asked for.

True
razor
<VetoSwitch TValue="bool"
            Label="Email notifications"
            HelperText="We will only mail you about things you asked for."
            @bind-Value="_notify" />

Three states

Set ThreeState and bind to a bool?, and the switch cycles off, on, indeterminate. Indeterminate is null - the state for a question nobody has answered yet, which a plain bool has nowhere to put. The thumb sits centred so the third state reads at a glance, and the control reports itself as an ARIA checkbox with aria-checked="mixed", the only role allowed to say so.

Indeterminate

Off, on, or left undecided.

null
razor
<VetoSwitch TValue="bool?"
            ThreeState="true"
            ShowIcons="true"
            ShowStateText="true"
            Label="Archived"
            @bind-Value="_archived" />

@code {
    private bool? _archived;   // null is the indeterminate state
}

Cycle order

Which way a three-state switch walks. The default puts on second, so the first press of an unset switch reads as a plain 'turn it on'. OffIndeterminateOn suits filters, where 'unset' sits naturally between exclude and include.

Off
Off
razor
<VetoSwitch TValue="bool?" ThreeState="true" Label="Default" @bind-Value="_a" />

<VetoSwitch TValue="bool?"
            ThreeState="true"
            Order="VetoSwitchOrder.OffIndeterminateOn"
            Label="Indeterminate in the middle"
            @bind-Value="_b" />

Sizes, colours and variants

The same size, colour and variant enums the rest of the library uses, all driven by modifier classes rather than inline styles.

razor
<VetoSwitch TValue="bool" Size="VetoSize.Small" Label="Small" @bind-Value="_v" />
<VetoSwitch TValue="bool" Color="VetoColor.Success" Label="Success" @bind-Value="_v" />
<VetoSwitch TValue="bool" Variant="VetoVariant.Filled" Label="Filled" @bind-Value="_v" />

Label placement and state text

The label goes after the control by default; put it first to line a column of switches up on the left, or above it to match the other inputs. ShowStateText prints the current state next to the control, and the three texts are yours to set.

Private
razor
<VetoSwitch TValue="bool"
            LabelPlacement="VetoSwitchLabelPlacement.Start"
            Label="Label first"
            @bind-Value="_v" />

<VetoSwitch TValue="bool"
            ShowStateText="true"
            OnText="Public"
            OffText="Private"
            Label="Visibility"
            @bind-Value="_visibility" />

Disabled and read-only

Disabled cannot be focused. Read-only can be focused - so its state can still be read out - but will not change.

razor
<VetoSwitch TValue="bool" Label="Disabled" Disabled="true" @bind-Value="_v" />
<VetoSwitch TValue="bool" Label="Read-only" ReadOnly="true" @bind-Value="_v" />

Confirming or saving before the change

BeforeChange is asked with the state the switch is about to take, and can say no. While it runs the switch is busy - a spinner in the thumb, aria-busy, input ignored - which is what you want while a setting saves to the server. Loading shows the same busy state on demand.

razor
<VetoSwitch TValue="bool" Label="Sync to cloud"
            BeforeChange="SaveAsync" @bind-Value="_synced" />

@code {
    private async Task<bool> SaveAsync(bool? next)
    {
        var response = await Http.PutAsJsonAsync("api/settings/sync", next);
        return response.IsSuccessStatusCode;   // false keeps the old state
    }
}

Validation

Inside an EditForm the switch picks up the model's validation attributes like any other input: it sets aria-invalid, swaps its helper text for the message, and announces it.

Required before you can continue.

razor
<EditForm Model="_form" OnValidSubmit="Save">
    <DataAnnotationsValidator />

    <VetoSwitch Label="I accept the terms"
                Required="true"
                HelperText="Required before you can continue."
                @bind-Value="_form.AcceptedTerms" />

    <button type="submit">Save</button>
</EditForm>

@code {
    private sealed class FormModel
    {
        [Range(typeof(bool), "true", "true",
            ErrorMessage = "You must accept the terms.")]
        public bool AcceptedTerms { get; set; }
    }
}

Parameters

Parameter Type Default Description
Value TValue? default The bound value. Use @bind-Value. TValue must be bool or bool?.
ThreeState bool false Cycle off, on and indeterminate instead of two states. Requires TValue of bool?.
Order VetoSwitchOrder OffOnIndeterminate The order a three-state switch walks its states in.
Label string? null Text for the switch's label. No label element is rendered without it.
LabelPlacement VetoSwitchLabelPlacement End End, Start or Top.
HelperText string? null Guidance under the control, replaced by the validation message while invalid.
ShowStateText bool false Render the current state's text beside the control.
OnText / OffText / IndeterminateText string "On" / "Off" / "Indeterminate" The state texts. Also the accessible name when there is no label.
ShowIcons bool false Draw an icon on the thumb for the current state.
OnIcon / OffIcon / IndeterminateIcon string? Check / Close / Minus The thumb icons, when ShowIcons is set.
Color VetoColor Primary The accent the track takes when on.
Size VetoSize Medium ExtraSmall, Small, Medium, Large or ExtraLarge.
Variant VetoVariant Outlined Outlined, Filled, Text, Soft, Underlined, Ghost or Elevated.
Disabled bool false Cannot be focused or changed.
ReadOnly bool false Can be focused, but will not change.
Required bool false Renders the required marker and sets aria-required. Enforcement comes from the model.
BeforeChange Func<bool?, Task<bool>>? null Asked before every change with the next state; return false to keep the current one. The switch is busy while it runs.
Loading bool false Shows the busy state and ignores input.
OnValueChanged EventCallback<TValue?> — Raised after the bound value changes.
State bool? — Read-only: the current state, with null for indeterminate.
ToggleAsync() / SetStateAsync(bool?) Task — Drive the switch from code; both respect Disabled and ReadOnly.
Something went wrong. Reload 🗙