심화 가이드
접근성 지원

메뉴바

개요

메뉴바는 애플리케이션 메뉴에 항상 접근할 수 있도록 제공하는 수평 탐색 막대입니다. 메뉴바는 명령을 File, Edit, View와 같은 논리적인 범주로 나눕니다. 사용자는 키보드나 마우스로 애플리케이션 기능을 찾고 실행할 수 있습니다.

사용법

메뉴바는 애플리케이션 명령을 항상 표시되고 쉽게 찾을 수 있는 탐색 구조로 구성할 때 적합합니다.

메뉴바를 사용하기 좋은 경우:

  • 애플리케이션 명령 막대(File, Edit, View, Insert, Format 등)를 만들 때
  • 인터페이스에서 항상 표시되는 탐색 기능을 만들 때
  • 명령을 논리적인 최상위 범주로 구성할 때
  • 키보드를 지원하는 수평 메뉴 탐색이 필요할 때
  • 데스크탑 스타일의 애플리케이션 인터페이스를 만들 때

메뉴바를 피해야 하는 경우:

  • 개별 작업의 드롭다운 메뉴를 만들 때(트리거가 있는 메뉴를 사용하세요)
  • 컨텍스트 메뉴를 만들 때(메뉴 가이드의 패턴을 사용하세요)
  • 간단한 독립형 작업 목록을 만들 때(메뉴를 사용하세요)
  • 가로 공간이 제한된 모바일 인터페이스
  • 사이드바나 헤더 탐색 패턴에 배치하는 것이 적합한 탐색 기능

주요 기능

  • 수평 탐색: 왼쪽/오른쪽 방향키로 최상위 범주 사이를 이동합니다.
  • 항상 표시: 모달이 아니며 닫을 수 없고 항상 표시됩니다.
  • 마우스를 올려 열기: 처음 키보드로 조작하거나 클릭한 뒤에는 마우스를 올리면 하위 메뉴가 열립니다.
  • 중첩 하위 메뉴: 여러 단계 깊이의 메뉴를 지원합니다.
  • 키보드 탐색: 방향키, Enter/Space, Escape, 문자 입력 검색을 지원합니다.
  • 비활성화 상태: 전체 메뉴바나 개별 항목을 비활성화합니다.
  • RTL 지원: 오른쪽에서 왼쪽으로 쓰는 언어의 탐색을 자동으로 지원합니다.

예제

기본 메뉴바

메뉴바는 최상위 범주로 구성된 애플리케이션 명령에 항상 접근할 수 있도록 합니다. 사용자는 왼쪽/오른쪽 방향키로 범주 사이를 이동하고 Enter나 아래 방향키로 메뉴를 엽니다.

오른쪽 방향키를 눌러 File, Edit, View 사이를 이동하세요. Enter나 아래 방향키로 메뉴를 열고, 위/아래 방향키로 하위 메뉴 항목을 탐색하세요.

비활성화된 메뉴바 항목

특정 메뉴 항목이나 전체 메뉴바를 비활성화해서 조작을 막을 수 있습니다. 비활성화된 항목이 키보드 포커스를 받을 수 있는지는 softDisabled 입력 프로퍼티로 제어합니다.

메뉴바의 [softDisabled]="true"이면 비활성화된 항목도 포커스를 받을 수 있지만 활성화할 수는 없습니다. [softDisabled]="false"이면 키보드 탐색에서 비활성화된 항목을 건너뜁니다.

RTL 지원

메뉴바는 오른쪽에서 왼쪽으로 쓰는 언어(RTL)에 자동으로 대응합니다. 방향키 탐색 방향이 반대로 바뀌고 하위 메뉴는 왼쪽에 배치됩니다.

dir="rtl" 어트리뷰트로 RTL 모드를 활성화합니다. 왼쪽 방향키는 오른쪽으로, 오른쪽 방향키는 왼쪽으로 이동해서 RTL 언어 사용자에게 자연스러운 탐색을 제공합니다.

테스트

Angular Aria는 메뉴바 컴포넌트를 테스트할 수 있는 컴포넌트 하네스를 제공합니다. 컴포넌트 테스트에서 하네스를 사용하는 예제는 다음과 같습니다.

import {ComponentFixture, TestBed} from '@angular/core/testing';
import {HarnessLoader} from '@angular/cdk/testing';
import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed';
import {MenuHarness} from '@angular/aria/menu/testing';
import {MyMenubarComponent} from './my-menubar'; // 테스트할 컴포넌트

describe('MyMenubarComponent', () => {
  let fixture: ComponentFixture<MyMenubarComponent>;
  let loader: HarnessLoader;

  beforeEach(async () => {
    TestBed.configureTestingModule({
      imports: [MyMenubarComponent],
    });

    fixture = TestBed.createComponent(MyMenubarComponent);
    await fixture.whenStable();
    loader = TestbedHarnessEnvironment.loader(fixture);
  });

  it('should interact with menubar items', async () => {
    // 메뉴바 하네스를 불러옵니다(선택자가 '[ngMenuBar]'인 MenuHarness입니다).
    const menubar = await loader.getHarness(MenuHarness.with({selector: '[ngMenuBar]'}));

    // 메뉴바는 항상 표시되며 언제나 "열린" 상태입니다.
    expect(await menubar.isOpen()).toBe(true);
    expect(await menubar.isMenuBar()).toBe(true);

    // 최상위 항목을 가져옵니다.
    const items = await menubar.getItems();
    expect(items.length).toBe(2);
    expect(await items[0].getText()).toBe('File');
    expect(await items[1].getText()).toBe('Edit');

    // 항목을 클릭해서 드롭다운 메뉴를 엽니다.
    await items[0].click();

    const fileMenu = await items[0].getSubmenu();
    expect(fileMenu).toBeTruthy();
    expect(await fileMenu!.isOpen()).toBe(true);
  });
});

API 레퍼런스

자세한 API 문서는 다음 API 레퍼런스를 참고하세요.