ToggleButton
An interactive toggle control for on/off or selected/unselected states. Use standalone with [(selected)] or inside a ToggleButtonGroup with a value key.
Import
import { AvToggleButtonComponent } from '@avesra/angular';Usage
import { Component } from '@angular/core';
import { AvToggleButtonComponent } from '@avesra/angular';
import { AppIconComponent } from '../../components/app-icon/app-icon.component';
@Component({
selector: 'app-toggle-button-basic-demo',
imports: [AvToggleButtonComponent, AppIconComponent],
template: `<button av-toggle-button>
<app-icon icon="solar:heart-linear" size="16" />
Like
</button>`,
})
export class ToggleButtonBasicDemo {}Anatomy
Apply av-toggle-button to a native <button>. Content is projected via ng-content.
<button av-toggle-button [(selected)]="isSelected">
Toggle label
</button>Variants
Two visual styles — default (filled) and ghost (transparent).
import { Component } from '@angular/core';
import { AvToggleButtonComponent } from '@avesra/angular';
import { AppIconComponent } from '../../components/app-icon/app-icon.component';
@Component({
selector: 'app-toggle-button-variants-demo',
imports: [AvToggleButtonComponent, AppIconComponent],
template: `<div class="flex items-center gap-3">
<button av-toggle-button>
<app-icon icon="solar:heart-linear" size="16" />
Default
</button>
<button av-toggle-button variant="ghost">
<app-icon icon="solar:heart-linear" size="16" />
Ghost
</button>
</div>`,
})
export class ToggleButtonVariantsDemo {}Icon Only
Set icon-only for a square layout and always provide an aria-label for screen readers.
import { Component } from '@angular/core';
import { AvToggleButtonComponent } from '@avesra/angular';
import { AppIconComponent } from '../../components/app-icon/app-icon.component';
@Component({
selector: 'app-toggle-button-icon-only-demo',
imports: [AvToggleButtonComponent, AppIconComponent],
template: `<div class="flex items-center gap-3">
<button av-toggle-button icon-only aria-label="Like">
<app-icon icon="solar:heart-linear" size="16" />
</button>
<button av-toggle-button icon-only variant="ghost" aria-label="Bookmark">
<app-icon icon="solar:bookmark-linear" size="16" />
</button>
</div>`,
})
export class ToggleButtonIconOnlyDemo {}Sizes
Three sizes — sm, md (default), and lg. Size inherits from the parent group when omitted.
import { Component } from '@angular/core';
import { AvToggleButtonComponent } from '@avesra/angular';
import { AppIconComponent } from '../../components/app-icon/app-icon.component';
@Component({
selector: 'app-toggle-button-sizes-demo',
imports: [AvToggleButtonComponent, AppIconComponent],
template: `<div class="flex flex-col gap-6">
<div class="flex items-center gap-3">
<button av-toggle-button size="sm">
<app-icon icon="solar:heart-linear" size="16" />
Small
</button>
<button av-toggle-button size="md">
<app-icon icon="solar:heart-linear" size="16" />
Medium
</button>
<button av-toggle-button size="lg">
<app-icon icon="solar:heart-linear" size="16" />
Large
</button>
</div>
<div class="flex items-center gap-3">
<button av-toggle-button icon-only size="sm" aria-label="Like">
<app-icon icon="solar:heart-linear" size="16" />
</button>
<button av-toggle-button icon-only size="md" aria-label="Like">
<app-icon icon="solar:heart-linear" size="16" />
</button>
<button av-toggle-button icon-only size="lg" aria-label="Like">
<app-icon icon="solar:heart-linear" size="16" />
</button>
</div>
</div>`,
})
export class ToggleButtonSizesDemo {}Disabled
Set disabled to prevent interaction. Disabled state also inherits from a parent toggle button group.
import { Component } from '@angular/core';
import { AvToggleButtonComponent } from '@avesra/angular';
import { AppIconComponent } from '../../components/app-icon/app-icon.component';
@Component({
selector: 'app-toggle-button-disabled-demo',
imports: [AvToggleButtonComponent, AppIconComponent],
template: `<div class="flex items-center gap-3">
<button av-toggle-button [disabled]="true">
<app-icon icon="solar:heart-linear" size="16" />
Like
</button>
<button av-toggle-button [disabled]="true" [selected]="true">
<app-icon icon="solar:heart-bold" size="16" />
Like
</button>
</div>`,
})
export class ToggleButtonDisabledDemo {}Controlled
Bind [(selected)] for two-way control. Swap icon and label content based on the selected state.
Status: Not selected
import { Component, signal } from '@angular/core';
import { AvToggleButtonComponent } from '@avesra/angular';
import { AppIconComponent } from '../../components/app-icon/app-icon.component';
@Component({
selector: 'app-toggle-button-controlled-demo',
imports: [AvToggleButtonComponent, AppIconComponent],
template: `<div class="flex flex-col gap-4">
<button av-toggle-button [(selected)]="isSelected">
@if (isSelected()) {
<app-icon icon="solar:heart-bold" size="16" />
Liked
} @else {
<app-icon icon="solar:heart-linear" size="16" />
Like
}
</button>
<p class="text-sm text-muted">
Status:
<span class="font-medium">{{ isSelected() ? 'Selected' : 'Not selected' }}</span>
</p>
</div>`,
})
export class ToggleButtonControlledDemo {
readonly isSelected = signal(false);
}Customization
Tailwind CSS
Pass utility classes and CSS variables on the host to customize appearance — for example an X.com-style like control.
import { Component, signal } from '@angular/core';
import { AvToggleButtonComponent } from '@avesra/angular';
import { AppIconComponent } from '../../components/app-icon/app-icon.component';
@Component({
selector: 'app-toggle-button-custom-styling-demo',
imports: [AvToggleButtonComponent, AppIconComponent],
template: `<button
av-toggle-button
variant="ghost"
class="x-like"
aria-label="Like"
[(selected)]="liked"
>
<span class="x-like__hit">
<span class="x-like__burst" aria-hidden="true"></span>
<span class="x-like__icon">
<app-icon
[icon]="liked() ? 'solar:heart-bold' : 'solar:heart-linear'"
size="20"
/>
</span>
</span>
<span class="x-like__count">{{ liked() ? '68.1K' : '68K' }}</span>
</button>`,
styles: [`
.x-like {
--av-toggle-button-bg: transparent;
--av-toggle-button-bg-hover: transparent;
--av-toggle-button-bg-pressed: transparent;
--av-toggle-button-bg-selected: transparent;
--av-toggle-button-bg-selected-hover: transparent;
--av-toggle-button-bg-selected-pressed: transparent;
--av-toggle-button-fg-selected: #f91880;
gap: 0;
padding-inline: 0;
color: var(--av-muted);
}
.x-like:hover,
.x-like[data-hovered='true'],
.x-like[data-selected='true'] {
color: #f91880;
}
.x-like__hit {
position: relative;
display: grid;
place-items: center;
width: 2.25rem;
height: 2.25rem;
margin-inline-end: -0.35rem;
border-radius: 9999px;
transition: background-color 100ms ease;
}
.x-like:hover .x-like__hit,
.x-like[data-hovered='true'] .x-like__hit {
background-color: rgba(249, 24, 128, 0.1);
}
.x-like__icon {
display: grid;
place-items: center;
transition: transform 150ms ease;
}
.x-like[data-selected='true'] .x-like__icon {
animation: x-like-pop 0.45s cubic-bezier(0.36, 0.07, 0.19, 0.97);
}
.x-like__count {
min-width: 2rem;
font-size: 0.8125rem;
font-weight: 400;
font-variant-numeric: tabular-nums;
line-height: 1;
}
.x-like__burst {
position: absolute;
inset: 0;
border-radius: 9999px;
border: 2px solid #f91880;
opacity: 0;
pointer-events: none;
}
.x-like[data-selected='true'] .x-like__burst {
animation: x-like-burst 0.55s ease-out;
}
@keyframes x-like-pop {
0% { transform: scale(1); }
30% { transform: scale(0.75); }
60% { transform: scale(1.28); }
100% { transform: scale(1); }
}
@keyframes x-like-burst {
0% { transform: scale(0.35); opacity: 0.7; }
100% { transform: scale(1.75); opacity: 0; }
}
`],
})
export class ToggleButtonCustomStylingDemo {
readonly liked = signal(false);
}Global CSS
To customize ToggleButton classes, use the @layer components directive.
@layer components {
.av-toggle-button {
@apply bg-accent text-accent-foreground;
}
.av-toggle-button--icon-only {
@apply rounded-lg;
}
}Styling Reference
Avesra follows the BEM methodology so variants and states stay reusable and easy to customize.
CSS Classes
Base & Size Classes
.av-toggle-button— Base toggle button styles.av-toggle-button--sm— Small size variant.av-toggle-button--md— Medium size variant (default).av-toggle-button--lg— Large size variant
Variant Classes
.av-toggle-button--default— Default variant with filled background.av-toggle-button--ghost— Ghost variant with transparent background
Modifier Classes
.av-toggle-button--icon-only— Icon-only toggle button.av-toggle-button--icon-only.av-toggle-button--sm— Small icon-only.av-toggle-button--icon-only.av-toggle-button--lg— Large icon-only
Interactive States
The toggle button supports both CSS pseudo-classes and data attributes:
- Selected:
[data-selected="true"](also[aria-pressed="true"]) - Hover:
:hoveror[data-hovered="true"] - Active/Pressed:
:activeor[data-pressed="true"] - Focus:
:focus-visibleor[data-focus-visible="true"] - Disabled:
:disabledor[aria-disabled="true"]
API Reference
Props for button[av-toggle-button]. Implements toggle semantics via aria-pressed. Outside a group, bind selection with [(selected)].
| Prop | Type | Default | Description |
|---|---|---|---|
variant | 'default' | 'ghost' | 'default' | Visual style variant. |
size | 'sm' | 'md' | 'lg' | 'md' | Size of the toggle button. Inherits from toggle-button-group when omitted. |
icon-only | boolean | false | Whether the button contains only an icon (square layout). |
value | string | '' | Unique value used for selection inside a toggle-button-group. |
disabled | boolean | false | Whether the toggle button is disabled. |
selected | boolean | false | Selected state outside a group. Supports two-way binding with [(selected)]. |