shadcn-html / checkbox
Built with: CSS
Checkbox
A control that toggles between checked and unchecked. Built on native <input type="checkbox"> with CSS-only checkmark.
Default
Basic checkbox with label.
<input class="checkbox" type="checkbox" id="terms">
<label for="terms">Accept terms and conditions</label>
With description
Checkbox with helper text.
You can enable or disable notifications at any time.
<input class="checkbox" type="checkbox" id="notify">
<div>
<label for="notify">Enable notifications</label>
<p class="field-description">...</p>
</div>
Disabled
<input class="checkbox" type="checkbox" disabled>
<input class="checkbox" type="checkbox" disabled checked>
Checked by default
<input class="checkbox" type="checkbox" id="option" checked>
<label for="option">Pre-checked option</label>
Indeterminate
Set via JavaScript: checkbox.indeterminate = true.
<input class="checkbox" type="checkbox" id="select-all">
<label for="select-all">Select all</label>
<script>
document.getElementById('select-all').indeterminate = true;
</script>
Invalid
Shows destructive border via aria-invalid="true".
<input class="checkbox" type="checkbox" aria-invalid="true">
<label for="terms">Accept terms and conditions</label>
Group
Multiple checkboxes in a group using <fieldset> and <legend>.
<fieldset>
<legend>Select items to display on the desktop:</legend>
<p class="field-description">Choose which items are visible.</p>
<div class="checkbox-item">
<input class="checkbox" type="checkbox" id="item-1" checked>
<label for="item-1">Hard disks</label>
</div>
<div class="checkbox-item">
<input class="checkbox" type="checkbox" id="item-2" checked>
<label for="item-2">External disks</label>
</div>
<!-- ... more items -->
</fieldset>
CSS view file
/* -- Checkbox component ----------------------------------------- */
@layer components {
.checkbox {
appearance: none;
width: 1.125rem;
height: 1.125rem;
border: 1px solid var(--border);
border-radius: var(--radius-sm);
background: var(--background);
cursor: pointer;
flex-shrink: 0;
position: relative;
transition: background-color 150ms, border-color 150ms;
&:checked {
background-color: var(--primary);
border-color: var(--primary);
&::after {
content: '';
position: absolute;
left: 50%;
top: 45%;
width: 6px;
height: 10px;
border: solid var(--primary-foreground);
border-width: 0 2px 2px 0;
transform: translate(-50%, -50%) rotate(45deg);
}
}
&:indeterminate {
background-color: var(--primary);
border-color: var(--primary);
&::after {
content: '';
position: absolute;
left: 50%;
top: 50%;
width: 10px;
height: 2px;
background: var(--primary-foreground);
transform: translate(-50%, -50%);
}
}
&:focus-visible {
outline: 2px solid var(--ring);
outline-offset: 2px;
}
&:disabled {
opacity: 0.5;
cursor: not-allowed;
}
&:is([aria-invalid="true"], :user-invalid) {
border-color: var(--destructive);
}
}
/* -- Checkbox item layout --------------------------------- */
.checkbox-item {
display: flex;
align-items: center;
gap: 0.5rem;
& > label {
font-size: 0.875rem;
cursor: pointer;
}
}
.checkbox-item-block {
display: flex;
align-items: flex-start;
gap: 0.5rem;
& > label {
font-size: 0.875rem;
cursor: pointer;
}
& > .checkbox {
margin-top: 0.125rem;
}
}
/* Disabled auto-styling */
.checkbox-item:has(.checkbox:disabled),
.checkbox-item-block:has(.checkbox:disabled) {
opacity: 0.5;
cursor: not-allowed;
}
/* -- Accessibility ---------------------------------------- */
@media (prefers-reduced-motion: reduce) {
.checkbox {
transition: none;
}
}
@media (prefers-contrast: more) {
.checkbox {
border-width: 2px;
}
.checkbox:disabled {
opacity: 0.7;
}
}
@media (forced-colors: active) {
.checkbox {
appearance: auto;
}
}
}