BitToggle is a physical switch turned into a control: flip it to choose between two mutually exclusive options - “On/Off”, “Show/Hide” - and the choice takes effect right away, with no Save button in between. That immediacy is what separates it from a checkbox, which states an intention that a later submit carries out; a switch inside a long form that ends in a Submit button is the one place not to use it. The knob slides between the two ends of the track, so the state is carried by position as much as by color, and the slide collapses to a jump wherever reduced motion is asked for. It is built on a real focusable button with the switch role, so Tab reaches it, Space and Enter flip it, and screen readers announce it as a switch together with its state. Beyond the two plain states it can name each of them with a state text, put an icon or arbitrary content inside its track, explain itself in a description line, show a spinner for as long as the change is still in flight, refuse a change before it lands, be flipped from code, and place its label on any side of the knob.

Usage


Basic

<BitToggle Label="Basic" />
<BitToggle Label="On by default" DefaultValue="true" />
<BitToggle Label="Disabled" IsEnabled="false" />
<BitToggle Label="Disabled and on" IsEnabled="false" Value="true" />
A click anywhere on the BitToggle - the track, its label or its state text - flips it, and the knob slides to the other end of the track to say so. Left unbound like the first one below, it keeps its own state with no binding or event handler involved, and DefaultValue only picks where that state starts. Disabling it greys it out and takes it out of the tab order and the interaction entirely; the disabled state renders both on and off.




Texts

<BitToggle Label="Text" Text="This is a toggle!" />

<BitToggle Label="OnText & OffText" OnText="Toggle is On" OffText="Toggle is Off" />

<BitToggle Label="OnText only (Text as the fallback)" OnText="Enabled" Text="Not enabled yet" />
A state text sits next to the knob and says in words what the knob says in position. OnText and OffText give each state its own wording, while Text is the single fallback used whenever the text for the current state is missing - so setting only Text labels both states the same way, and setting only OnText leaves the off state showing Text or nothing at all.





Track content

<BitToggle Label="Text content">
    <OnContent>ON</OnContent>
    <OffContent>OFF</OffContent>
</BitToggle>

<BitToggle Label="Icon content" DefaultValue="true">
    <OnContent><BitIcon IconName="@BitIconName.Accept" /></OnContent>
    <OffContent><BitIcon IconName="@BitIconName.Cancel" /></OffContent>
</BitToggle>

<BitToggle Label="Only one side">
    <OffContent>Click me</OffContent>
</BitToggle>
OnContent and OffContent put arbitrary markup inside the track, on the side the knob has just left - the compact "I/O", "ON/OFF" or ✓/✗ pattern that fits where there is no room for a state text beside the toggle. The track widens to fit whatever is put in it instead of letting it overflow, and the content is hidden from screen readers, which already learn the state from the switch itself. Both sides are laid out on top of each other, so the track is as wide as the wider of the two and keeps that width through a flip - the third toggle below, which only has an off side, does not shrink when it is turned on.





Icons

<BitToggle Label="Both states" OnIconName="@BitIconName.Accept" OffIconName="@BitIconName.Cancel" />

<BitToggle Label="On state only" OnIconName="@BitIconName.CheckMark" DefaultValue="true" />

<BitToggle Label="Icon and track content" OnIconName="@BitIconName.Sunny" OffIconName="@BitIconName.ClearNight">
    <OnContent>Day</OnContent>
    <OffContent>Night</OffContent>
</BitToggle>

<BitToggle Label="Disabled" OnIconName="@BitIconName.Accept" OffIconName="@BitIconName.Cancel" IsEnabled="false" />
OnIconName and OffIconName draw a glyph inside the knob itself, the way a native platform switch marks its two states. The whole toggle steps up to a roomier geometry as soon as either of them is set - and stays there in both states - so flipping it never resizes it under the pointer. Setting only one of the two leaves the other state with a plain knob. The External Icons section shows the BitIconInfo counterparts of these parameters.







Label

<BitToggle Label="This is an inline label" Inline />

<BitToggle>
    <LabelTemplate>
        <div style="display:flex;align-items:center;gap:10px">
            <BitLabel Style="color:green">This is custom Label</BitLabel>
            <BitIcon IconName="@BitIconName.Filter" />
        </div>
    </LabelTemplate>
</BitToggle>
By default the label sits above the knob. Inline puts the two on a single line instead, which is the usual shape of a settings row. When a plain string is not enough - a formatted phrase, an icon, a link to what is being switched on - LabelTemplate replaces the label with arbitrary markup while it stays part of the click target and keeps naming the switch for screen readers.


Inline:





LabelTemplate:

Label position

