AvesraAvesrabeta

List Box

A listbox displays a list of options and allows a user to select one or more of them.

Import

import { AvListBoxImports } from '@avesra/angular';

Usage

import { Component, signal } from '@angular/core';
import {
  AvAvatarImports,
  AvDescriptionComponent,
  AvLabelComponent,
  AvListBoxImports,
  AvSurfaceComponent,
} from '@avesra/angular';

@Component({
  selector: 'app-list-box-basic-demo',
  imports: [
    AvSurfaceComponent,
    AvListBoxImports,
    AvLabelComponent,
    AvDescriptionComponent,
    AvAvatarImports,
  ],
  template: `<div av-surface class="w-56 rounded-3xl shadow-surface">
  <div
    av-list-box
    aria-label="Users"
    selection-mode="single"
    [(selectedKeys)]="selectedUser"
    class="w-full"
  >
    @for (user of users; track user.id) {
      <div av-list-box-item [id]="user.id" [textValue]="user.name">
        <span av-avatar size="sm">
          <img av-avatar-image [alt]="user.name" [src]="user.avatar" />
          <span av-avatar-fallback>{{ user.fallback }}</span>
        </span>
        <div class="flex flex-col">
          <label av-label>{{ user.name }}</label>
          <p av-description>{{ user.email }}</p>
        </div>
        <span av-list-box-item-indicator></span>
      </div>
    }
  </div>
</div>
<p class="mt-3 text-sm text-muted">Selected: {{ selectedUser().join(', ') || 'none' }}</p>`,
})
export class ListBoxBasicDemo {
  readonly selectedUser = signal<string[]>(['1']);
  readonly users = [
  {
    "id": "1",
    "name": "Bob",
    "email": "[email protected]",
    "avatar": "/images/gradients/gradient-blue-cyan.png",
    "fallback": "B"
  },
  {
    "id": "2",
    "name": "Fred",
    "email": "[email protected]",
    "avatar": "/images/gradients/gradient-cyan-blue-purple.png",
    "fallback": "F"
  },
  {
    "id": "3",
    "name": "Martha",
    "email": "[email protected]",
    "avatar": "/images/gradients/gradient-purple-violet.png",
    "fallback": "M"
  }
];
}

Anatomy

Import the List Box parts and compose them with attribute selectors. Project av-label, av-description, and av-list-box-item-indicator inside each item. Group related items with av-list-box-section.

<div
  av-list-box
  aria-label="Options"
  selection-mode="single"
  [(selectedKeys)]="selected"
>
  <div av-list-box-item id="item-1" textValue="Item 1">
    <label av-label></label>
    <p av-description></p>
    <span av-list-box-item-indicator></span>
  </div>
  <div av-list-box-section>
    <!-- Section heading (plain text or your own heading styles) -->
    <div av-list-box-item id="item-2" textValue="Item 2">
      <label av-label></label>
      <span av-list-box-item-indicator></span>
    </div>
  </div>
</div>

With Disabled Items

Set disabled on an individual av-list-box-item to prevent activation. The item remains visible but is skipped by keyboard navigation. Use disabled on av-list-box to disable the entire list.

Actions

Create a new file

⌘N

Make changes

⌘E

Danger zone

Move to trash

⌘⇧D
import { Component, signal } from '@angular/core';
import {
  AvDescriptionComponent,
  AvKbdImports,
  AvLabelComponent,
  AvListBoxImports,
  AvSeparatorImports,
  AvSurfaceComponent,
} from '@avesra/angular';

