Skip to content
IzzyBlazor 0.1.0-alpha.17

Enter all results ↑ ↓ move Esc close

Checkbox

A checkbox drawn to match the fields.

An interactive page: C# runs over a Blazor Server connection.

Usage

razor
@* The label comes from the property's [Display(Name)], or Label. *@
<Checkbox @bind-Value="Model!.Subscribe" />
<Checkbox @bind-Value="Model!.RememberMe" Label="Keep me signed in" />

@* A label with markup. *@
<Checkbox @bind-Value="Model!.AcceptTerms">
    I agree to the <Anchor Href="terms">terms of service</Anchor>
</Checkbox>

Use a checkbox for one yes-or-no choice, such as agreeing to something; a Switch for a setting that reads as on or off, and a CheckboxGroup for several choices from a list.

What it posts

A checked box posts true, and an unchecked one posts false from a hidden field that follows it, so a property that defaults to true can be turned off on a static page. A disabled box posts nothing.

Agreeing to terms

Use ChildContent for a label with markup, such as a link, and [Required] with [Range(typeof(bool), "true", "true")] for a box that must be checked.

Preview

Code

Terms.razor
@using System.ComponentModel.DataAnnotations

<Form Model="Model" FormName="checkbox-terms" OnValidSubmit="Save" MaxWidth="28.Rem" Grow>
    <Checkbox @bind-Value="Model!.AcceptLicense">
        Publish under the <Anchor Href="https://opensource.org/license/mit" External>MIT license</Anchor>
    </Checkbox>
    <Row><Button Submit>Publish package</Button></Row>
    @if (_published)
    {
        <Alert Status="Status.Success">Published under the MIT license.</Alert>
    }
</Form>

@code {
    [SupplyParameterFromForm(FormName = "checkbox-terms")]
    private Package? Model { get; set; }

    private bool _published;

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

    private void Save() => _published = true;

    public sealed class Package
    {
        // [Required] has the browser stop the post until it's checked. A bool is never null, so
        // [Required] alone passes on the server: [Range] is the server's check.
        [Required(ErrorMessage = "Agree to the license to publish")]
        [Range(typeof(bool), "true", "true", ErrorMessage = "Agree to the license to publish")]
        [Display(Name = "License")]
        public bool AcceptLicense { get; set; }
    }
}

Live: The browser stops the post in the model's words, and clearing a checked box shows them under it at once.

[Required] has the browser stop the post until the box is checked, but a bool is never null, so on the server it always passes: [Range] is the check there. Give both the same ErrorMessage, and with script the browser shows it too.

Select all

Use a CheckboxGroup with SelectAll for a box that checks or clears a list of others at once; the script does it on static pages too.

Preview

Notify me about

Code

Everything.razor
@using System.ComponentModel.DataAnnotations
@using Microsoft.AspNetCore.Http

<Form Model="Model" FormName="checkbox-group-everything" OnValidSubmit="Save" MaxWidth="24.Rem" Grow>
    <CheckboxGroup @bind-Value="Model!.Topics" Items="Enum.GetValues<Topic>()" SelectAll SelectAllText="Everything" />
    <Row Gap="3" Align="Align.Center" Wrap>
        <Button Submit>Save</Button>
        @if (_saved is not null)
        {
            <TextBlock Size="TextSize.Sm" Color="Color.Muted">Last saved: @_saved</TextBlock>
        }
    </Row>
</Form>

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

    private string? _saved;

    [CascadingParameter] private HttpContext? HttpContext { get; set; }

    // With nothing checked the group posts nothing: give the defaults only when this form didn't post.
    protected override void OnInitialized()
    {
        var posted = HttpContext?.Request.HasFormContentType == true
            && HttpContext.Request.Form["_handler"] == "checkbox-group-everything";
        Model ??= posted ? new() : new() { Topics = [Topic.Comments] };
    }

    // What was saved, not the field: on an interactive page it changes as boxes are checked.
    private void Save() => _saved = Model!.Topics is { Count: > 0 } topics
        ? string.Join(", ", Enum.GetValues<Topic>().Where(topics.Contains)) + "."
        : "nothing.";

    public sealed class Notifications
    {
        [Display(Name = "Notify me about")]
        public List<Topic>? Topics { get; set; } = [];
    }

    public enum Topic { Comments, Mentions, Releases }
}