<BitToggle Label="Top" LabelPosition="BitLabelPosition.Top" />
<BitToggle Label="Bottom" LabelPosition="BitLabelPosition.Bottom" />
<BitToggle Label="Start" LabelPosition="BitLabelPosition.Start" />
<BitToggle Label="End" LabelPosition="BitLabelPosition.End" />
LabelPosition places the label on any of the four sides of the knob: Top is the default stacked layout, Bottom flips that stack, and Start and End put the two on one line - the same shapes Inline and Reversed reach, expressed as one choice rather than two flags. It takes precedence over both of them when set, and it follows the reading direction, so Start is the left in LTR and the right in RTL.

Reversed

<BitToggle Label="This is a reversed label" Reversed />

<BitToggle Label="This is a reversed inline label" Reversed Inline />
Reversed swaps the two sides, putting the knob before the label. On its own it flips the stacked layout; combined with Inline it flips the single-line one. It is the two-flag shorthand of the LabelPosition parameter above.


Default:





Inline:

FullWidth

<BitToggle Label="This is a full-width toggle" FullWidth Inline />

<BitToggle Label="This is a reversed full-width toggle" Reversed FullWidth Inline />

<BitToggle FullWidth Inline>
    <LabelTemplate>
        <BitActionButton FullWidth>go go go</BitActionButton>
    </LabelTemplate>
</BitToggle>
FullWidth stretches the BitToggle across its container and pushes the label and the knob to opposite edges - the layout of a settings list, where every row lines its switches up on the same side. It is meant for the single-line shapes, so it is paired with Inline (or a Start/End label position) below.


Default:





Reversed:



Loading

<BitToggle Label="Save to the server" Loading="isSaving" Value="savedValue" OnChange="HandleSaveToggle" />

<div>Saved state: <b>@savedValue</b></div>


<BitToggle Label="Save to the server (AutoLoading)" AutoLoading @bind-Value="autoLoadingValue" OnChange="SaveTheToggle" />


<BitToggle Label="Loading" Loading />
<BitToggle Label="Loading and on" Loading Value="true" />
<BitToggle Label="Loading with icons" Loading OnIconName="@BitIconName.Accept" OffIconName="@BitIconName.Cancel" />
@code {
    private bool isSaving;
    private bool savedValue;
    private bool autoLoadingValue;
    
    private async Task HandleSaveToggle(bool value)
    {
        isSaving = true;
    
        await Task.Delay(1000);
    
        savedValue = value;
        isSaving = false;
    }
    
    private async Task SaveTheToggle(bool value)
    {
        // AutoLoading keeps the toggle busy for exactly as long as this callback takes
        await Task.Delay(1000);
    }
}
                    
A switch promises an immediate result, which is a promise a round trip to a server cannot always keep. Loading covers that gap: the knob turns into a spinner, the toggle keeps its current state and stops accepting clicks, and it is announced as busy and unavailable - so the change in flight is never flipped a second time while it is still being saved. The toggle below stays busy for a second before its new state lands.


Saved state: False



AutoLoading reaches the same result without a flag of its own: the BitToggle raises and clears the busy state itself around its awaited callbacks - OnClick, OnChanging and OnChange - so the spinner covers exactly as long as the work behind the change takes. The toggle below saves for a second with no isSaving field anywhere.




The spinner takes the place of the knob's icon, so it works with or without one, and it is drawn to the size of whichever knob it lands in - turning a toggle busy never resizes it in front of the person waiting on it:

Read-only & Required

<BitToggle Label="Read-only toggle" ReadOnly @bind-Value="readOnlyValue" Text="Locked" />
<BitToggleButton @bind-IsChecked="readOnlyValue" Text="Change it from here" />


<BitToggle Label="I accept the terms" Required />
@code {
    private bool readOnlyValue;
}
                    
ReadOnly keeps the BitToggle focusable and lets screen readers announce it and its state, but clicking or pressing Space no longer changes it - unlike disabling, which takes it out of the interaction altogether. The value can still change from code:




Required marks the label with an asterisk and tells assistive technologies the choice has to be made. Because a switch is always in one of its two states, the rule that makes one of them wrong belongs to the model - see the Validation section - rather than to the browser's own required check.

Binding

<BitToggle Label="Always on" Value="true" />

<BitToggle Label="One-way" Value="oneWayValue" />
<BitToggleButton @bind-IsChecked="oneWayValue" OnText="On" OffText="Off" />

<BitToggle Label="Two-way" @bind-Value="twoWayValue" />
<BitToggleButton @bind-IsChecked="twoWayValue" OnText="On" OffText="Off" />


<BitButton OnClick="() => methodToggleRef.ToggleAsync()">Flip it</BitButton>
<BitButton OnClick="() => methodToggleRef.ToggleAsync(true)">Turn it on</BitButton>
<BitButton OnClick="() => methodToggleRef.ToggleAsync(false)">Turn it off</BitButton>

