Accordion

Accordion

콘텐츠를 접을 수 있는 섹션으로 나누는 컴포넌트예요. 사용자가 콘텐츠 섹션을 펼치고 접을 수 있게 해주며, 제한된 공간에서 많은 정보를 관리하는 데 도움을 줘요.

출처: 문서

본문

Usage

Accordion은 사용자가 콘텐츠 섹션을 펼치고 접을 수 있게 해줘요. 처음에는 섹션 헤더만 보여주고 상호작용 시 콘텐츠를 드러냄으로써 제한된 공간에서 많은 양의 정보를 관리하는 데 도움을 줘요.

Accordion은 주로 이렇게 쓰여요:

  • FAQ 섹션: 질문을 헤더로 표시하고 클릭 시 답변 공개
  • 폼: 긴 폼을 개인 정보, 배송, 결제 같은 섹션으로 정리
  • 메뉴: 사이드바나 모바일 뷰의 중첩 네비게이션
import { Accordion } from '@mantine/core';
import { data } from './data';

function Demo() {
  const items = data.map((item) => (
    <Accordion.Item key={item.value} value={item.value}>
      <Accordion.Control>{item.value}</Accordion.Control>
      <Accordion.Panel>{item.description}</Accordion.Panel>
    </Accordion.Item>
  ));

  return (
    <Accordion defaultValue="Apples" order={3}>
      {items}
    </Accordion>
  );
}

order prop

(이 페이지의 모든 데모에서 쓰이는) order prop은 Accordion.Control 루트 요소의 제목 레벨을 설정해요. WAI-ARIA 권장사항에 따르면 페이지 개요(outline)에 맞게 h2–h6 제목 레벨을 사용해야 해요.

이 페이지의 모든 예시는 order={3}을 사용해요. 즉 모든 Accordion.Control의 button 요소가 h3 태그로 감싸진다는 뜻이에요(h2 태그는 문서 섹션에 사용돼요).

order prop은 라이브러리에서 강제하지 않지만, 애플리케이션이 접근성 표준을 충족해야 한다면 필요해요.

Change chevron

chevron prop으로 chevron 아이콘을 바꿀 수 있어요. chevron이 설정되면 chevronIconSize prop은 무시돼요. chevron 아이콘을 제거하려면 chevron={null}을 사용하세요.

chevron 스타일을 커스터마이즈하려면 data-rotate 속성과 함께 Styles API를 사용하세요. 이 속성은 disableChevronRotation prop이 설정되지 않았을 때 항목이 열리면 설정돼요.

Custom control label

Accordion.Control 컴포넌트의 라벨로 어떤 React 노드든 사용할 수 있어요. Accordion.Control에 중첩 요소를 사용할 때는 스크린 리더가 접근할 수 있도록 aria-label 속성을 설정하는 것이 권장돼요.

With icons

icon prop으로 Accordion.Control의 왼쪽 섹션에 어떤 요소든 표시할 수 있어요.

Change transition

트랜지션 지속 시간을 바꾸려면 transitionDuration prop을 설정하세요. 트랜지션을 비활성화하려면 transitionDuration을 0으로 설정하세요.

import { Accordion } from '@mantine/core';

function Demo() {
  return (
    <Accordion transitionDuration={200}>
      {/* ...content */}
    </Accordion>
  )
}

Default opened items

multiple={false}일 때는 defaultValue를 문자열로 설정하세요.

import { Accordion } from '@mantine/core';

function Demo() {
  // Second item will be opened by default
  return (
    <Accordion defaultValue="item-2">
      <Accordion.Item value="item-1">{/* item-1 */}</Accordion.Item>
      <Accordion.Item value="item-2">{/* item-2 */}</Accordion.Item>
    </Accordion>
  );
}

multiple={true}일 때는 defaultValue를 문자열 배열로 설정하세요.

import { Accordion } from '@mantine/core';

function Demo() {
  // Both items are opened by default
  return (
    <Accordion multiple defaultValue={['item-1', 'item-2']}>
      <Accordion.Item value="item-1">{/* item-1 */}</Accordion.Item>
      <Accordion.Item value="item-2">{/* item-2 */}</Accordion.Item>
    </Accordion>
  );
}

Control opened state

multiple={false}일 때는 value를 문자열로 설정하세요.

import { useState } from 'react';
import { Accordion } from '@mantine/core';

