Skip to content
Ndop UI

Toggle Group

A set of toggle buttons of which one or several are pressed, such as text alignment or formatting.

import { Component, signal } from '@angular/core';
import { NdIcon } from '@ndop/core';
import { ToggleGroup, ToggleGroupItem } from '@/ui/toggle-group/toggle-group';

/** Text formatting where any number of options combine, in the outline style. */
@Component({
  selector: 'example-toggle-group-demo',
  imports: [NdIcon, ToggleGroup, ToggleGroupItem],
  template: `
    <div
      ndToggleGroup
      type="multiple"
      variant="outline"
      aria-label="Text formatting"
      [(value)]="formatting"
    >
      <button ndToggleGroupItem value="bold" aria-label="Toggle bold">
        <svg ndIcon="bold"></svg>
      </button>
      <button ndToggleGroupItem value="italic" aria-label="Toggle italic">
        <svg ndIcon="italic"></svg>
      </button>
      <button ndToggleGroupItem value="underline" aria-label="Toggle underline">
        <svg ndIcon="underline"></svg>
      </button>
    </div>
  `,
})
export class ToggleGroupDemoExample {
  protected readonly formatting = signal<readonly string[]>(['bold']);
}

A toggle group is a set of toggle buttons: one pressed at most, such as text alignment, or any number, such as bold, italic and underline. Only one of its buttons is in the tab order, and the arrow keys move between them. Its value is always an array of the pressed buttons' values. With spacing 0, the default, its buttons join into one bar; the outline variant draws a border around each.

Installation

npx @ndop/cli add toggle-group

Usage

import { ToggleGroup, ToggleGroupItem } from '@/ui/toggle-group/toggle-group';
<div
  ndToggleGroup
  type="multiple"
  variant="outline"
  aria-label="Text formatting"
  [(value)]="formatting"
>
  <button ndToggleGroupItem value="bold" aria-label="Toggle bold">
    <svg ndIcon="bold"></svg>
  </button>
  <button ndToggleGroupItem value="italic" aria-label="Toggle italic">
    <svg ndIcon="italic"></svg>
  </button>
  <button ndToggleGroupItem value="underline" aria-label="Toggle underline">
    <svg ndIcon="underline"></svg>
  </button>
</div>

Examples

Toggle Group single

Text alignment, where one option at most is pressed.

import { Component, signal } from '@angular/core';
import { NdIcon } from '@ndop/core';
import { ToggleGroup, ToggleGroupItem } from '@/ui/toggle-group/toggle-group';

/** Text alignment, where one option at most is pressed. */
@Component({
  selector: 'example-toggle-group-single',
  imports: [NdIcon, ToggleGroup, ToggleGroupItem],
  template: `
    <div ndToggleGroup aria-label="Text alignment" [(value)]="alignment">
      <button ndToggleGroupItem value="start" aria-label="Align start">
        <svg ndIcon="text-align-start"></svg>
      </button>
      <button ndToggleGroupItem value="center" aria-label="Align center">
        <svg ndIcon="text-align-center"></svg>
      </button>
      <button ndToggleGroupItem value="end" aria-label="Align end">
        <svg ndIcon="text-align-end"></svg>
      </button>
    </div>
  `,
})
export class ToggleGroupSingleExample {
  protected readonly alignment = signal<readonly string[]>(['start']);
}

Toggle Group sizes

The small and large sizes.

import { Component } from '@angular/core';
import { NdIcon } from '@ndop/core';
import { ToggleGroup, ToggleGroupItem } from '@/ui/toggle-group/toggle-group';

/** The small and large sizes. */
@Component({
  selector: 'example-toggle-group-sizes',
  imports: [NdIcon, ToggleGroup, ToggleGroupItem],
  template: `
    <div class="flex flex-col items-start gap-4">
      @for (size of sizes; track size) {
        <div
          ndToggleGroup
          type="multiple"
          variant="outline"
          [size]="size"
          [attr.aria-label]="'Text formatting, ' + size"
        >
          <button ndToggleGroupItem value="bold" aria-label="Toggle bold">
            <svg ndIcon="bold"></svg>
          </button>
          <button ndToggleGroupItem value="italic" aria-label="Toggle italic">
            <svg ndIcon="italic"></svg>
          </button>
          <button
            ndToggleGroupItem
            value="underline"
            aria-label="Toggle underline"
          >
            <svg ndIcon="underline"></svg>
          </button>
        </div>
      }
    </div>
  `,
})
export class ToggleGroupSizesExample {
  protected readonly sizes = ['sm', 'lg'] as const;
}

Toggle Group spacing

Separate buttons instead of one joined bar.

import { Component } from '@angular/core';
import { ToggleGroup, ToggleGroupItem } from '@/ui/toggle-group/toggle-group';

/** Separate buttons instead of one joined bar. */
@Component({
  selector: 'example-toggle-group-spacing',
  imports: [ToggleGroup, ToggleGroupItem],
  template: `
    <div
      ndToggleGroup
      variant="outline"
      size="sm"
      [spacing]="2"
      aria-label="Release channel"
      [defaultValue]="['stable']"
    >
      <button ndToggleGroupItem value="stable">Stable</button>
      <button ndToggleGroupItem value="beta">Beta</button>
      <button ndToggleGroupItem value="nightly">Nightly</button>
    </div>
  `,
})
export class ToggleGroupSpacingExample {}