<BitToggle @ref="methodToggleRef" Label="Driven from code" ReadOnly
           Text="Read-only, still scriptable" OnChange="LogMethodChange" />

<div>@(string.IsNullOrEmpty(methodChangeLog) ? "Nothing changed yet." : methodChangeLog)</div>
@code {
    private bool oneWayValue;
    private bool twoWayValue;
    
    private string methodChangeLog = string.Empty;
    private BitToggle methodToggleRef = default!;
    
    private void LogMethodChange(bool value)
    {
        methodChangeLog = $"OnChange fired with {value}";
    }
}
                    
Value comes in the usual binding shapes. Passed one-way, the parameter dictates the state: the BitToggle renders whatever the expression says and a click cannot move it away from a fixed value. Bound two-way with @bind-Value, changes flow in both directions - flipping the toggle updates the field, and updating the field from elsewhere (the toggle buttons below) flips the toggle.

One-way (fixed):


One-way:


Two-way:



The ToggleAsync method changes the state from code through the very path a click takes, so OnChanging still gets its veto and OnChange still reports the result - which is what separates it from writing to the bound field directly. Its overload takes the state to move to instead of flipping the current one, and does nothing when the toggle is already in it. Neither the read-only nor the loading state stops it: those close the toggle to the user, not to the code behind it - only disabling it closes both.



Nothing changed yet.

Events

<style>
    .clickable-box {
        padding: 1rem;
        cursor: pointer;
        width: fit-content;
        border-radius: 0.25rem;
        border: 1px dashed gray;
    }
</style>


<BitToggle Label="Flip me"
           OnClick="LogOnClick"
           OnChanging="LogOnChanging"
           OnChange="LogOnChange" />

<div>@(string.IsNullOrEmpty(eventsLog) ? "No clicks yet." : eventsLog)</div>


<BitToggle Label="Allow the change" @bind-Value="allowChange" />

<BitToggle Label="Guarded toggle" OnChanging="HandleOnChanging" />

<div>Cancelled attempts: @cancelledCounter</div>


<div class="clickable-box" @onclick="() => containerClickCounter++">
    <BitToggle Label="Bubbles up" />
    <BitToggle Label="Stops here" StopPropagation />
</div>

<div>Container clicks: @containerClickCounter</div>


<BitToggle Label="Focus me"
           OnFocus="LogOnFocus"
           OnBlur="LogOnBlur"
           OnFocusIn="LogOnFocusIn"
           OnFocusOut="LogOnFocusOut" />

<div>@(string.IsNullOrEmpty(focusLog) ? "Not focused yet." : focusLog)</div>
@code {
    private string eventsLog = string.Empty;
    private string focusLog = string.Empty;
    private int cancelledCounter;
    private int containerClickCounter;
    private bool allowChange;
    
    private void LogOnClick()
    {
        eventsLog = "OnClick";
    }
    
    private void LogOnChanging(BitToggleChangeArgs args)
    {
        eventsLog += $" → OnChanging (to {args.Value})";
    }
    
    private void LogOnChange(bool value)
    {
        eventsLog += $" → OnChange ({value})";
    }
    
    private void HandleOnChanging(BitToggleChangeArgs args)
    {
        if (allowChange) return;
    
        args.Cancel = true;
        cancelledCounter++;
    }
    
    private void LogOnFocus()
    {
        focusLog = "OnFocus";
    }
    
    private void LogOnFocusIn()
    {
        focusLog += " → OnFocusIn";
    }
    
    private void LogOnFocusOut()
    {
        focusLog = "OnFocusOut";
    }
    
    private void LogOnBlur()
    {
        focusLog += " → OnBlur";
    }
}
                    
Three callbacks fire in a fixed order around a click: OnClick first, while the state is still the old one; then OnChanging, carrying the state the BitToggle is about to move to; and finally OnChange, once the new state is committed. The toggle below has all three wired to a log - flip it and watch the order:


No clicks yet.



OnChanging is the veto point: setting Cancel on its arguments leaves the BitToggle where it was, so a change can be refused instead of being reverted after the fact. It is awaited, so it can take its time - asking for confirmation, or checking with the server before letting the state through. While it is taking that time the BitToggle stops accepting clicks, so a second click cannot start a change that races the one still being decided; use Loading alongside it when the wait is long enough to be worth showing.



Cancelled attempts: 0



A BitToggle inside a clickable container fires that container's handler too. StopPropagation keeps the clicks to itself. Both toggles below sit in the same clickable box:


Container clicks: 0



Focus is reported as well: OnFocus and OnBlur fire as the switch gains and loses the focus, and OnFocusIn and OnFocusOut are their bubbling counterparts - the pair to reach for when the toggle sits inside a container that tracks whether the focus is anywhere within it. Tab into the toggle below and back out again:


Not focused yet.

Validation

<style>
    .validation-message {
        color: red;
    }
</style>

