심화 가이드
접근성 지원

아코디언

개요

아코디언은 관련 콘텐츠를 펼치고 접을 수 있는 섹션으로 구성합니다. 페이지 스크롤을 줄이고 사용자가 필요한 정보에 집중하도록 돕습니다. 각 섹션은 트리거 버튼과 콘텐츠 패널로 구성되며, 트리거를 클릭하면 연결된 패널을 표시하거나 숨깁니다.

사용법

아코디언은 콘텐츠를 논리적인 그룹으로 나누고, 사용자가 대체로 한 번에 하나의 섹션을 확인하는 경우에 적합합니다.

아코디언을 사용하기 좋은 경우:

  • 여러 질문과 답변으로 구성된 FAQ를 표시할 때
  • 긴 폼을 다루기 쉬운 섹션으로 나눌 때
  • 콘텐츠가 많은 페이지에서 스크롤을 줄일 때
  • 관련 정보를 단계적으로 공개할 때

아코디언을 피해야 하는 경우:

  • 탐색 메뉴를 만들 때(메뉴 컴포넌트를 사용하세요)
  • 탭 인터페이스를 만들 때(탭 컴포넌트를 사용하세요)
  • 접을 수 있는 섹션을 하나만 표시할 때(펼침/접기 패턴을 사용하세요)
  • 사용자가 여러 섹션을 동시에 확인해야 할 때(다른 레이아웃을 고려하세요)

주요 기능

  • 펼침 모드: 한 번에 하나의 패널만 열거나 여러 패널을 열도록 제어합니다.
  • 키보드 탐색: 방향키, Home, End로 트리거 사이를 이동합니다.
  • 지연 렌더링: 패널을 펼칠 때만 콘텐츠를 생성해서 초기 로딩 성능을 개선합니다.
  • 비활성화 상태: 전체 그룹이나 개별 트리거를 비활성화합니다.
  • 포커스 관리: 비활성화된 항목이 키보드 포커스를 받을 수 있는지 제어합니다.
  • 코드로 제어: 컴포넌트 코드에서 패널을 펼치거나 접고, 펼침 상태를 전환합니다.
  • RTL 지원: 오른쪽에서 왼쪽으로 쓰는 언어를 자동으로 지원합니다.

예제

단일 펼침 모드

[multiExpandable]="false"로 설정하면 한 번에 하나의 패널만 열 수 있습니다. 새 패널을 열면 이전에 열려 있던 패널은 자동으로 닫힙니다.

이 모드는 FAQ나 사용자가 한 번에 하나의 답변에 집중하도록 할 때 적합합니다.

다중 펼침 모드

[multiExpandable]="true"로 설정하면 여러 패널을 동시에 열 수 있습니다. 사용자는 다른 패널을 닫지 않고 필요한 만큼 패널을 펼칠 수 있습니다.

이 모드는 폼의 섹션이나 여러 패널의 콘텐츠를 비교해야 하는 경우에 유용합니다.

NOTE: multiExpandable 입력 프로퍼티의 기본값은 true입니다. 한 번에 하나의 패널만 펼치려면 명시적으로 false로 설정하세요.

비활성화된 아코디언 항목

disabled 입력 프로퍼티로 특정 트리거를 비활성화할 수 있습니다. 키보드 탐색 중 비활성화된 항목의 동작은 아코디언 그룹의 softDisabled 입력 프로퍼티로 제어합니다.

[softDisabled]="true"(기본값)이면 비활성화된 항목도 포커스를 받을 수 있지만 활성화할 수는 없습니다. [softDisabled]="false"이면 키보드 탐색에서 비활성화된 항목을 완전히 건너뜁니다.

콘텐츠 지연 렌더링

ng-template에 ngAccordionContent 디렉티브를 적용하면 패널을 펼칠 때까지 콘텐츠 렌더링을 미룰 수 있습니다. 이미지, 차트, 복잡한 컴포넌트처럼 처리 비용이 큰 콘텐츠를 포함한 아코디언의 성능을 개선할 수 있습니다.

<div ngAccordionGroup>
  <div>
    <button ngAccordionTrigger [panel]="panel1">Trigger Text</button>
    <div ngAccordionPanel #panel1="ngAccordionPanel">
      <ng-template ngAccordionContent>
        <!-- 이 콘텐츠는 패널을 열 때만 렌더링됩니다. -->
        <img src="large-image.jpg" alt="Description" />
        <app-expensive-component />
      </ng-template>
    </div>
  </div>
</div>

기본적으로 패널을 접으면 콘텐츠가 DOM에서 제거됩니다. 예를 들어 패널을 접어도 초기화되지 않아야 하는 동영상이 있다면, [preserveContent]="true"로 설정해서 콘텐츠를 유지하세요.

테스트

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

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

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

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

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

  it('should allow expanding panels', async () => {
    // 아코디언 그룹 하네스를 불러옵니다.
    const group = await loader.getHarness(AccordionGroupHarness);

    // 그룹에 있는 모든 개별 아코디언(항목)을 가져옵니다.
    const accordions = await group.getAccordions();
    expect(accordions.length).toBe(3);

    // 초기 상태를 확인합니다(첫 번째 패널은 펼쳐지고 나머지는 접힌 상태).
    expect(await accordions[0].isExpanded()).toBe(true);
    expect(await accordions[1].isExpanded()).toBe(false);

    // 두 번째 패널을 펼칩니다.
    await accordions[1].expand();

    // 변경된 상태를 확인합니다.
    expect(await accordions[1].isExpanded()).toBe(true);
    // multiExpandable이 false이면 이제 첫 번째 패널은 접혀 있어야 합니다.
    expect(await accordions[0].isExpanded()).toBe(false);
  });
});

API 레퍼런스

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