@Component({
  selector: 'app-list-box-with-disabled-items-demo',
  imports: [
    AvSurfaceComponent,
    AvListBoxImports,
    AvLabelComponent,
    AvDescriptionComponent,
    AvSeparatorImports,
    AvKbdImports,
  ],
  template: `<div av-surface class="w-64 rounded-3xl shadow-surface">
  <div
    av-list-box
    aria-label="File actions"
    selection-mode="none"
    class="w-full p-2"
    (action)="onAction($event)"
  >
    <div av-list-box-section>
      <p class="px-2.5 py-1 text-xs font-medium text-muted">Actions</p>
      <div av-list-box-item id="disabled-new" textValue="New file">
        <div class="flex h-8 items-start justify-center pt-px">
          <svg class="size-4 shrink-0 text-muted" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
            <path d="M8 2a.75.75 0 0 1 .75.75V7h4.25a.75.75 0 0 1 0 1.5H8.75v4.25a.75.75 0 0 1-1.5 0V8.5H3a.75.75 0 0 1 0-1.5h4.25V2.75A.75.75 0 0 1 8 2Z" />
          </svg>
        </div>
        <div class="flex flex-col">
          <label av-label>New file</label>
          <p av-description>Create a new file</p>
        </div>
        <kbd av-kbd variant="light" class="ms-auto">
          <abbr av-kbd-abbr key-value="command"></abbr>
          <span av-kbd-content>N</span>
        </kbd>
      </div>
      <div av-list-box-item id="disabled-edit" textValue="Edit file">
        <div class="flex h-8 items-start justify-center pt-px">
          <svg class="size-4 shrink-0 text-muted" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
            <path d="M11.013 1.427a1.75 1.75 0 0 1 2.474 0l1.086 1.086a1.75 1.75 0 0 1 0 2.474l-8.61 8.61c-.21.21-.47.364-.756.445l-3.251.93a.75.75 0 0 1-.927-.928l.929-3.25c.081-.286.235-.547.445-.757l8.61-8.61Z" />
          </svg>
        </div>
        <div class="flex flex-col">
          <label av-label>Edit file</label>
          <p av-description>Make changes</p>
        </div>
        <kbd av-kbd variant="light" class="ms-auto">
          <abbr av-kbd-abbr key-value="command"></abbr>
          <span av-kbd-content>E</span>
        </kbd>
      </div>
    </div>
    <div av-separator></div>
    <div av-list-box-section>
      <p class="px-2.5 py-1 text-xs font-medium text-muted">Danger zone</p>
      <div av-list-box-item id="disabled-delete" textValue="Delete file" variant="danger" disabled>
        <div class="flex h-8 items-start justify-center pt-px">
          <svg class="size-4 shrink-0 text-danger" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
            <path d="M5 2.5A1.5 1.5 0 0 1 6.5 1h3A1.5 1.5 0 0 1 11 2.5V3h2.25a.75.75 0 0 1 0 1.5H13v8.25A1.75 1.75 0 0 1 11.25 14.5h-6.5A1.75 1.75 0 0 1 3 12.75V4.5H1.75a.75.75 0 0 1 0-1.5H5V2.5Z" />
          </svg>
        </div>
        <div class="flex flex-col">
          <label av-label>Delete file</label>
          <p av-description>Move to trash</p>
        </div>
        <kbd av-kbd variant="light" class="ms-auto">
          <abbr av-kbd-abbr key-value="command"></abbr>
          <abbr av-kbd-abbr key-value="shift"></abbr>
          <span av-kbd-content>D</span>
        </kbd>
      </div>
    </div>
  </div>
</div>
@if (lastAction()) {
  <p class="mt-3 text-sm text-muted">Last action: {{ lastAction() }}</p>
}`,
})
export class ListBoxWithDisabledItemsDemo {
  readonly lastAction = signal('');

  onAction(key: string): void {
    this.lastAction.set(key);
  }
}

With Sections

Use selection-mode="none" with (action) for action menus. Group items in sections and separate groups with av-separator. Mark destructive actions with variant="danger" on the item.

Actions

Create a new file

⌘N

Make changes

⌘E

Danger zone

Move to trash

⌘⇧D
import { Component, signal } from '@angular/core';
import {
  AvDescriptionComponent,
  AvKbdImports,
  AvLabelComponent,
  AvListBoxImports,
  AvSeparatorImports,
  AvSurfaceComponent,
} from '@avesra/angular';