<EditForm Model="validationModel" OnValidSubmit="HandleValidSubmit" OnInvalidSubmit="HandleInvalidSubmit">
    <DataAnnotationsValidator />

    <BitToggle Label="Terms and conditions" Text="I agree." @bind-Value="validationModel.TermsAgreement" />
    <ValidationMessage For="@(() => validationModel.TermsAgreement)" />

    <BitButton ButtonType="BitButtonType.Submit">Submit</BitButton>
</EditForm>
@code {
    private BitToggleValidationModel validationModel = new();
    
    public class BitToggleValidationModel
    {
        [Range(typeof(bool), "true", "true", ErrorMessage = "You must agree to the terms and conditions.")]
        public bool TermsAgreement { get; set; }
    }
    
    private void HandleValidSubmit() { }
    private void HandleInvalidSubmit() { }
}
                    
Inside an EditForm, the BitToggle takes part in validation like any other input: bind it to a model property, let data annotations state the rule - here, that the terms must be agreed to - and a failed submit shows the message. While invalid, the BitToggle also switches to its error styling and reports aria-invalid on the switch, so the failure is both visible and announced right at the control. For a plain HTML post rather than an EditForm, Name names the hidden checkbox that carries the state into the form data - it submits true while the toggle is on and is left out of the post entirely while it is off, exactly as a native checkbox would.


Accessibility

<BitToggle Label="Focus me with Tab, flip me with Space" />
<BitToggle Label="Hover over my knob" Title="The native tooltip of the toggle" />


<BitButton OnClick="FocusTheToggle">Focus the toggle</BitButton>
<BitToggle @ref="toggleRef" Label="Programmatic focus target" />


<BitToggle AriaLabel="Dark mode" />
<BitToggle Label="Auto renew" AriaDescription="The subscription will be renewed one day before it expires." />


<div id="offline-mode-heading"><b>Offline mode</b></div>
<div id="offline-mode-hint">Keep a copy of the last synced data on this device.</div>

<BitToggle AriaLabelledby="offline-mode-heading" AriaDescribedby="offline-mode-hint" Text="Enabled" />


<BitToggle Label="Show advanced settings" AriaControls="advanced-settings-panel"
           @bind-Value="advancedSettingsVisible" />

<div id="advanced-settings-panel">
    @if (advancedSettingsVisible)
    {
        <BitMessage Color="BitColor.Info">The panel this toggle controls.</BitMessage>
    }
</div>


<BitToggle Text="Dark mode" />
<BitToggle Label="Notifications" OnText="Allowed" OffText="Blocked" />
@code {
    private BitToggle toggleRef = default!;
    private bool advancedSettingsVisible;
    
    private async Task FocusTheToggle()
    {
        await toggleRef.FocusAsync();
    }
}
                    
The BitToggle is a real focusable button carrying the switch role: Tab moves the focus to it and draws a focus ring, Space and Enter flip it, and screen readers announce it as a switch that is on or off. Its pointer target is never smaller than 24 by 24 CSS pixels, whatever size the track is drawn at, and the label and the state text are part of that target as well. AutoFocus puts the initial focus on it when the page renders, and Title fills the native tooltip shown when the pointer rests on the knob. Role is the escape hatch for the rare case where the switch semantics are wrong - setting it to checkbox makes the control announce itself as checked or unchecked instead of on or off, for a choice that only takes effect on a later submit.




The FocusAsync method moves the focus programmatically:




A BitToggle without a visible label needs an AriaLabel to have an accessible name, and AriaDescription adds a visually hidden description that screen readers read after the name - the announced-only counterpart of the visible Description.

The subscription will be renewed one day before it expires.



When the name of the switch is already written somewhere on the page - a section heading, a table column, the caption of the row it sits in - AriaLabelledby points at that element by its id instead of repeating its words inside the toggle. It outranks every other source of the name, including the toggle's own label and AriaLabel. Its counterpart AriaDescribedby does the same for an explanation already on the page, except that it is added to what the toggle already describes itself with - its state text and its AriaDescription - instead of replacing them.

Offline mode
Keep a copy of the last synced data on this device.




When flipping the switch governs another part of the page, AriaControls names that part by its id, so assistive technologies can tie the switch to what it acts on instead of leaving the two unrelated:





The name of a switch must not change along with its state, or it renames itself on every flip instead of naming itself. So the name comes from the label, and a state text that differs between the two states - OnText and OffText - is announced as a description after it rather than folded into it; the on/off state itself is already carried by the switch. Only a state text that says the same thing in both states, like a lone Text, can name a toggle that has no label of its own:

Description

<BitToggle Label="Auto renew"
           Description="The subscription is renewed one day before it expires." />


