Skip to content

feat(aria/toolbar): Support Select/Comboboxes in the toolbar #33684

Description

@PhilippMDoerner

Feature Description

The toolbar currently does not support <select> tags or other forms of comboboxes, despite the WCAG pattern allowing for one.

I tried with this dummy component and it makes opening the select tag impossible and blocks and keyboard navigation native to the select tag.

Example:

import {
  Toolbar,
  ToolbarWidget,
  ToolbarWidgetGroup,
} from '@angular/aria/toolbar';
import { Component, signal } from '@angular/core';

@Component({
  selector: 'app-formatting-toolbar',
  standalone: true,
  imports: [Toolbar, ToolbarWidget, ToolbarWidgetGroup],
  template: `
    <div ngToolbar aria-label="Text formatting toolbar" class="toolbar">
      <div
        ngToolbarWidgetGroup
        role="group"
        aria-label="Text style"
        class="group"
      >
        <button
          ngToolbarWidget
          value="bold"
          type="button"
          class="tb-btn"
          aria-label="Bold"
        >
          <strong>B</strong>
        </button>
        <button
          ngToolbarWidget
          value="italic"
          type="button"
          class="tb-btn"
          aria-label="Italic"
        >
          <em>I</em>
        </button>
      </div>

      <div
        class="tb-divider"
        role="separator"
        aria-orientation="vertical"
      ></div>

      <select
        ngToolbarWidget
        value="14"
        class="tb-select"
        id="font-size"
        aria-label="Font size"
        (change)="onFontSizeChange($event)"
      >
        <option value="12">12px</option>
        <option value="14" selected>14px</option>
        <option value="16">16px</option>
        <option value="20">20px</option>
      </select>

      <div
        class="tb-divider"
        role="separator"
        aria-orientation="vertical"
      ></div>

      <!-- Spinbutton: decrement / native number input / increment -->
      <div class="spin" role="presentation">
        <input
          ngToolbarWidget
          type="number"
          [value]="2"
          class="tb-spin-input"
          aria-label="Line spacing"
          [min]="minSpacing"
          [max]="maxSpacing"
          [step]="stepSize"
          [value]="lineSpacing()"
          (input)="onSpacingInput($event)"
        />
      </div>
    </div>
  `,
})
export class FormattingToolbarComponent {
  readonly minSpacing = 1;
  readonly maxSpacing = 3;
  readonly stepSize = 0.5;

  lineSpacing = signal(1.5);

  onFontSizeChange(event: Event): void {
    const value = (event.target as HTMLSelectElement).value;
    console.log('font-size changed to', value);
  }

  step(delta: number): void {
    const next = this.clamp(this.lineSpacing() + delta);
    this.lineSpacing.set(next);
  }

  onSpacingInput(event: Event): void {
    const raw = (event.target as HTMLInputElement).valueAsNumber;
    if (!Number.isNaN(raw)) {
      this.lineSpacing.set(this.clamp(raw));
    }
  }

  private clamp(value: number): number {
    return Math.min(this.maxSpacing, Math.max(this.minSpacing, value));
  }
}

Expected behavior:

  • When clicking on or pressing enter/space on a select tag or trigger of a custom combobox implementation it should open the associated listbox with options in a popup
  • You should be able to use the arrow keys not used for toolbar navigation to have the usual select/combobox behavior
  • Selecting an option should function as normal and emit the selected option as the new value of the toolbar

Note: Spinbuttons (basically just ) are similarly non-functional as their keyboard and mouse interaction gets blocked same as for select.

Use Case

Toolbars for rich text editors, notably for selecting font-size or the text-tag, see Screenshot:

Image

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3An issue that is relevant to core functions, but does not impede progress. Important, but not urgentarea: aria/toolbarfeatureLabel used to distinguish feature request from other issues

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions