Checkbox
A control that allows the user to toggle between checked and not checked.
Demo
Indeterminate State
The indeterminate state is useful for "Select All" patterns where some but not all items are selected. Click the parent checkbox to toggle all children, or click individual items to see the parent update automatically.
Checkbox Group
Use CheckboxGroup to manage multiple related checkboxes. The selected values are displayed below in real-time.
technologyDisabled State
Disabled checkboxes prevent user interaction and display with reduced opacity. Try clicking the disabled checkboxes below.
Controlled Mode
Control the checkbox state programmatically using external buttons. This pattern is useful for complex UIs requiring external state management.
Unchecked
Custom Styling Example
Checkboxes are completely headless - style them however you want using data attributes and Tailwind utility classes.
Features
- Three states: checked, unchecked, and indeterminate
- Keyboard navigation (Space to toggle)
- Controlled and uncontrolled modes
- Support for HTML forms (hidden input)
- Blazor EditForm integration with validation
- Grouping capabilities via CheckboxGroup
- WCAG compliant with proper ARIA attributes
Installation
dotnet add package SummitUIAnatomy
Import the components and structure them as follows:
<SmCheckboxRoot>
<SmCheckboxIndicator>
<span>✓</span>
</SmCheckboxIndicator>
</SmCheckboxRoot>Sub-components
CheckboxRoot
The root checkbox component containing the button element.
CheckboxIndicator
Renders when the checkbox is in a checked or indeterminate state.
CheckboxGroup
A wrapper for managing a group of checkboxes.
CheckboxGroupLabel
Accessible label for the checkbox group.
API Reference
CheckboxRoot
| Property | Type | Default | Description |
|---|---|---|---|
| Checked | bool? | null | Controlled checked state |
| DefaultChecked | bool | false | Default checked state for uncontrolled mode |
| CheckedChanged | EventCallback<bool> | - | Callback when checked state changes |
| CheckedExpression | Expression<Func<bool>>? | null | Expression for EditForm binding and validation |
| Indeterminate | bool | false | Controlled indeterminate state |
| IndeterminateChanged | EventCallback<bool> | - | Callback when indeterminate state changes |
| Disabled | bool | false | Prevents interaction with the checkbox |
| Required | bool | false | Indicates checkbox must be checked for form submission |
| Name | string? | null | Form field name for hidden input |
| Value | string? | "on" | Value submitted with form data |
| AriaLabel | string? | null | Accessible label for the checkbox when not wrapped in a label element |
CheckboxIndicator
| Property | Type | Default | Description |
|---|---|---|---|
| ForceMount | bool | false | Always render in DOM (useful for CSS animations) |
| ChildContent | RenderFragment? | - | Content to render when checked or indeterminate |
CheckboxGroup
| Property | Type | Default | Description |
|---|---|---|---|
| Values | IReadOnlyList<string>? | null | Controlled values of checked items |
| DefaultValues | IReadOnlyList<string>? | null | Default values for uncontrolled mode |
| ValuesChanged | EventCallback<IReadOnlyList<string>> | - | Callback when values change |
| ValuesExpression | Expression<Func<IReadOnlyList<string>?>>? | null | Expression for EditForm binding and validation |
| Disabled | bool | false | Disable entire group |
| Name | string? | null | Form name for hidden inputs |
CheckboxGroupLabel
| Property | Type | Default | Description |
|---|---|---|---|
| ChildContent | RenderFragment? | - | Label content for the checkbox group |
Examples
Basic Usage
<SmCheckboxRoot DefaultChecked="true">
<SmCheckboxIndicator>
<span>✓</span>
</SmCheckboxIndicator>
</SmCheckboxRoot>With Label
Wrap the checkbox in a label for better accessibility and click handling.
<label style="display: flex; gap: 0.5rem; align-items: center;">
<SmCheckboxRoot id="c1">
<SmCheckboxIndicator>
<span>✓</span>
</SmCheckboxIndicator>
</SmCheckboxRoot>
Accept terms and conditions
</label>Controlled Mode
Control the checked state externally.
@code {
private bool isChecked = true;
}
<SmCheckboxRoot @bind-Checked="isChecked">
<SmCheckboxIndicator>
<span>✓</span>
</SmCheckboxIndicator>
</SmCheckboxRoot>Indeterminate State
Use the indeterminate state for parent checkboxes with partially selected children.
@code {
private bool isIndeterminate = true;
}
<SmCheckboxRoot @bind-Indeterminate="isIndeterminate">
<SmCheckboxIndicator>
@if (isIndeterminate)
{
<span>-</span>
}
else
{
<span>✓</span>
}
</SmCheckboxIndicator>
</SmCheckboxRoot>Checkbox Group
Manage multiple checkboxes as a group.
@code {
private IReadOnlyList<string> values = new[] { "apple" };
}
<SmCheckboxGroup @bind-Values="values">
<SmCheckboxGroupLabel>Favorite Fruits</SmCheckboxGroupLabel>
<label>
<SmCheckboxRoot Value="apple">
<SmCheckboxIndicator>✓</SmCheckboxIndicator>
</SmCheckboxRoot>
Apple
</label>
<label>
<SmCheckboxRoot Value="banana">
<SmCheckboxIndicator>✓</SmCheckboxIndicator>
</SmCheckboxRoot>
Banana
</label>
</SmCheckboxGroup>EditForm Integration (Single Checkbox)
Use with Blazor EditForm for model binding and validation support.
@using System.ComponentModel.DataAnnotations
<EditForm Model="model" OnValidSubmit="HandleSubmit">
<DataAnnotationsValidator />
<label style="display: flex; gap: 0.5rem; align-items: center;">
<SmCheckboxRoot @bind-Checked="model.AcceptTerms">
<SmCheckboxIndicator>✓</SmCheckboxIndicator>
</SmCheckboxRoot>
Accept Terms and Conditions
</label>
<ValidationMessage For="@(() => model.AcceptTerms)" />
<button type="submit">Submit</button>
</EditForm>
@code {
private FormModel model = new();
public class FormModel
{
[Range(typeof(bool), "true", "true",
ErrorMessage = "You must accept the terms")]
public bool AcceptTerms { get; set; }
}
private void HandleSubmit() { /* handle submission */ }
}EditForm Integration (Checkbox Group)
Use CheckboxGroup with EditForm for multi-select validation.
@using System.ComponentModel.DataAnnotations
<EditForm Model="model" OnValidSubmit="HandleSubmit">
<DataAnnotationsValidator />
<SmCheckboxGroup @bind-Values="model.Interests">
<SmCheckboxGroupLabel>Select your interests</SmCheckboxGroupLabel>
<label>
<SmCheckboxRoot Value="technology">
<SmCheckboxIndicator>✓</SmCheckboxIndicator>
</SmCheckboxRoot>
Technology
</label>
<label>
<SmCheckboxRoot Value="sports">
<SmCheckboxIndicator>✓</SmCheckboxIndicator>
</SmCheckboxRoot>
Sports
</label>
<label>
<SmCheckboxRoot Value="music">
<SmCheckboxIndicator>✓</SmCheckboxIndicator>
</SmCheckboxRoot>
Music
</label>
</SmCheckboxGroup>
<ValidationMessage For="@(() => model.Interests)" />
<button type="submit">Submit</button>
</EditForm>
@code {
private FormModel model = new();
public class FormModel
{
[MinLength(1, ErrorMessage = "Select at least one interest")]
public IReadOnlyList<string>? Interests { get; set; } = [];
}
private void HandleSubmit() { /* handle submission */ }
}Styling
Data Attributes
Use these data attributes to style checkboxes based on their state.
| Attribute | Values | Description |
|---|---|---|
| data-state | "checked" | "unchecked" | "indeterminate" | Current state of the checkbox |
| data-disabled | Present when disabled | Indicates disabled state |
Tailwind CSS Examples
Style checkboxes using Tailwind utility classes and data attribute selectors.
Size Variants
<!-- Small (16px) -->
<SmCheckboxRoot class="w-4 h-4 flex items-center justify-center bg-transparent border-2 border-su-border rounded cursor-pointer data-[state=checked]:bg-su-primary data-[state=checked]:border-su-primary">
<SmCheckboxIndicator class="text-su-primary-foreground">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3">
<path d="M20 6 9 17l-5-5"/>
</svg>
</SmCheckboxIndicator>
</SmCheckboxRoot>
<!-- Medium (20px - default) -->
<SmCheckboxRoot class="w-5 h-5 flex items-center justify-center bg-transparent border-2 border-su-border rounded cursor-pointer data-[state=checked]:bg-su-primary data-[state=checked]:border-su-primary">
<SmCheckboxIndicator class="text-su-primary-foreground">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3">
<path d="M20 6 9 17l-5-5"/>
</svg>
</SmCheckboxIndicator>
</SmCheckboxRoot>
<!-- Large (24px) -->
<SmCheckboxRoot class="w-6 h-6 flex items-center justify-center bg-transparent border-2 border-su-border rounded cursor-pointer data-[state=checked]:bg-su-primary data-[state=checked]:border-su-primary">
<SmCheckboxIndicator class="text-su-primary-foreground">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3">
<path d="M20 6 9 17l-5-5"/>
</svg>
</SmCheckboxIndicator>
</SmCheckboxRoot>Color Variants
<!-- Primary (default) -->
<SmCheckboxRoot class="w-5 h-5 flex items-center justify-center bg-transparent border-2 border-su-border rounded cursor-pointer data-[state=checked]:bg-su-primary data-[state=checked]:border-su-primary">
<SmCheckboxIndicator class="text-su-primary-foreground">✓</SmCheckboxIndicator>
</SmCheckboxRoot>
<!-- Success (green) -->
<SmCheckboxRoot class="w-5 h-5 flex items-center justify-center bg-transparent border-2 border-green-500 rounded cursor-pointer data-[state=checked]:bg-green-500 data-[state=checked]:border-green-500">
<SmCheckboxIndicator class="text-white">✓</SmCheckboxIndicator>
</SmCheckboxRoot>
<!-- Warning (yellow) -->
<SmCheckboxRoot class="w-5 h-5 flex items-center justify-center bg-transparent border-2 border-yellow-500 rounded cursor-pointer data-[state=checked]:bg-yellow-500 data-[state=checked]:border-yellow-500">
<SmCheckboxIndicator class="text-white">✓</SmCheckboxIndicator>
</SmCheckboxRoot>
<!-- Danger (red) -->
<SmCheckboxRoot class="w-5 h-5 flex items-center justify-center bg-transparent border-2 border-red-500 rounded cursor-pointer data-[state=checked]:bg-red-500 data-[state=checked]:border-red-500">
<SmCheckboxIndicator class="text-white">✓</SmCheckboxIndicator>
</SmCheckboxRoot>Interactive States
<!-- With focus ring and hover effects -->
<SmCheckboxRoot class="w-5 h-5 flex items-center justify-center bg-transparent border-2 border-su-border rounded cursor-pointer transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-su-ring focus-visible:ring-offset-2 hover:border-su-primary hover:scale-105 data-[state=checked]:bg-su-primary data-[state=checked]:border-su-primary data-[disabled]:opacity-50 data-[disabled]:cursor-not-allowed">
<SmCheckboxIndicator class="text-su-primary-foreground">✓</SmCheckboxIndicator>
</SmCheckboxRoot>
<!-- With shadow on hover -->
<SmCheckboxRoot class="w-5 h-5 flex items-center justify-center bg-transparent border-2 border-su-border rounded cursor-pointer transition-all hover:shadow-lg hover:border-su-primary data-[state=checked]:bg-su-primary data-[state=checked]:border-su-primary data-[state=checked]:shadow-md">
<SmCheckboxIndicator class="text-su-primary-foreground">✓</SmCheckboxIndicator>
</SmCheckboxRoot>
<!-- Disabled state -->
<SmCheckboxRoot Disabled="true" class="w-5 h-5 flex items-center justify-center bg-transparent border-2 border-su-border rounded cursor-not-allowed opacity-50 data-[state=checked]:bg-su-primary data-[state=checked]:border-su-primary">
<SmCheckboxIndicator class="text-su-primary-foreground">✓</SmCheckboxIndicator>
</SmCheckboxRoot>Custom Shapes and Effects
<!-- Circular checkbox -->
<SmCheckboxRoot class="w-5 h-5 flex items-center justify-center bg-transparent border-2 border-su-border rounded-full cursor-pointer transition-all hover:border-su-primary data-[state=checked]:bg-su-primary data-[state=checked]:border-su-primary">
<SmCheckboxIndicator class="text-su-primary-foreground">✓</SmCheckboxIndicator>
</SmCheckboxRoot>
<!-- With gradient background -->
<SmCheckboxRoot class="w-5 h-5 flex items-center justify-center bg-transparent border-2 border-su-border rounded cursor-pointer transition-all data-[state=checked]:bg-gradient-to-br data-[state=checked]:from-blue-500 data-[state=checked]:to-purple-600 data-[state=checked]:border-transparent">
<SmCheckboxIndicator class="text-white">✓</SmCheckboxIndicator>
</SmCheckboxRoot>
<!-- With rotation animation -->
<SmCheckboxRoot class="w-5 h-5 flex items-center justify-center bg-transparent border-2 border-su-border rounded cursor-pointer transition-all duration-300 hover:rotate-6 data-[state=checked]:bg-su-primary data-[state=checked]:border-su-primary data-[state=checked]:rotate-0">
<SmCheckboxIndicator class="text-su-primary-foreground animate-in zoom-in-50 duration-200">✓</SmCheckboxIndicator>
</SmCheckboxRoot>
<!-- With shadow effects -->
<SmCheckboxRoot class="w-5 h-5 flex items-center justify-center bg-transparent border-2 border-su-border rounded cursor-pointer transition-all shadow-sm hover:shadow-md data-[state=checked]:bg-su-primary data-[state=checked]:border-su-primary data-[state=checked]:shadow-lg">
<SmCheckboxIndicator class="text-su-primary-foreground">✓</SmCheckboxIndicator>
</SmCheckboxRoot>CSS Examples
Alternative styling approaches using vanilla CSS with data attribute selectors.
Basic Styling
/* Checkbox styles */
.checkbox {
width: 1.25rem;
height: 1.25rem;
display: flex;
align-items: center;
justify-content: center;
background: transparent;
border: 2px solid #ccc;
border-radius: 4px;
cursor: pointer;
}
.checkbox:hover {
border-color: #666;
}
.checkbox[data-state="checked"],
.checkbox[data-state="indeterminate"] {
background: #0066cc;
border-color: #0066cc;
}
.checkbox[data-disabled] {
opacity: 0.5;
cursor: not-allowed;
}
/* Indicator styles */
.checkbox-indicator {
color: white;
}Animated Checkbox
/* Animated checkbox with smooth transitions */
.animated-checkbox {
width: 1.25rem;
height: 1.25rem;
display: flex;
align-items: center;
justify-content: center;
background: transparent;
border: 2px solid hsl(var(--border));
border-radius: 0.25rem;
cursor: pointer;
transition: all 300ms cubic-bezier(0.4, 0, 0.2, 1);
}
.animated-checkbox:hover {
border-color: hsl(var(--primary));
transform: scale(1.05);
}
.animated-checkbox[data-state="checked"] {
background: hsl(var(--primary));
border-color: hsl(var(--primary));
animation: checkbox-pop 300ms ease-out;
}
.animated-checkbox-indicator {
color: hsl(var(--primary-foreground));
animation: checkmark-appear 200ms ease-out;
}
@keyframes checkbox-pop {
0% {
transform: scale(1);
}
50% {
transform: scale(1.1);
}
100% {
transform: scale(1);
}
}
@keyframes checkmark-appear {
0% {
opacity: 0;
transform: scale(0.5);
}
100% {
opacity: 1;
transform: scale(1);
}
}Custom Indicator with SVG
/* Checkbox with custom checkmark styles */
.custom-checkbox {
width: 1.25rem;
height: 1.25rem;
display: flex;
align-items: center;
justify-content: center;
background: transparent;
border: 2px solid hsl(var(--border));
border-radius: 0.25rem;
cursor: pointer;
position: relative;
}
.custom-checkbox[data-state="checked"] {
background: hsl(var(--primary));
border-color: hsl(var(--primary));
}
/* Custom SVG checkmark */
.custom-checkbox[data-state="checked"]::after {
content: '';
position: absolute;
width: 0.375rem;
height: 0.75rem;
border: solid white;
border-width: 0 2px 2px 0;
transform: rotate(45deg);
}
/* For indeterminate state - horizontal line */
.custom-checkbox[data-state="indeterminate"]::after {
content: '';
position: absolute;
width: 0.625rem;
height: 2px;
background: white;
transform: none;
}Themed Variants
/* Success theme */
.checkbox-success {
border-color: #22c55e;
}
.checkbox-success[data-state="checked"] {
background: #22c55e;
border-color: #22c55e;
}
/* Warning theme */
.checkbox-warning {
border-color: #eab308;
}
.checkbox-warning[data-state="checked"] {
background: #eab308;
border-color: #eab308;
}
/* Error theme */
.checkbox-error {
border-color: #ef4444;
}
.checkbox-error[data-state="checked"] {
background: #ef4444;
border-color: #ef4444;
}
/* Info theme */
.checkbox-info {
border-color: #3b82f6;
}
.checkbox-info[data-state="checked"] {
background: #3b82f6;
border-color: #3b82f6;
}Accessibility
Keyboard Navigation
| Key | Action |
|---|---|
| Space | Toggles the checkbox state |
ARIA Attributes
- role:
checkboxis set on the root element - aria-checked:
Reflects the current state (
true,false, ormixed) - aria-label:
Provides an accessible name when set via the
AriaLabelparameter - aria-disabled: Set when the checkbox is disabled
- aria-required: Set when the checkbox is required