@Component({
  selector: 'app-list-box-with-sections-demo',
  imports: [
    AvSurfaceComponent,
    AvListBoxImports,
    AvLabelComponent,
    AvDescriptionComponent,
    AvSeparatorImports,
    AvKbdImports,
  ],
  template: `<div av-surface class="w-64 rounded-3xl shadow-surface">
  <div
    av-list-box
    aria-label="File actions"
    selection-mode="none"
    class="w-full p-2"
    (action)="onAction($event)"
  >
    <div av-list-box-section>
      <p class="px-2.5 py-1 text-xs font-medium text-muted">Actions</p>
      <div av-list-box-item id="section-new" textValue="New file">
        <div class="flex h-8 items-start justify-center pt-px">
          <svg class="size-4 shrink-0 text-muted" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
            <path d="M8 2a.75.75 0 0 1 .75.75V7h4.25a.75.75 0 0 1 0 1.5H8.75v4.25a.75.75 0 0 1-1.5 0V8.5H3a.75.75 0 0 1 0-1.5h4.25V2.75A.75.75 0 0 1 8 2Z" />
          </svg>
        </div>
        <div class="flex flex-col">
          <label av-label>New file</label>
          <p av-description>Create a new file</p>
        </div>
        <kbd av-kbd variant="light" class="ms-auto">
          <abbr av-kbd-abbr key-value="command"></abbr>
          <span av-kbd-content>N</span>
        </kbd>
      </div>
      <div av-list-box-item id="section-edit" textValue="Edit file">
        <div class="flex h-8 items-start justify-center pt-px">
          <svg class="size-4 shrink-0 text-muted" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
            <path d="M11.013 1.427a1.75 1.75 0 0 1 2.474 0l1.086 1.086a1.75 1.75 0 0 1 0 2.474l-8.61 8.61c-.21.21-.47.364-.756.445l-3.251.93a.75.75 0 0 1-.927-.928l.929-3.25c.081-.286.235-.547.445-.757l8.61-8.61Z" />
          </svg>
        </div>
        <div class="flex flex-col">
          <label av-label>Edit file</label>
          <p av-description>Make changes</p>
        </div>
        <kbd av-kbd variant="light" class="ms-auto">
          <abbr av-kbd-abbr key-value="command"></abbr>
          <span av-kbd-content>E</span>
        </kbd>
      </div>
    </div>
    <div av-separator></div>
    <div av-list-box-section>
      <p class="px-2.5 py-1 text-xs font-medium text-muted">Danger zone</p>
      <div av-list-box-item id="section-delete" textValue="Delete file" variant="danger">
        <div class="flex h-8 items-start justify-center pt-px">
          <svg class="size-4 shrink-0 text-danger" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
            <path d="M5 2.5A1.5 1.5 0 0 1 6.5 1h3A1.5 1.5 0 0 1 11 2.5V3h2.25a.75.75 0 0 1 0 1.5H13v8.25A1.75 1.75 0 0 1 11.25 14.5h-6.5A1.75 1.75 0 0 1 3 12.75V4.5H1.75a.75.75 0 0 1 0-1.5H5V2.5Z" />
          </svg>
        </div>
        <div class="flex flex-col">
          <label av-label>Delete file</label>
          <p av-description>Move to trash</p>
        </div>
        <kbd av-kbd variant="light" class="ms-auto">
          <abbr av-kbd-abbr key-value="command"></abbr>
          <abbr av-kbd-abbr key-value="shift"></abbr>
          <span av-kbd-content>D</span>
        </kbd>
      </div>
    </div>
  </div>
</div>
@if (lastAction()) {
  <p class="mt-3 text-sm text-muted">Last action: {{ lastAction() }}</p>
}`,
})
export class ListBoxWithSectionsDemo {
  readonly lastAction = signal('');

  onAction(key: string): void {
    this.lastAction.set(key);
  }
}

Multi Select

Set selection-mode="multiple" so users can select several items. Selected item ids are stored in selectedKeys (string[]).

import { Component, signal } from '@angular/core';
import {
  AvAvatarImports,
  AvDescriptionComponent,
  AvLabelComponent,
  AvListBoxImports,
  AvSurfaceComponent,
} from '@avesra/angular';

@Component({
  selector: 'app-list-box-multiple-selection-demo',
  imports: [
    AvSurfaceComponent,
    AvListBoxImports,
    AvLabelComponent,
    AvDescriptionComponent,
    AvAvatarImports,
  ],
  template: `<div av-surface class="w-64 rounded-3xl shadow-surface">
  <div
    av-list-box
    aria-label="Users"
    selection-mode="multiple"
    [(selectedKeys)]="selectedUsers"
    class="w-full"
  >
    @for (user of users; track user.id) {
      <div av-list-box-item [id]="user.id" [textValue]="user.name">
        <span av-avatar size="sm">
          <img av-avatar-image [alt]="user.name" [src]="user.avatar" />
          <span av-avatar-fallback>{{ user.fallback }}</span>
        </span>
        <div class="flex flex-col">
          <label av-label>{{ user.name }}</label>
          <p av-description>{{ user.email }}</p>
        </div>
        <span av-list-box-item-indicator></span>
      </div>
    }
  </div>
</div>
<p class="mt-3 text-sm text-muted">Selected: {{ selectedUsers().join(', ') || 'none' }}</p>`,
})
export class ListBoxMultipleSelectionDemo {
  readonly selectedUsers = signal<string[]>([]);
  readonly users = [
  {
    "id": "1",
    "name": "Bob",
    "email": "[email protected]",
    "avatar": "/images/gradients/gradient-blue-cyan.png",
    "fallback": "B"
  },
  {
    "id": "2",
    "name": "Fred",
    "email": "[email protected]",
    "avatar": "/images/gradients/gradient-cyan-blue-purple.png",
    "fallback": "F"
  },
  {
    "id": "3",
    "name": "Martha",
    "email": "[email protected]",
    "avatar": "/images/gradients/gradient-purple-violet.png",
    "fallback": "M"
  }
];
}