Toggle Group vertical

A vertical group, moved through with the up and down arrows.

import { Component } from '@angular/core';
import { ToggleGroup, ToggleGroupItem } from '@/ui/toggle-group/toggle-group';

/** A vertical group, moved through with the up and down arrows. */
@Component({
  selector: 'example-toggle-group-vertical',
  imports: [ToggleGroup, ToggleGroupItem],
  template: `
    <div
      ndToggleGroup
      orientation="vertical"
      variant="outline"
      [spacing]="1"
      aria-label="Layout"
      [defaultValue]="['list']"
    >
      <button ndToggleGroupItem value="list">List</button>
      <button ndToggleGroupItem value="board">Board</button>
      <button ndToggleGroupItem value="calendar">Calendar</button>
    </div>
  `,
})
export class ToggleGroupVerticalExample {}

Toggle Group disabled

A disabled group.

import { Component } from '@angular/core';
import { NdIcon } from '@ndop/core';
import { ToggleGroup, ToggleGroupItem } from '@/ui/toggle-group/toggle-group';

/** A disabled group. */
@Component({
  selector: 'example-toggle-group-disabled',
  imports: [NdIcon, ToggleGroup, ToggleGroupItem],
  template: `
    <div
      ndToggleGroup
      type="multiple"
      disabled
      aria-label="Text formatting"
      [defaultValue]="['bold']"
    >
      <button ndToggleGroupItem value="bold" aria-label="Toggle bold">
        <svg ndIcon="bold"></svg>
      </button>
      <button ndToggleGroupItem value="italic" aria-label="Toggle italic">
        <svg ndIcon="italic"></svg>
      </button>
      <button ndToggleGroupItem value="underline" aria-label="Toggle underline">
        <svg ndIcon="underline"></svg>
      </button>
    </div>
  `,
})
export class ToggleGroupDisabledExample {}

Accessibility

Implements the toggle buttons pattern of the WAI-ARIA Authoring Practices.

Keyboard

Keys the component handles.

Key Action
TabMoves focus into the group, to its tab stop; then out of it.
SpaceorEnterPresses or releases the focused item.
ArrowRightorArrowLeftHorizontal groups: moves focus to the next or previous enabled item, wrapping, without pressing it.
ArrowDownorArrowUpVertical groups: moves focus to the next or previous enabled item, wrapping, without pressing it.
HomeorEndMoves focus to the first or last enabled item.

Focus

  • Arrow keys, Home and End move focus only; pressing stays with Space and Enter. Disabled items are skipped.

Right-to-left

In right-to-left layouts, ArrowLeft moves to the next item and ArrowRight to the previous one. Direction comes from the nearest dir attribute, on the item or an ancestor.

API reference

ToggleGroup

[ndToggleGroup]role group

A group of toggle buttons (@ndop/primitives/toggle-group): one pressed at most (type="single", the default) or any number (type="multiple"). Arrow keys move between items. Its value is always an array of the pressed items' values. Name it with aria-label. Its variant and size apply to every item; with spacing 0 (the default) the items join into one bar.

ToggleGroup binding Type Default
[variant]
Visual style of every item.
'default' | 'outline''default'
[size]
Size of every item.
'default' | 'sm' | 'lg''default'
[spacing]
Space between items, in Tailwind spacing units; 0 joins them into one bar.
number0
[class]
Extra classes, merged last so they win.
string''
[defaultValue]
Initial value when it isn't bound.
readonly string[][]
[type]
single: pressing an item releases the others. multiple: items are pressed independently.
'single' | 'multiple''single'
[orientation]
Which arrow keys move focus: left and right, or up and down.
'horizontal' | 'vertical''horizontal'
[disabled]
Disables every item. A disabled bound field does too.
booleanfalse
[(value)]
The pressed items' values, in both modes. Two-way bindable with [(value)].
readonly string[][]
Data attribute Values
data-slottoggle-group
data-variant —
data-size —
data-spacing —
data-orientation —
data-disabled —

ToggleGroupItem

button[ndToggleGroupItem]

One toggle button of a ToggleGroup, styled like a Toggle with the group's variant and size.

Manages aria-pressed.

ToggleGroupItem binding Type Default
[variant]
Visual style, when the group doesn't set one.
'default' | 'outline'—
[size]
Size, when the group doesn't set one.
'default' | 'sm' | 'lg'—
[class]
Extra classes, merged last so they win.
string''
[value]required
The value this item adds to the group's while pressed.
string—
[disabled]
Disables this item; arrow keys skip it.
booleanfalse
Data attribute Values
data-slottoggle-group-item
data-variant —
data-size —
data-spacing —
data-state —
data-disabled —
data-orientation —

Agent notes

Do

  • Name the group with aria-label, such as "Text alignment", and every icon-only button too.
  • Use type="multiple" when the options combine.

Don't

  • Don't use it for navigation between views of a page; use Tabs.
  • Don't use a single toggle group for unrelated options.