<div style="max-width:32rem">
    <BitToggle FullWidth Inline
               Label="Offline mode"
               Description="Keep a copy of the last synced data on this device." />

    <BitToggle FullWidth Inline
               Label="Usage statistics"
               Description="Send anonymous usage data to help us prioritize what to build next." />
</div>


<BitToggle Label="Beta features">
    <DescriptionTemplate>
        Turning this on opts you into features that are still changing.
        <BitLink Href="https://bitplatform.dev" Target="_blank">Learn more</BitLink>
    </DescriptionTemplate>
</BitToggle>
Description adds the second line of a settings row: the sentence that says what turning the switch on actually does, where the label only names it. It takes a line of its own under the whole BitToggle - in every layout, including the single-line ones - and screen readers announce it after the name of the switch, so the explanation is heard as well as read. In the single-line shapes the described BitToggle spans its container - the layout a settings row wants anyway - while stacked it keeps hugging its content. DescriptionTemplate puts arbitrary markup there instead of a plain string. Where the explanation should only be announced and never shown, use AriaDescription instead.

The subscription is renewed one day before it expires.



Inline and FullWidth, the usual shape of a settings list:

Keep a copy of the last synced data on this device.

Send anonymous usage data to help us prioritize what to build next.



DescriptionTemplate:

Turning this on opts you into features that are still changing. Learn more

Color

<BitToggle Color="BitColor.Primary" Label="Primary" Value />
<BitToggle Color="BitColor.Secondary" Label="Secondary" Value />
<BitToggle Color="BitColor.Tertiary" Label="Tertiary" Value />
<BitToggle Color="BitColor.Info" Label="Info" Value />
<BitToggle Color="BitColor.Success" Label="Success" Value />
<BitToggle Color="BitColor.Warning" Label="Warning" Value />
<BitToggle Color="BitColor.SevereWarning" Label="SevereWarning" Value />
<BitToggle Color="BitColor.Error" Label="Error" Value />

<div style="background:var(--bit-clr-fg-sec);color:var(--bit-clr-bg-sec);padding:1rem">
    <BitToggle Color="BitColor.PrimaryBackground" Label="PrimaryBackground" Value />
    <BitToggle Color="BitColor.SecondaryBackground" Label="SecondaryBackground" Value />
    <BitToggle Color="BitColor.TertiaryBackground" Label="TertiaryBackground" Value />
</div>

<BitToggle Color="BitColor.PrimaryForeground" Label="PrimaryForeground" Value />
<BitToggle Color="BitColor.SecondaryForeground" Label="SecondaryForeground" Value />
<BitToggle Color="BitColor.TertiaryForeground" Label="TertiaryForeground" Value />

<BitToggle Color="BitColor.PrimaryBorder" Label="PrimaryBorder" Value />
<BitToggle Color="BitColor.SecondaryBorder" Label="SecondaryBorder" Value />
<BitToggle Color="BitColor.TertiaryBorder" Label="TertiaryBorder" Value />


<BitToggle Color="BitColor.Success" Label="Success" />
<BitToggle Color="BitColor.Warning" Label="Warning" />
<BitToggle Color="BitColor.Error" Label="Error" />
Color picks the theme color the track fills with once the BitToggle is on, with Primary as the default; the off track stays neutral whichever color is picked, so it keeps reading as "off". The semantic colors - Success, Warning, Error and friends - tie the toggle to what switching it on means, while the Background, Foreground and Border families keep it legible on non-default surfaces like the inverted panel below.








Off:

External Icons

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.1/css/all.min.css" />

<BitToggle Label="Check / Xmark (string)" OnIcon="@("fa-solid fa-check")" OffIcon="@("fa-solid fa-xmark")" />

<BitToggle Label="Sun / Moon (BitIconInfo.Fa)" Color="BitColor.Warning"
           OnIcon="@BitIconInfo.Fa("solid sun")" OffIcon="@BitIconInfo.Fa("solid moon")" />

<BitToggle Label="Rocket (BitIconInfo.Css)" Color="BitColor.Error" OnIcon="@BitIconInfo.Css("fa-solid fa-rocket")" />


<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.min.css" />

<BitToggle Label="Check / X (string)" OnIcon="@("bi bi-check-lg")" OffIcon="@("bi bi-x-lg")" />

<BitToggle Label="Bell (BitIconInfo.Bi)" Color="BitColor.Success"
           OnIcon="@BitIconInfo.Bi("bell-fill")" OffIcon="@BitIconInfo.Bi("bell-slash")" />
The knob icons are not limited to the built-in icon font: OnIcon and OffIcon take a BitIconInfo - or a raw CSS class string - that can point at any icon library whose stylesheet is loaded, like FontAwesome or Bootstrap Icons below. Use BitIconInfo.Fa(), BitIconInfo.Bi() or BitIconInfo.Css() to build one.


FontAwesome:








Bootstrap Icons:



Size