Controlled

Drive selection from outside the listbox with [(selectedKeys)] — for example Select all / Clear controls next to the list, or any signal that updates the model.

Selected: 1

import { Component, signal } from '@angular/core';
import {
  AvAvatarImports,
  AvButtonComponent,
  AvDescriptionComponent,
  AvLabelComponent,
  AvListBoxImports,
  AvSurfaceComponent,
} from '@avesra/angular';

@Component({
  selector: 'app-list-box-controlled-selection-demo',
  imports: [
    AvSurfaceComponent,
    AvListBoxImports,
    AvLabelComponent,
    AvDescriptionComponent,
    AvAvatarImports,
    AvButtonComponent,
  ],
  template: `<div class="flex flex-wrap items-start gap-4">
  <div class="flex flex-wrap gap-2">
    <button av-button size="sm" variant="tertiary" (click)="selectAllUsers()">Select all</button>
    <button av-button size="sm" variant="tertiary" (click)="clearSelection()">Clear</button>
  </div>
  <div av-surface class="w-64 rounded-3xl shadow-surface">
    <div
      av-list-box
      aria-label="Users"
      selection-mode="multiple"
      [(selectedKeys)]="controlledSelected"
      class="w-full"
    >
      @for (user of users; track user.id) {
        <div av-list-box-item [id]="user.id" [textValue]="user.name">
          <span av-avatar size="sm">
            <img av-avatar-image [alt]="user.name" [src]="user.avatar" />
            <span av-avatar-fallback>{{ user.fallback }}</span>
          </span>
          <div class="flex flex-col">
            <label av-label>{{ user.name }}</label>
            <p av-description>{{ user.email }}</p>
          </div>
          <span av-list-box-item-indicator>
            <svg class="size-4 text-accent" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
              <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.75.75 0 0 1 1.06-1.06L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z" />
            </svg>
          </span>
        </div>
      }
    </div>
  </div>
</div>
<p class="mt-3 text-sm text-muted">
  Selected: {{ controlledSelected().join(', ') || 'none' }}
</p>`,
})
export class ListBoxControlledSelectionDemo {
  readonly controlledSelected = signal<string[]>(['1']);
  readonly users = [
  {
    "id": "1",
    "name": "Bob",
    "email": "[email protected]",
    "avatar": "/images/gradients/gradient-blue-cyan.png",
    "fallback": "B"
  },
  {
    "id": "2",
    "name": "Fred",
    "email": "[email protected]",
    "avatar": "/images/gradients/gradient-cyan-blue-purple.png",
    "fallback": "F"
  },
  {
    "id": "3",
    "name": "Martha",
    "email": "[email protected]",
    "avatar": "/images/gradients/gradient-purple-violet.png",
    "fallback": "M"
  }
];

  selectAllUsers(): void {
    this.controlledSelected.set(this.users.map((user) => user.id));
  }

  clearSelection(): void {
    this.controlledSelected.set([]);
  }
}

Custom Check Icon

Project custom content into av-list-box-item-indicator to replace the default checkmark. The indicator host is shown only when the item is selected.

import { Component, signal } from '@angular/core';
import {
  AvAvatarImports,
  AvDescriptionComponent,
  AvLabelComponent,
  AvListBoxImports,
  AvSurfaceComponent,
} from '@avesra/angular';

