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 | 포커스된 항목의 열림 상태 토글 |