<BitToggle Size="BitSize.Small" Label="Off" />
<BitToggle Size="BitSize.Small" Label="On" Value />
<BitToggle Size="BitSize.Small" Label="With icons" Value OnIconName="@BitIconName.Accept" OffIconName="@BitIconName.Cancel" />

<BitToggle Size="BitSize.Medium" Label="Off" />
<BitToggle Size="BitSize.Medium" Label="On" Value />
<BitToggle Size="BitSize.Medium" Label="With icons" Value OnIconName="@BitIconName.Accept" OffIconName="@BitIconName.Cancel" />

<BitToggle Size="BitSize.Large" Label="Off" />
<BitToggle Size="BitSize.Large" Label="On" Value />
<BitToggle Size="BitSize.Large" Label="With icons" Value OnIconName="@BitIconName.Accept" OffIconName="@BitIconName.Cancel" />
Size scales the track, the knob, the label and the state text together: Small for dense lists and table rows, Medium (the default) for forms, and Large where the BitToggle is a primary control or aimed at touch. A toggle carrying knob icons steps every size up to a roomier track that fits them, keeping the three sizes in proportion.

Small:




Medium:




Large:

Style & Class

<style>
    .custom-class {
        padding: 0.5rem;
        border-radius: 0.25rem;
        background-color: #d3d3d347;
        border: 1px solid dodgerblue;
    }

    .custom-thumb {
        background: #fff;
    }

    .custom-button {
        padding: 0;
        width: 52px;
        height: 22px;
        border: none;
        background: #ccc;
        border-radius: 11px;
        --bit-tgl-pad: -4px;
        --bit-tgl-thb-size: 30px;
    }

    .custom-check .custom-thumb {
        background: #ff6868;
    }

    .custom-check .custom-button {
        background: #ffcece;
    }

    .custom-check .custom-button:hover .custom-thumb {
        background: #ff6868;
    }

    .custom-on-content {
        font-weight: 700;
        letter-spacing: 0.1em;
    }

    .custom-off-content {
        opacity: 0.75;
        font-style: italic;
    }
</style>


<BitToggle Label="Styled toggle" Style="background-color:#ff6a00b3;padding:0.5rem;border-radius:0.25rem" />

<BitToggle Label="Classed toggle" Class="custom-class" />


<BitToggle Label="Styles"
           Styles="@(new() { Root = "--toggle-background: lightgray;", Checked = "--toggle-background: #2ecc71;",
                             Thumb = "background: whitesmoke;",
                             Button = "background: var(--toggle-background); border: none; border-radius: 60px; padding: 0; height: 30px; width: 50px; --bit-tgl-pad: 2px; --bit-tgl-thb-size: 26px;" } )" />

<BitToggle Label="Classes"
           Classes="@(new() { Thumb = "custom-thumb",
                              Button = "custom-button",
                              Checked = "custom-check" } )" />

<BitToggle Label="Each side of the track content"
           Classes="@(new() { OnContent = "custom-on-content",
                              OffContent = "custom-off-content" } )">
    <OnContent>ON</OnContent>
    <OffContent>OFF</OffContent>
</BitToggle>
The BitToggle can be restyled from the outside at three levels of reach. Style and Class apply to the root element, while Styles and Classes reach every part of it by name - the root, the label, the description, the container, the button (which is the track), the track content and each of its two sides on its own, the thumb, its icon, the spinner and the state text - plus a Checked slot that is applied only while the toggle is on, which is what lets the two states be painted differently without a single line of state-tracking code.


Component's style & class:





Styles & Classes:



RTL

<BitToggle Label="این یک تاگل است" Dir="BitDir.Rtl" OnText="روشن" OffText="خاموش" />

<BitToggle Label="این یک تاگل خطی است" Dir="BitDir.Rtl" Inline />

<BitToggle Label="این یک تاگل خطی برعکس است" Dir="BitDir.Rtl" Reversed Inline />

<BitToggle Label="این یک تاگل با محتوا است" Dir="BitDir.Rtl" OnIconName="@BitIconName.Accept" OffIconName="@BitIconName.Cancel">
    <OnContent>روشن</OnContent>
    <OffContent>خاموش</OffContent>
</BitToggle>
Set Dir to BitDir.Rtl to render the BitToggle right-to-left. The knob then travels the other way - resting on the right when off and sliding to the left when on - and every side-aware layout follows it, so the track content, the label position and the reversed layouts all mirror without any extra markup.










API

BitToggle parameters

