Checkbox Group
Group of checkboxes with shared value, validation, and variant styling.
Import
import { AvCheckboxGroupImports } from '@avesra/angular';Usage
Choose all that apply
Love building software
Enjoy creating beautiful interfaces
Passionate about content creation
import { Component } from '@angular/core';
import {
AvCheckboxGroupImports,
AvDescriptionComponent,
AvLabelComponent,
} from '@avesra/angular';
@Component({
selector: 'app-checkbox-group-basic-demo',
imports: [
AvCheckboxGroupImports,
AvLabelComponent,
AvDescriptionComponent,
],
template: `<av-checkbox-group name="interests">
<label av-label>Select your interests</label>
<p av-description>Choose all that apply</p>
<div av-checkbox value="coding">
<span av-checkbox-control>
<span av-checkbox-indicator></span>
</span>
<span av-checkbox-content>
Coding
<p av-description>Love building software</p>
</span>
</div>
<div av-checkbox value="design">
<span av-checkbox-control>
<span av-checkbox-indicator></span>
</span>
<span av-checkbox-content>
Design
<p av-description>Enjoy creating beautiful interfaces</p>
</span>
</div>
<div av-checkbox value="writing">
<span av-checkbox-control>
<span av-checkbox-indicator></span>
</span>
<span av-checkbox-content>
Writing
<p av-description>Passionate about content creation</p>
</span>
</div>
</av-checkbox-group>`,
})
export class CheckboxGroupBasicDemo {}Anatomy
Import the CheckboxGroup components and compose the parts with av-checkbox-group, av-checkbox, av-checkbox-control, av-checkbox-indicator, and av-checkbox-content.
<av-checkbox-group name="interests">
<label av-label></label>
<p av-description></p> <!-- Optional -->
<div av-checkbox value="option1">
<span av-checkbox-control>
<span av-checkbox-indicator></span>
</span>
<span av-checkbox-content>
Label <!-- plain text — the clickable label -->
</span>
<p av-description></p> <!-- Optional per-checkbox help text -->
</div>
<p av-error-message></p> <!-- Optional -->
</av-checkbox-group>In Surface
When used inside a av-surface component, use variant="secondary" to apply the lower emphasis variant suitable for surface backgrounds.
Choose all that apply
Love building software
Enjoy creating beautiful interfaces
Passionate about content creation
import { Component } from '@angular/core';
import {
AvCheckboxGroupImports,
AvDescriptionComponent,
AvLabelComponent,
AvSurfaceComponent,
} from '@avesra/angular';
@Component({
selector: 'app-checkbox-group-on-surface-demo',
imports: [
AvSurfaceComponent,
AvCheckboxGroupImports,
AvLabelComponent,
AvDescriptionComponent,
],
template: `<div av-surface class="w-full rounded-3xl p-6">
<av-checkbox-group name="interests" variant="secondary">
<label av-label>Select your interests</label>
<p av-description>Choose all that apply</p>
<div av-checkbox value="coding">
<span av-checkbox-control>
<span av-checkbox-indicator></span>
</span>
<span av-checkbox-content>
Coding
<p av-description>Love building software</p>
</span>
</div>
<div av-checkbox value="design">
<span av-checkbox-control>
<span av-checkbox-indicator></span>
</span>
<span av-checkbox-content>
Design
<p av-description>Enjoy creating beautiful interfaces</p>
</span>
</div>
<div av-checkbox value="writing">
<span av-checkbox-control>
<span av-checkbox-indicator></span>
</span>
<span av-checkbox-content>
Writing
<p av-description>Passionate about content creation</p>
</span>
</div>
</av-checkbox-group>
</div>`,
})
export class CheckboxGroupOnSurfaceDemo {}Disabled
Feature selection is temporarily disabled
This feature is coming soon
This feature is coming soon
import { Component } from '@angular/core';
import {
AvCheckboxGroupImports,
AvDescriptionComponent,
AvLabelComponent,
} from '@avesra/angular';
@Component({
selector: 'app-checkbox-group-disabled-demo',
imports: [
AvCheckboxGroupImports,
AvLabelComponent,
AvDescriptionComponent,
],
template: `<av-checkbox-group disabled name="disabled-features">
<label av-label>Features</label>
<p av-description>Feature selection is temporarily disabled</p>
<div av-checkbox value="feature1">
<span av-checkbox-control>
<span av-checkbox-indicator></span>
</span>
<span av-checkbox-content>
Feature 1
<p av-description>This feature is coming soon</p>
</span>
</div>
<div av-checkbox value="feature2">
<span av-checkbox-control>
<span av-checkbox-indicator></span>
</span>
<span av-checkbox-content>
Feature 2
<p av-description>This feature is coming soon</p>
</span>
</div>
</av-checkbox-group>`,
})
export class CheckboxGroupDisabledDemo {}Indeterminate
import { Component, computed, signal } from '@angular/core';
import { AvCheckboxGroupImports } from '@avesra/angular';
@Component({
selector: 'app-checkbox-group-indeterminate-demo',
imports: [AvCheckboxGroupImports],
template: `<div>
<div
av-checkbox
name="select-all"
[selected]="selectAllSelected()"
[indeterminate]="selectAllIndeterminate()"
(selectedChange)="onSelectAllChange($event)"
>
<span av-checkbox-control>
<span av-checkbox-indicator></span>
</span>
<span av-checkbox-content>Select all</span>
</div>
<div class="ms-6 flex flex-col gap-2">
<av-checkbox-group [(value)]="selected">
<div av-checkbox value="coding">
<span av-checkbox-control>
<span av-checkbox-indicator></span>
</span>
<span av-checkbox-content>Coding</span>
</div>
<div av-checkbox value="design">
<span av-checkbox-control>
<span av-checkbox-indicator></span>
</span>
<span av-checkbox-content>Design</span>
</div>
<div av-checkbox value="writing">
<span av-checkbox-control>
<span av-checkbox-indicator></span>
</span>
<span av-checkbox-content>Writing</span>
</div>
</av-checkbox-group>
</div>
</div>`,
})
export class CheckboxGroupIndeterminateDemo {
readonly allOptions = ['coding', 'design', 'writing'] as const;
readonly selected = signal<string[]>(['coding']);
readonly selectAllSelected = computed(
() => this.selected().length === this.allOptions.length,
);
readonly selectAllIndeterminate = computed(() => {
const length = this.selected().length;
return length > 0 && length < this.allOptions.length;
});
onSelectAllChange(isSelected: boolean): void {
this.selected.set(isSelected ? [...this.allOptions] : []);
}
}Controlled
import { Component, signal } from '@angular/core';
import {
AvCheckboxGroupImports,
AvLabelComponent,
} from '@avesra/angular';
@Component({
selector: 'app-checkbox-group-controlled-demo',
imports: [
AvCheckboxGroupImports,
AvLabelComponent,
],
template: `<av-checkbox-group
class="min-w-[320px]"
name="skills"
[(value)]="selected"
>
<label av-label>Your skills</label>
<div av-checkbox value="coding">
<span av-checkbox-control>
<span av-checkbox-indicator></span>
</span>
<span av-checkbox-content>Coding</span>
</div>
<div av-checkbox value="design">
<span av-checkbox-control>
<span av-checkbox-indicator></span>
</span>
<span av-checkbox-content>Design</span>
</div>
<div av-checkbox value="writing">
<span av-checkbox-control>
<span av-checkbox-indicator></span>
</span>
<span av-checkbox-content>Writing</span>
</div>
<label av-label class="my-4 text-sm text-muted">
Selected: {{ selected().join(', ') || 'None' }}
</label>
</av-checkbox-group>`,
})
export class CheckboxGroupControlledDemo {
readonly selected = signal<string[]>(['coding', 'design']);
}Validation
import { Component, computed, signal } from '@angular/core';
import {
AvButtonComponent,
AvCheckboxGroupImports,
AvFieldErrorComponent,
AvFormComponent,
AvLabelComponent,
} from '@avesra/angular';
@Component({
selector: 'app-checkbox-group-validation-demo',
imports: [
AvFormComponent,
AvCheckboxGroupImports,
AvLabelComponent,
AvFieldErrorComponent,
AvButtonComponent,
],
template: `<form
av-form
class="flex flex-col gap-4 px-4"
(submit)="onSubmit($event)"
>
<av-checkbox-group
name="preferences"
[(value)]="selected"
[invalid]="isInvalid()"
>
<label av-label required [invalid]="isInvalid()">Preferences</label>
<div av-checkbox name="preferences" value="email">
<span av-checkbox-control>
<span av-checkbox-indicator></span>
</span>
<span av-checkbox-content>Email notifications</span>
</div>
<div av-checkbox name="preferences" value="sms">
<span av-checkbox-control>
<span av-checkbox-indicator></span>
</span>
<span av-checkbox-content>SMS notifications</span>
</div>
<div av-checkbox name="preferences" value="push">
<span av-checkbox-control>
<span av-checkbox-indicator></span>
</span>
<span av-checkbox-content>Push notifications</span>
</div>
<p av-field-error [visible]="isInvalid()">
Please select at least one notification method.
</p>
</av-checkbox-group>
<button av-button type="submit">Submit</button>
</form>`,
})
export class CheckboxGroupValidationDemo {
readonly selected = signal<string[]>([]);
readonly submitted = signal(false);
readonly isInvalid = computed(
() => this.submitted() && this.selected().length === 0,
);
onSubmit(event: Event): void {
event.preventDefault();
this.submitted.set(true);
if (this.selected().length === 0) {
return;
}
const form = event.target as HTMLFormElement;
const formData = new FormData(form);
const values = formData.getAll('preferences');
alert(`Selected preferences: ${values.join(', ')}`);
}
}Features and Add-ons Example
Choose how you want to receive updates
Receive updates via email
Get instant SMS notifications
Browser and mobile push alerts
import { Component } from '@angular/core';
import {
AvCheckboxGroupImports,
AvDescriptionComponent,
AvLabelComponent,
} from '@avesra/angular';
import { AppIconComponent } from '../../components/app-icon/app-icon.component';
@Component({
selector: 'app-checkbox-group-features-and-addons-demo',
imports: [
AvCheckboxGroupImports,
AvLabelComponent,
AvDescriptionComponent,
AppIconComponent,
],
template: `<div class="flex w-full flex-col items-center gap-10 px-4 py-8">
<section class="flex w-full min-w-[320px] flex-col gap-4">
<av-checkbox-group name="notification-preferences">
<label av-label>Notification preferences</label>
<p av-description>Choose how you want to receive updates</p>
<div class="flex flex-col gap-2">
@for (addon of addOns; track addon.value) {
<div av-checkbox [value]="addon.value" variant="secondary" class="group w-full">
<div
class="relative flex w-full flex-row items-start justify-start gap-4 rounded-3xl bg-surface px-5 py-4 transition-all group-data-[selected=true]:bg-accent/10"
>
<span
av-checkbox-control
class="absolute top-3 end-4 size-5 rounded-full before:rounded-full"
>
<span av-checkbox-indicator></span>
</span>
<app-icon
[icon]="addon.icon"
size="20"
class="size-5 text-accent-soft-foreground"
/>
<span av-checkbox-content class="flex flex-col gap-1">
<span>{{ addon.title }}</span>
<p av-description>{{ addon.description }}</p>
</span>
</div>
</div>
}
</div>
</av-checkbox-group>
</section>
</div>`,
})
export class CheckboxGroupFeaturesAndAddOnsDemo {
readonly addOns = [
{
description: 'Receive updates via email',
icon: 'solar:letter-linear',
title: 'Email Notifications',
value: 'email',
},
{
description: 'Get instant SMS notifications',
icon: 'solar:chat-round-line-linear',
title: 'SMS Alerts',
value: 'sms',
},
{
description: 'Browser and mobile push alerts',
icon: 'solar:bell-linear',
title: 'Push Notifications',
value: 'push',
},
];
}With Custom Indicator
Select the features you want
Receive updates via email
Get weekly newsletters
import { Component, signal } from '@angular/core';
import {
AvCheckboxGroupImports,
AvDescriptionComponent,
AvLabelComponent,
} from '@avesra/angular';
@Component({
selector: 'app-checkbox-group-with-custom-indicator-demo',
imports: [
AvCheckboxGroupImports,
AvLabelComponent,
AvDescriptionComponent,
],
template: `<av-checkbox-group name="features" [(value)]="selected">
<label av-label>Features</label>
<p av-description>Select the features you want</p>
<div av-checkbox value="notifications">
<span av-checkbox-control>
<span av-checkbox-indicator>
@if (selected().includes('notifications')) {
<svg
aria-hidden="true"
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-width="2"
viewBox="0 0 24 24"
>
<path d="M6 18L18 6M6 6l12 12" />
</svg>
}
</span>
</span>
<span av-checkbox-content>
Email notifications
<p av-description>Receive updates via email</p>
</span>
</div>
<div av-checkbox value="newsletter">
<span av-checkbox-control>
<span av-checkbox-indicator>
@if (selected().includes('newsletter')) {
<svg
aria-hidden="true"
fill="none"
stroke="currentColor"
stroke-linecap="round"
stroke-width="2"
viewBox="0 0 24 24"
>
<path d="M6 18L18 6M6 6l12 12" />
</svg>
}
</span>
</span>
<span av-checkbox-content>
Newsletter
<p av-description>Get weekly newsletters</p>
</span>
</div>
</av-checkbox-group>`,
})
export class CheckboxGroupWithCustomIndicatorDemo {
readonly selected = signal<string[]>([]);
}Reactive form
Integrate with Angular reactive forms using [formControl] or formControlName on av-checkbox-group.
import { Component } from '@angular/core';
import { FormControl, ReactiveFormsModule } from '@angular/forms';
import {
AvCheckboxGroupImports,
AvLabelComponent,
} from '@avesra/angular';
@Component({
selector: 'app-checkbox-group-reactive-form-demo',
imports: [
ReactiveFormsModule,
AvCheckboxGroupImports,
AvLabelComponent,
],
template: `<av-checkbox-group class="min-w-[320px]" [formControl]="interestsControl">
<label av-label>Interests</label>
<div av-checkbox value="coding">
<span av-checkbox-control>
<span av-checkbox-indicator></span>
</span>
<span av-checkbox-content>Coding</span>
</div>
<div av-checkbox value="design">
<span av-checkbox-control>
<span av-checkbox-indicator></span>
</span>
<span av-checkbox-content>Design</span>
</div>
<div av-checkbox value="writing">
<span av-checkbox-control>
<span av-checkbox-indicator></span>
</span>
<span av-checkbox-content>Writing</span>
</div>
<label av-label class="my-4 text-sm text-muted">
Form value: {{ interestsControl.value?.join(', ') || 'None' }}
</label>
</av-checkbox-group>`,
})
export class CheckboxGroupReactiveFormDemo {
readonly interestsControl = new FormControl<string[]>(['design']);
}Styling
CSS Classes
Avesra uses BEM-style classes for predictable customization.
.av-checkbox-group— Group layout container.av-checkbox-group--primary— Primary visual variant.av-checkbox-group--secondary— Secondary visual variant (inherited by children)
Interactive States
Group-level disabled and invalid props cascade to child checkboxes. Individual checkbox states use the same selectors documented on the Checkbox page.
Accessibility
Checkbox Group renders a role="group" container and provides:
- Group labeling via
av-labelwitharia-labelledby - Supplementary text via
av-descriptionlinked witharia-describedby - Each child checkbox retains independent
aria-checkedstate - Group-level
aria-invalidwhen validation fails - Keyboard navigation between checkboxes via Tab
API
| Prop | Type | Default | Description |
|---|---|---|---|
variant | 'primary' | 'secondary' | 'primary' | Shared visual variant applied to all child checkboxes. |
disabled | boolean | false | Disables all child checkboxes. |
invalid | boolean | false | Marks all child checkboxes as invalid. |
name | string | — | Form field name for native form submission. |
default-value | string[] | [] | Initial selected values for uncontrolled usage. |
value | string[] | [] | Selected values. Supports two-way binding with `[(value)]`. |
valueChange | EventEmitter<string[]> | — | Emits when the selected values change. |