@Component({
  selector: 'app-list-box-custom-check-icon-demo',
  imports: [
    AvSurfaceComponent,
    AvListBoxImports,
    AvLabelComponent,
    AvDescriptionComponent,
    AvAvatarImports,
  ],
  template: `<div av-surface class="w-64 rounded-3xl shadow-surface">
  <div
    av-list-box
    aria-label="Users"
    selection-mode="multiple"
    [(selectedKeys)]="customCheckSelected"
    class="w-full"
  >
    @for (user of users; track user.id) {
      <div av-list-box-item [id]="user.id" [textValue]="user.name">
        <span av-avatar size="sm">
          <img av-avatar-image [alt]="user.name" [src]="user.avatar" />
          <span av-avatar-fallback>{{ user.fallback }}</span>
        </span>
        <div class="flex flex-col">
          <label av-label>{{ user.name }}</label>
          <p av-description>{{ user.email }}</p>
        </div>
        <span av-list-box-item-indicator>
          <svg class="size-4 text-accent" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
            <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.75.75 0 0 1 1.06-1.06L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z" />
          </svg>
        </span>
      </div>
    }
  </div>
</div>
<p class="mt-3 text-sm text-muted">Selected: {{ customCheckSelected().join(', ') || 'none' }}</p>`,
})
export class ListBoxCustomCheckIconDemo {
  readonly customCheckSelected = signal<string[]>(['1', '2']);
  readonly users = [
  {
    "id": "1",
    "name": "Bob",
    "email": "[email protected]",
    "avatar": "/images/gradients/gradient-blue-cyan.png",
    "fallback": "B"
  },
  {
    "id": "2",
    "name": "Fred",
    "email": "[email protected]",
    "avatar": "/images/gradients/gradient-cyan-blue-purple.png",
    "fallback": "F"
  },
  {
    "id": "3",
    "name": "Martha",
    "email": "[email protected]",
    "avatar": "/images/gradients/gradient-purple-violet.png",
    "fallback": "M"
  }
];
}

Styling

Passing Tailwind CSS classes

Pass utility classes on the av-list-box and av-list-box-item hosts.

import { Component, signal } from '@angular/core';
import {
  AvLabelComponent,
  AvListBoxImports,
} from '@avesra/angular';

@Component({
  selector: 'app-list-box-custom-styling-demo',
  imports: [
    AvListBoxImports,
    AvLabelComponent,
  ],
  template: `<div
  av-list-box
  aria-label="Options"
  selection-mode="single"
  [(selectedKeys)]="selected"
  class="w-56 rounded-lg border border-border bg-surface p-2"
>
  <div
    av-list-box-item
    id="1"
    textValue="Item 1"
    class="hover:bg-surface-secondary"
  >
    <label av-label>Item 1</label>
    <span av-list-box-item-indicator></span>
  </div>
  <div
    av-list-box-item
    id="2"
    textValue="Item 2"
    class="hover:bg-surface-secondary"
  >
    <label av-label>Item 2</label>
    <span av-list-box-item-indicator></span>
  </div>
</div>`,
})
export class ListBoxCustomStylingDemo {
  readonly selected = signal<string[]>(['1']);
}

Customizing the component classes

To customize the List Box classes, use the @layer components directive. Learn more.

@layer components {
  .av-list-box {
    @apply rounded-lg border border-border bg-surface p-2;
  }

  .av-list-box-item {
    @apply rounded px-2 py-1 cursor-pointer;
  }

  .av-list-box-item--danger {
    @apply text-danger;
  }

  .av-list-box-item__indicator {
    @apply text-accent;
  }
}

Avesra follows the BEM methodology so component variants and states stay reusable and easy to customize.

CSS Classes

The List Box component uses these CSS classes:

Base Classes

  • .av-list-box — Base listbox container
  • .av-list-box-item — Individual listbox item
  • .av-list-box-item__indicator — Selection indicator
  • .av-list-box-section — Section group (role="group")

Variant Classes

  • .av-list-box-item--danger — Danger item variant

State Classes

  • .av-list-box-item[data-selected="true"] — Selected item state
  • .av-list-box-item[data-focus-visible="true"] — Focused item state
  • .av-list-box-item[data-disabled="true"] — Disabled item state
  • .av-list-box-item__indicator[data-visible="true"] — Visible indicator state

Interactive States

The component supports both CSS pseudo-classes and data attributes:

  • Hover::hover or [data-hovered="true"] on item
  • Pressed::active or [data-pressed="true"] on item
  • Focus::focus-visible or [data-focus-visible="true"] on item
  • Selected:[data-selected="true"] on item
  • Disabled:[data-disabled="true"] on item