Name Type Default value Description
AriaControls string? null The id of the element the toggle controls, rendered as aria-controls on the switch.
AriaDescription string? null Detailed description of the toggle for the benefit of screen readers, rendered as a visually hidden element that the switch points to via aria-describedby.
AriaDescribedby string? null The id of an existing element that describes the toggle, added to the aria-describedby of the switch alongside its state text and its AriaDescription rather than replacing them.
AriaLabelledby string? null The id of an existing element that labels the toggle, rendered as aria-labelledby on the switch. Takes precedence over the label of the toggle and over AriaLabel.
AutoFocus bool false If true, the toggle automatically receives focus when the page renders (rendered as the autofocus attribute).
AutoLoading bool false Turns the toggle busy on its own for as long as the awaited OnClick, OnChanging and OnChange callbacks behind a change are still running, without a loading flag having to be tracked outside the component.
Classes BitToggleClassStyles? null Custom CSS classes for different parts of the toggle.
Color BitColor? null The general color of the toggle, applied to the track of the checked state.
Description string? null A visible explanation of what the toggle switches, rendered on a line of its own under it and announced after the name of the switch through aria-describedby.
DescriptionTemplate RenderFragment? null Custom description of the toggle, replacing Description with arbitrary markup.
FullWidth bool false Renders the toggle in full width of its container while putting space between the label and the knob.
Inline bool false Renders the label and the knob in a single line together.
Label string? null Label of the toggle.
LabelPosition BitLabelPosition? null The position of the label in regards to the knob of the toggle. Takes precedence over Inline and Reversed when set.
LabelTemplate RenderFragment? null Custom label of the toggle.
Loading bool false Renders a spinner in place of the knob's icon and suspends the toggle until the pending work behind the change is done.
OffContent RenderFragment? null Content rendered inside the track of the toggle while it is OFF, next to the knob.
OffIcon BitIconInfo? null The icon rendered inside the knob while the toggle is OFF, using custom CSS classes for external icon libraries. Takes precedence over OffIconName when both are set.
OffIconName string? null The name of the built-in icon rendered inside the knob while the toggle is OFF.
OffText string? null Text to display when toggle is OFF.
OnBlur EventCallback<FocusEventArgs> Callback for when the toggle loses focus.
OnChanging EventCallback<BitToggleChangeArgs> Callback invoked before the state of the toggle changes, letting the change be cancelled by setting Cancel on the provided arguments.
OnClick EventCallback<MouseEventArgs> Callback for when the toggle is clicked, invoked before the state changes.
OnContent RenderFragment? null Content rendered inside the track of the toggle while it is ON, next to the knob.
OnFocus EventCallback<FocusEventArgs> Callback for when the toggle receives focus.
OnFocusIn EventCallback<FocusEventArgs> Callback for when focus moves into the toggle.
OnFocusOut EventCallback<FocusEventArgs> Callback for when focus moves out of the toggle.
OnIcon BitIconInfo? null The icon rendered inside the knob while the toggle is ON, using custom CSS classes for external icon libraries. Takes precedence over OnIconName when both are set.
OnIconName string? null The name of the built-in icon rendered inside the knob while the toggle is ON.
OnText string? null Text to display when toggle is ON.
Reversed bool false Reverses the positions of the label and input of the toggle.
Role string? switch Denotes role of the toggle, default is switch.
Size BitSize? null The size of the toggle.
StopPropagation bool false If true, stops the click event from bubbling up to the parent elements.
Styles BitToggleClassStyles? null Custom CSS styles for different parts of the toggle.
Text string? null The default text used when the On or Off texts are null.
Title string? null The native tooltip of the knob of the toggle, shown on hover.

BitToggle public members

Name Type Default value Description
InputElement ElementReference The ElementReference of the switch button of the BitToggle - the element that holds the tab stop, not the hidden checkbox that carries the value into a form.
FocusAsync (bool preventScroll = false) => ValueTask Gives focus to the switch button of the BitToggle. Pass true to keep the browser from scrolling the toggle into view along the way.
ToggleAsync () => Task Flips the state of the BitToggle from code, as a click would: OnChanging still gets to cancel the change and OnChange still reports it. Unlike a click it is not blocked by the read-only or loading states, which only close the toggle to the user; a disabled toggle changes through neither.
ToggleAsync (bool value) => Task Moves the BitToggle to a specific state from code, doing nothing when it is already in it. Otherwise identical to the parameterless overload.

BitInputBase parameters

Name Type Default value Description
DefaultValue TValue? null The default value of the input to be used in uncontrolled mode (i.e. when the Value is not bound), typically used alongside the OnChange callback.
DisplayName string? null Gets or sets the display name for this field.
InputHtmlAttributes IReadOnlyDictionary<string, object>? null Gets or sets a collection of additional attributes that will be applied to the created element.
Name string? null Gets or sets the name of the element. Allows access by name from the associated form.
NoValidate bool false Disables the validation of the input.
OnChange EventCallback<TValue?> Callback for when the input value changes.
ReadOnly bool false Makes the input read-only.
Required bool false Makes the input required.
Value TValue? null Gets or sets the value of the input. This should be used with two-way binding.