function Demo() {
  const [value, setValue] = useState<string | null>(null);

  return (
    <Accordion value={value} onChange={setValue}>
      <Accordion.Item value="item-1">{/* item-1 */}</Accordion.Item>
      <Accordion.Item value="item-2">{/* item-2 */}</Accordion.Item>
    </Accordion>
  );
}

multiple={true}일 때는 value를 문자열 배열로 설정하세요.

import { useState } from 'react';
import { Accordion } from '@mantine/core';

function Demo() {
  const [value, setValue] = useState<string[]>([]);

  return (
    <Accordion multiple value={value} onChange={setValue}>
      <Accordion.Item value="item-1">{/* item-1 */}</Accordion.Item>
      <Accordion.Item value="item-2">{/* item-2 */}</Accordion.Item>
    </Accordion>
  );
}

Disable collapse

기본적으로 단일 모드(multiple={false})에서는 열린 항목을 항상 닫을 수 있어서 Accordion이 완전히 접힌 상태가 될 수 있어요. disableCollapse prop을 설정하면 이를 방지할 수 있어요. 항목이 열리면 컨트롤을 다시 클릭해도 아무 일도 일어나지 않고, 상태를 바꾸는 유일한 방법은 다른 항목을 열는 것이에요. 설정 패널, 스테퍼 방식 흐름, FAQ 페이지처럼 한 섹션이 항상 보이도록 유지하고 싶을 때 유용해요.

disableCollapse는 이미 열린 항목을 접을 수 없게 할 뿐 마운트 시 항목을 강제로 열지는 않아요. 처음부터 항목 하나가 열려 있게 하려면 defaultValue(비제어) 또는 value(제어)와 함께 사용하세요.

multiple이 설정되면 이 prop은 효과가 없어요. 다중 모드에서는 이미 열림/닫힘 조합이 자유롭기 때문이에요.

Compose controls

Accordion.Control 안에 버튼이나 링크를 넣는 것은 Accordion을 사용할 때 흔한 실수예요. Accordion.Control 루트 요소는 button이에요. 다른 상호작용 요소 안에 상호작용 요소를 넣는 것은 금지돼요. 다음 컴포넌트를 구현하려 하면 React에서 DOM 검증 오류가 발생해요.

import { Accordion } from '@mantine/core';

// ❌ Incorrect usage: do not do this
function Demo() {
  return (
    <Accordion>
      <Accordion.Item value="item-1">
        <Accordion.Control>
          Control 1
          <button type="button">My action</button>
        </Accordion.Control>
        <Accordion.Panel>Panel 1</Accordion.Panel>
      </Accordion.Item>
    </Accordion>
  );
}

상호작용 요소를 Accordion.Control 안에 넣는 대신 그 옆에 렌더링하세요. 예를 들어 원래 컨트롤의 오른쪽에 ActionIcon이나 Menu를 추가할 수 있어요. Accordion.Control 위에 상호작용 요소를 표시해야 한다면 대신 position: absolute를 사용하세요.

Disabled items

Accordion.Control 컴포넌트에 disabled prop을 설정해 비활성화할 수 있어요. 항목을 비활성화하면 마우스나 키보드로 활성화할 수 없고, 화살표 키 탐색에서도 건너뛰어요.

Unstyled Accordion

Accordion 컴포넌트에 unstyled prop을 설정하면 필수적이지 않은 라이브러리 스타일을 모두 제거해요. 어떤 스타일도 재정의하지 않고 Styles API로 컴포넌트를 스타일링할 때 unstyled prop을 사용하세요.

Styles API

Accordion은 Styles API를 지원해요. classNames prop으로 컴포넌트의 어떤 내부 요소든 스타일을 추가할 수 있어요.

Styles API로 Accordion 스타일을 커스터마이즈하는 예시예요.

TypeScript

@mantine/core에서 내보낸 AccordionProps 타입은 multiple 상태를 설명하는 boolean 타입을 받는 제네릭이에요.

import type { AccordionProps } from '@mantine/core';

type MultipleAccordionProps = AccordionProps<true>;
type DefaultAccordionProps = AccordionProps<false>;

Accessibility

Accordion 컴포넌트는 WAI-ARIA 접근성 패턴을 구현해요.

Keyboard interactions

Key Description
ArrowDown 다음 항목으로 포커스 이동
ArrowUp 이전 항목으로 포커스 이동
Home 첫 번째 항목으로 포커스 이동
End 마지막 항목으로 포커스 이동
Space/Enter 포커스된 항목의 열림 상태 토글

더 알아보기 (Learn more)