Skip to content
IzzyBlazor 0.1.0-alpha.17

Enter all results ↑ ↓ move Esc close

Switch

An on/off switch that posts like a checkbox.

JavaScript off: what the HTML and CSS do on their own.

Usage

razor
@* The label comes from the property's [Display(Name)], or Label. *@
<Switch @bind-Value="Model!.EmailNotifications" />

@* A settings row: the switch at the end, the hint under the label. *@
<Switch @bind-Value="Model!.AutoDeploy" Label="Automatic deploys"
        ControlPosition="ControlPosition.End" Hint="Deploy main when its checks pass." />

A switch is a Checkbox that reads as on or off, and it posts the same way, true or false, so it works on static pages with JavaScript off. Use it for settings; for agreeing to something or choosing an item, use a checkbox.

At the end of the row

Use ControlPosition.End to put the switch at the end of the row, with the hint under the label, as in a list of settings.

Preview

Deploy main to production when its checks pass.

A preview URL on every pull request.

Code

ControlEnd.razor
@using System.ComponentModel.DataAnnotations

<Form Model="Model" FormName="switch-control-end" MaxWidth="32.Rem" Grow>
    <Switch @bind-Value="Model!.AutoDeploy" ControlPosition="ControlPosition.End"
            Hint="Deploy main to production when its checks pass." />
    <Switch @bind-Value="Model!.Previews" ControlPosition="ControlPosition.End"
            Hint="A preview URL on every pull request." />
</Form>

@code {
    [SupplyParameterFromForm(FormName = "switch-control-end")]
    private Project? Model { get; set; }

    protected override void OnInitialized() => Model ??= new();

    public sealed class Project
    {
        [Display(Name = "Automatic deploys")]
        public bool AutoDeploy { get; set; } = true;

        [Display(Name = "Preview deployments")]
        public bool Previews { get; set; }
    }
}

Icons on rows

Use Icon for an icon at the start of each row, and a Fieldset with Dividers to group the rows under a heading.

Preview

Email notifications

An email each time, with a link to sign that device out.

When someone mentions you or replies to you.

A short email when something new ships, about once a month.

Code

Icons.razor
@using System.ComponentModel.DataAnnotations

<Form Model="Model" FormName="switch-icons" MaxWidth="32.Rem" Grow>
    <Fieldset Label="Email notifications" Dividers Gap="3">
        <Switch @bind-Value="Model!.NewDevice" Icon="Lucide.KeyRound" ControlPosition="ControlPosition.End"
                Hint="An email each time, with a link to sign that device out." />
        <Switch @bind-Value="Model!.Mentions" Icon="Lucide.MessageSquareCheck" ControlPosition="ControlPosition.End"
                Hint="When someone mentions you or replies to you." />
        <Switch @bind-Value="Model!.ProductUpdates" Icon="Lucide.LayersPlus" ControlPosition="ControlPosition.End"
                Hint="A short email when something new ships, about once a month." />
    </Fieldset>
</Form>

@code {
    [SupplyParameterFromForm(FormName = "switch-icons")]
    private Notifications? Model { get; set; }

    protected override void OnInitialized() => Model ??= new();

    public sealed class Notifications
    {
        [Display(Name = "Sign-in from a new device")] public bool NewDevice { get; set; } = true;
        [Display(Name = "Mentions and comments")] public bool Mentions { get; set; } = true;
        [Display(Name = "Product updates")] public bool ProductUpdates { get; set; }
    }
}

The icon is decorative, so give every row in a group one, or none.

Saving as it changes

Use @bind-Value:after to save each change on an interactive page; a static page saves when the form posts, so it needs a Save button.

Preview

Visitors see a maintenance page until you turn it off.

Code

SaveOnChange.razor
<Form Model="Model" FormName="switch-save-on-change" OnValidSubmit="Save" MaxWidth="32.Rem" Grow>
    <Switch @bind-Value="Model!.Maintenance" @bind-Value:after="Save" ControlPosition="ControlPosition.End"
            Label="Maintenance mode" Hint="Visitors see a maintenance page until you turn it off." />
    <Row Gap="3" Align="Align.Center" Wrap>
        @* An interactive page saves on each change, so it needs no button. *@
        @if (!Interactive)
        {
            <Button Submit Size="ControlSize.Sm">Save</Button>
        }
        @if (_saved is not null)
        {
            <TextBlock Size="TextSize.Sm" Color="Color.Muted">@_saved</TextBlock>
        }
    </Row>
</Form>

@code {
    [SupplyParameterFromForm(FormName = "switch-save-on-change")]
    private SiteStatus? Model { get; set; }

    private string? _saved;

    // True from the prerender of an interactive page on, so the button never shows and goes.
    private bool Interactive => RendererInfo.IsInteractive || AssignedRenderMode is not null;

    protected override void OnInitialized() => Model ??= new();

    // Runs after each change on an interactive page, and on a static page's post.
    private void Save() => _saved = Model!.Maintenance ? "Last saved: in maintenance mode." : "Last saved: live.";

    public sealed class SiteStatus
    {
        public bool Maintenance { get; set; }
    }
}

Off: Switching changes nothing until Save posts the form.

To hide the button on an interactive page, check AssignedRenderMode as well as RendererInfo.IsInteractive, which is false while the page prerenders, so the button doesn't show and then disappear.

Sizes and disabled

Use Size to line up with buttons and other fields, and Disabled for a switch that can't change, which doesn't post. There's no ReadOnly: HTML has no read-only checkbox, and in a read-only Form the switch is disabled while a hidden field posts its value.

Preview

Disabled: not posted.

Code

States.razor
<Form Model="Model" FormName="switch-states" MaxWidth="32.Rem" Grow>
    <Switch @bind-Value="Model!.Small" Label="Small" Size="ControlSize.Sm" />
    <Switch @bind-Value="Model!.Large" Label="Large" Size="ControlSize.Lg" />
    <Switch @bind-Value="Model!.Replicas" Label="Read replicas" Disabled Hint="Disabled: not posted." />
</Form>

@code {
    [SupplyParameterFromForm(FormName = "switch-states")]
    private Database? Model { get; set; }

    protected override void OnInitialized() => Model ??= new();

    public sealed class Database
    {
        public bool Small { get; set; } = true;
        public bool Large { get; set; } = true;
        public bool Replicas { get; set; }
    }
}

A disabled field posts nothing, so after a static post its property holds its default (false): keep its value on the server rather than saving it from the post.

Mode support

What works in each mode, Switch
FeatureOffStaticLive
EverythingYesYesYes

Off: JavaScript disabled. Static: a static SSR page with IzzyBlazor's script. Live: an interactive page (Server, WebAssembly or Auto).

Accessibility

  • It renders a native checkbox with role="switch" inside its label, so Space toggles it and screen readers hear "on" or "off".
  • The label text names it; the hint and errors are linked with aria-describedby.
  • In Windows high-contrast mode it shows as the browser's own checkbox.

Parameters

Switch parameters
PropTypeDefault
ChildContentRich label content, such as text with a link.RenderFragment?
ControlPositionWhich side of the label the box or switch sits on.ControlPositionControlPosition.Start
IconAn icon before the label, such as a key for a security setting.IconData?
@bind-ValueThe value, bound with @bind-Value.boolfalse
DisplayNameThe field's name in validation messages from the input itself, such as a value that can't be parsed.string?

See also