BitInputBase public members

Name Type Default value Description
InputElement ElementReference The ElementReference of the input element.
FocusAsync() () => ValueTask Gives focus to the input element.
FocusAsync(bool preventScroll) (bool preventScroll) => ValueTask Gives focus to the input element.

BitComponentBase parameters

Name Type Default value Description
AriaLabel string? null Gets or sets the accessible label for the component, used by assistive technologies.
Class string? null Gets or sets the CSS class name(s) to apply to the rendered element.
Dir BitDir? null Gets or sets the text directionality for the component's content.
ForceAnimation bool false Gets or sets a value indicating whether the component's animations play at their full duration even when reduced motion is requested.
HtmlAttributes Dictionary<string, object> new Dictionary<string, object>() Captures additional HTML attributes to be applied to the rendered element, in addition to the component's parameters.
Id string? null Gets or sets the unique identifier for the component's root element.
IsEnabled bool true Gets or sets a value indicating whether the component is enabled and can respond to user interaction.
Style string? null Gets or sets the CSS style string to apply to the rendered element.
TabIndex string? null Gets or sets the tab order index for the component when navigating with the keyboard.
Visibility BitVisibility BitVisibility.Visible Gets or sets the visibility state (visible, hidden, or collapsed) of the component.

BitComponentBase public members

Name Type Default value Description
UniqueId Guid Guid.NewGuid() Gets the readonly unique identifier for the component's root element, assigned when the component instance is constructed.
RootElement ElementReference Gets the reference to the root HTML element associated with this component.

BitToggleClassStyles properties

Name Type Default value Description
Root string? null Custom CSS classes/styles for the root element of the BitToggle.
Label string? null Custom CSS classes/styles for the label of the BitToggle.
Description string? null Custom CSS classes/styles for the description of the BitToggle.
Container string? null Custom CSS classes/styles for the container of the BitToggle.
Button string? null Custom CSS classes/styles for the button of the BitToggle.
Checked string? null Custom CSS classes/styles for the checked state of the BitToggle.
Content string? null Custom CSS classes/styles for the content rendered inside the track of the BitToggle.
OnContent string? null Custom CSS classes/styles for the ON side of the content rendered inside the track of the BitToggle.
OffContent string? null Custom CSS classes/styles for the OFF side of the content rendered inside the track of the BitToggle.
Thumb string? null Custom CSS classes/styles for the thumb of the BitToggle.
Icon string? null Custom CSS classes/styles for the icon rendered inside the thumb of the BitToggle.
Spinner string? null Custom CSS classes/styles for the loading spinner of the BitToggle.
Text string? null Custom CSS classes/styles for the text of the BitToggle.

BitToggleChangeArgs properties

Name Type Default value Description
Value bool false The state the toggle is about to move to (read-only).
Cancel bool false Set to true to cancel the change and keep the current state of the toggle.

BitColor enum

Name Value Description
Primary 0 Primary general color.
Secondary 1 Secondary general color.
Tertiary 2 Tertiary general color.
Info 3 Info general color.
Success 4 Success general color.
Warning 5 Warning general color.
SevereWarning 6 SevereWarning general color.
Error 7 Error general color.
PrimaryBackground 8 Primary background color.
SecondaryBackground 9 Secondary background color.
TertiaryBackground 10 Tertiary background color.
PrimaryForeground 11 Primary foreground color.
SecondaryForeground 12 Secondary foreground color.
TertiaryForeground 13 Tertiary foreground color.
PrimaryBorder 14 Primary border color.
SecondaryBorder 15 Secondary border color.
TertiaryBorder 16 Tertiary border color.

BitLabelPosition enum

Name Value Description
Top 0 The label shows on the top of the toggle.
End 1 The label shows on the end of the toggle.
Bottom 2 The label shows on the bottom of the toggle.
Start 3 The label shows on the start of the toggle.

BitSize enum

Name Value Description
Small 0 The small size toggle.
Medium 1 The medium size toggle.
Large 2 The large size toggle.

BitVisibility enum

Name Value Description
Visible 0 The content of the component is visible.
Hidden 1 The content of the component is hidden, but the space it takes on the page remains (visibility:hidden).
Collapsed 2 The component is hidden (display:none).

BitDir enum

Name Value Description
Ltr 0 Ltr (left to right) is to be used for languages that are written from the left to the right (like English).
Rtl 1 Rtl (right to left) is to be used for languages that are written from the right to the left (like Arabic).
Auto 2 Auto lets the user agent decide. It uses a basic algorithm as it parses the characters inside the element until it finds a character with a strong directionality, then applies that directionality to the whole element.

Feedback

You can give us your feedback through our GitHub repo by filing a new Issue or starting a new Discussion.


Or you can review / edit this page on GitHub.


Or you can review / edit this component on GitHub.