Examples

Basic Usage

<div
  av-list-box
  aria-label="Users"
  selection-mode="single"
  [(selectedKeys)]="selected"
>
  <div av-list-box-item id="1" textValue="Bob">
    <label av-label>Bob</label>
    <p av-description>[email protected]</p>
    <span av-list-box-item-indicator></span>
  </div>
  <div av-list-box-item id="2" textValue="Alice">
    <label av-label>Alice</label>
    <p av-description>[email protected]</p>
    <span av-list-box-item-indicator></span>
  </div>
</div>

With Sections

<div
  av-list-box
  aria-label="Actions"
  selection-mode="none"
  (action)="onAction($event)"
>
  <div av-list-box-section>
    <p class="px-2.5 py-1 text-xs font-medium text-muted">Actions</p>
    <div av-list-box-item id="new" textValue="New file">
      <label av-label>New file</label>
    </div>
    <div av-list-box-item id="edit" textValue="Edit file">
      <label av-label>Edit file</label>
    </div>
  </div>
  <div av-separator></div>
  <div av-list-box-section>
    <p class="px-2.5 py-1 text-xs font-medium text-muted">Danger zone</p>
    <div av-list-box-item id="delete" textValue="Delete" variant="danger">
      <label av-label>Delete</label>
    </div>
  </div>
</div>

Controlled Selection

import { Component, signal } from '@angular/core';
import {
  AvListBoxComponent,
  AvListBoxItemComponent,
  AvListBoxItemIndicatorComponent,
} from '@avesra/angular';

@Component({
  selector: 'app-controlled-list-box',
  imports: [AvListBoxComponent, AvListBoxItemComponent, AvListBoxItemIndicatorComponent],
  template: `
    <div
      av-list-box
      aria-label="Options"
      selection-mode="multiple"
      [(selectedKeys)]="selected"
    >
      <div av-list-box-item id="1" textValue="Option 1">
        Option 1
        <span av-list-box-item-indicator></span>
      </div>
      <div av-list-box-item id="2" textValue="Option 2">
        Option 2
        <span av-list-box-item-indicator></span>
      </div>
      <div av-list-box-item id="3" textValue="Option 3">
        Option 3
        <span av-list-box-item-indicator></span>
      </div>
    </div>
  `,
})
export class ControlledListBox {
  readonly selected = signal<string[]>(['1']);
}

Custom Indicator

<div
  av-list-box
  aria-label="Options"
  selection-mode="multiple"
  [(selectedKeys)]="selected"
>
  <div av-list-box-item id="1" textValue="Option 1">
    Option 1
    <span av-list-box-item-indicator>
      <!-- Projected content replaces the default checkmark -->
      <svg class="size-4 text-accent" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
        <path
          d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.75.75 0 0 1 1.06-1.06L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"
        />
      </svg>
    </span>
  </div>
</div>

Accessibility

List Box implements the ARIA listbox pattern via Angular CDK and provides:

  • Full keyboard navigation (arrow keys, Home/End, Enter/Space)
  • Typeahead search using each item's textValue
  • Screen reader announcements for selection changes
  • Proper focus management and disabled item skipping
  • Section containers expose role="group"; indicators are aria-hidden

Always set aria-label on the listbox when there is no visible label. Prefer textValue on items that contain icons or complex content.

API

Props for div[av-list-box] and div[av-list-box-item]. span[av-list-box-item-indicator] has no inputs — omit children for the default checkmark, or project a custom icon. div[av-list-box-section] has no inputs.

PropTypeDefaultDescription
aria-labelstring—Accessibility label for the listbox (av-list-box).
selection-mode'none' | 'single' | 'multiple''single'Selection behavior. Use none with (action) for action menus (av-list-box).
selectedKeysstring[][]Controlled selected item ids. Supports two-way binding with [(selectedKeys)] (av-list-box).
disabledbooleanfalseDisables all listbox items (av-list-box).
actionOutputEmitterRef<string>—Emits the item id when activated in selection-mode="none" (av-list-box).
idstring—Required unique item id (av-list-box-item).
textValuestring—Text value for accessibility and typeahead search (av-list-box-item).
variant'default' | 'danger''default'Visual variant for the item (av-list-box-item).
disabledbooleanfalseWhether this item is disabled (av-list-box-item).

Made with ❤ by SyntaxHertz. Open source and available on GitHub.