Switch
A static page with IzzyBlazor's script. No circuit.
Usage
@* 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
Code
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>
{
[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
Code
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>
{
[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
Code
<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>
{
[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; }
}
}Static: Switching changes nothing until Save posts the form; the page doesn't reload.
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
Code
<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>
{
[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
| Feature | Off | Static | Live |
|---|---|---|---|
| Everything | Yes | Yes | Yes |
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 itslabel, 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
| Prop | Type | Default |
|---|---|---|
ChildContentRich label content, such as text with a link. | RenderFragment? | |
ControlPositionWhich side of the label the box or switch sits on. | ControlPosition | ControlPosition.Start |
IconAn icon before the label, such as a key for a security setting. | IconData? | |
@bind-ValueThe value, bound with @bind-Value. | bool | false |
DisplayNameThe field's name in validation messages from the input itself, such as a value that can't be parsed. | string? |
Plus 26 field props.
Full APISee also
- Checkbox: a checkbox drawn to match the fields.
- SegmentedControl: one choice from a few, as joined buttons.
- CheckboxGroup: several choices as checkboxes.
- Demos: Notification settings.