A dash of your own

Use Indeterminate to show a dash when only some of what a box stands for is checked, and set the others from its ValueChanged on an interactive page.

Always Live

Preview

Code

SelectAll.razor
@* Interactive pages only: C# sets the dash and all three. On a static page, use a CheckboxGroup's
   SelectAll, which the script runs. *@
<Form Model="Model" FormName="checkbox-select-all" MaxWidth="24.Rem" Grow>
    <Column Gap="2">
        <Checkbox Value="AllOn" ValueChanged="SetAll" ValueExpression="() => Model!.Everything"
                  Indeterminate="SomeOn" Label="Notify me about everything" />
        <Column Gap="2" PaddingStart="6">
            <Checkbox @bind-Value="Model!.Comments" />
            <Checkbox @bind-Value="Model!.Mentions" />
            <Checkbox @bind-Value="Model!.Releases" />
        </Column>
    </Column>
</Form>

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

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

    // The top box is worked out from the three below.
    private bool AllOn => Model!.Comments && Model.Mentions && Model.Releases;
    private bool SomeOn => !AllOn && (Model!.Comments || Model.Mentions || Model.Releases);

    // Checking the top box sets all three.
    private void SetAll(bool on) => Model!.Comments = Model.Mentions = Model.Releases = on;

    public sealed class Notifications
    {
        public bool Everything { get; set; }
        public bool Comments { get; set; } = true;
        public bool Mentions { get; set; }
        public bool Releases { get; set; }
    }
}

Nothing links the boxes but your C#, so this works on an interactive page only; on a static page, use SelectAll.

Hints, icons and the end of the row

Use Hint for help under the label, ControlPosition.End to put the box at the end of the row and Icon for an icon at its start, as on a Switch (see them there).

Sizes and disabled

Use Size to line up with buttons and other fields, and Disabled for a box 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 box is disabled while a hidden field posts its value.

Preview

Code

Sizes.razor
<Form Model="Model" FormName="checkbox-sizes" Grow>
    <Row Gap="5" Wrap>
        <Checkbox @bind-Value="Model!.Small" Label="Small" Size="ControlSize.Sm" />
        <Checkbox @bind-Value="Model!.Medium" Label="Medium" />
        <Checkbox @bind-Value="Model!.Large" Label="Large" Size="ControlSize.Lg" />
    </Row>
    <Row Gap="5" Wrap>
        <Checkbox @bind-Value="Model!.Locked" Label="Disabled" Disabled />
        <Checkbox @bind-Value="Model!.LockedOn" Label="Disabled, checked" Disabled />
    </Row>
</Form>

@code {
    [SupplyParameterFromForm(FormName = "checkbox-sizes")]
    private Options? Model { get; set; }

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

    public sealed class Options
    {
        public bool Small { get; set; } = true;
        public bool Medium { get; set; } = true;
        public bool Large { get; set; } = true;
        public bool Locked { get; set; }
        public bool LockedOn { get; set; } = true;
    }
}

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, Checkbox
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 inside its label, so Space toggles it and clicking the label does too.
  • The label text, or ChildContent, names it; the hint and errors are linked with aria-describedby, and an Icon beside it is hidden from screen readers.
  • With script, an unchecked indeterminate box is announced as "mixed"; with JavaScript off, only the dash shows it and screen readers hear "not checked". A checked box is "checked" either way, with no dash.

Parameters

Checkbox parameters
PropTypeDefault
ChildContentRich label content, such as text with a link.RenderFragment?
IndeterminateShows the box as partly selected (a dash), such as a "select all" box when only some items are.boolfalse
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