Switch
An accessible on/off toggle styled entirely with Tailwind utilities.
Basic Switch (Uncontrolled)
Renders a native <button> with role="switch". The track and thumb are styled with the custom data-state-checked: variant.
<BitBhSwitch aria-label="Wi-Fi" DefaultChecked="false"
class="relative inline-block w-10 h-5 rounded-full bg-zinc-300 cursor-pointer transition-colors outline-none focus-visible:ring-2 focus-visible:ring-blue-600 focus-visible:ring-offset-2 data-state-checked:bg-blue-600 data-disabled:opacity-50 data-disabled:cursor-not-allowed">
<BitBhSwitchThumb class="absolute top-1/2 left-0.5 h-4 w-4 -translate-y-1/2 rounded-full bg-white shadow transition-[left] data-state-checked:left-[calc(100%-1.125rem)]" />
</BitBhSwitch>
<BitBhSwitch aria-label="Bluetooth" DefaultChecked="true"
class="relative inline-block w-10 h-5 rounded-full bg-zinc-300 cursor-pointer transition-colors outline-none focus-visible:ring-2 focus-visible:ring-blue-600 focus-visible:ring-offset-2 data-state-checked:bg-blue-600 data-disabled:opacity-50 data-disabled:cursor-not-allowed">
<BitBhSwitchThumb class="absolute top-1/2 left-0.5 h-4 w-4 -translate-y-1/2 rounded-full bg-white shadow transition-[left] data-state-checked:left-[calc(100%-1.125rem)]" />
</BitBhSwitch>Controlled
Drive the state externally with Checked + OnCheckedChange.
Notifications: on
<div class="flex items-center gap-4">
<BitBhSwitch aria-label="Notifications" Checked="@notificationsOn" OnCheckedChange="v => notificationsOn = v"
class="relative inline-block w-10 h-5 rounded-full bg-zinc-300 cursor-pointer transition-colors outline-none focus-visible:ring-2 focus-visible:ring-blue-600 focus-visible:ring-offset-2 data-state-checked:bg-blue-600 data-disabled:opacity-50 data-disabled:cursor-not-allowed">
<BitBhSwitchThumb class="absolute top-1/2 left-0.5 h-4 w-4 -translate-y-1/2 rounded-full bg-white shadow transition-[left] data-state-checked:left-[calc(100%-1.125rem)]" />
</BitBhSwitch>
<span class="text-sm text-zinc-500">
Notifications: <strong class="text-zinc-900">@(notificationsOn ? "on" : "off")</strong>
</span>
<BitBhButton OnClick="() => notificationsOn = !notificationsOn"
class="inline-flex items-center gap-2 rounded-lg border border-zinc-200 bg-white px-3 py-1.5 text-sm font-medium text-zinc-900 cursor-pointer hover:bg-zinc-100">
Toggle from outside
</BitBhButton>
</div>
@code {
private bool notificationsOn = true;
}Disabled
data-disabled: dims the track and disables interaction.
<BitBhSwitch aria-label="Airplane mode" DefaultChecked="false" Disabled="true"
class="relative inline-block w-10 h-5 rounded-full bg-zinc-300 cursor-pointer transition-colors outline-none focus-visible:ring-2 focus-visible:ring-blue-600 focus-visible:ring-offset-2 data-state-checked:bg-blue-600 data-disabled:opacity-50 data-disabled:cursor-not-allowed">
<BitBhSwitchThumb class="absolute top-1/2 left-0.5 h-4 w-4 -translate-y-1/2 rounded-full bg-white shadow transition-[left] data-state-checked:left-[calc(100%-1.125rem)]" />
</BitBhSwitch>
<BitBhSwitch aria-label="Location services" DefaultChecked="true" Disabled="true"
class="relative inline-block w-10 h-5 rounded-full bg-zinc-300 cursor-pointer transition-colors outline-none focus-visible:ring-2 focus-visible:ring-blue-600 focus-visible:ring-offset-2 data-state-checked:bg-blue-600 data-disabled:opacity-50 data-disabled:cursor-not-allowed">
<BitBhSwitchThumb class="absolute top-1/2 left-0.5 h-4 w-4 -translate-y-1/2 rounded-full bg-white shadow transition-[left] data-state-checked:left-[calc(100%-1.125rem)]" />
</BitBhSwitch>With label
Wrap in a <label> to make the text clickable.
<label class="inline-flex items-center gap-2.5 cursor-pointer text-sm select-none">
<BitBhSwitch DefaultChecked="true"
class="relative inline-block w-10 h-5 rounded-full bg-zinc-300 cursor-pointer transition-colors outline-none focus-visible:ring-2 focus-visible:ring-blue-600 focus-visible:ring-offset-2 data-state-checked:bg-blue-600 data-disabled:opacity-50 data-disabled:cursor-not-allowed">
<BitBhSwitchThumb class="absolute top-1/2 left-0.5 h-4 w-4 -translate-y-1/2 rounded-full bg-white shadow transition-[left] data-state-checked:left-[calc(100%-1.125rem)]" />
</BitBhSwitch>
<span>Email me about updates</span>
</label>As a non-native element
As="div" renders a div while keeping ARIA, tabindex, and keyboard handling intact.
<BitBhSwitch aria-label="Dark mode" As="div" DefaultChecked="false"
class="relative inline-block w-10 h-5 rounded-full bg-zinc-300 cursor-pointer transition-colors outline-none focus-visible:ring-2 focus-visible:ring-blue-600 focus-visible:ring-offset-2 data-state-checked:bg-blue-600 data-disabled:opacity-50 data-disabled:cursor-not-allowed">
<BitBhSwitchThumb class="absolute top-1/2 left-0.5 h-4 w-4 -translate-y-1/2 rounded-full bg-white shadow transition-[left] data-state-checked:left-[calc(100%-1.125rem)]" />
</BitBhSwitch>Form Submission
Set Name to render an adjacent hidden input.
<form @onsubmit="HandleFormSubmit" @onsubmit:preventDefault="true"
class="flex flex-wrap items-center gap-4">
<label class="inline-flex items-center gap-2.5 cursor-pointer text-sm select-none">
<BitBhSwitch Name="newsletter" Value="yes" DefaultChecked="false"
class="relative inline-block w-10 h-5 rounded-full bg-zinc-300 cursor-pointer transition-colors outline-none focus-visible:ring-2 focus-visible:ring-blue-600 focus-visible:ring-offset-2 data-state-checked:bg-blue-600 data-disabled:opacity-50 data-disabled:cursor-not-allowed">
<BitBhSwitchThumb class="absolute top-1/2 left-0.5 h-4 w-4 -translate-y-1/2 rounded-full bg-white shadow transition-[left] data-state-checked:left-[calc(100%-1.125rem)]" />
</BitBhSwitch>
<span>Subscribe to newsletter</span>
</label>
<button type="submit"
class="inline-flex items-center gap-2 rounded-lg border border-blue-600 bg-blue-600 px-3 py-1.5 text-sm font-medium text-white cursor-pointer hover:bg-blue-700">
Submit
</button>
@if (lastSubmittedValue is not null)
{
<span class="text-sm text-zinc-500">Posted value: <code>@lastSubmittedValue</code></span>
}
</form>
@code {
private string? lastSubmittedValue;
private void HandleFormSubmit() =>
lastSubmittedValue = "(submitted — check the network tab in a real form)";
}