Chart
먼저 보고, 그다음 계약을 읽습니다
recharts 를 axe 토큰으로 감싼 얇은 wrapper — LineChart · BarChart · AreaChart 3종이 동일한 data/xKey/series API 를 공유.
Component intent의도와 경계 읽기
recharts 는 강력하지만 컬러·축·grid 기본값이 우리 토큰과 충돌한다. 본 wrapper 는 series 색을 semantic 팔레트(accent → success → warning → danger → info)로 순환 배정하고, 축·grid·tooltip 을 CSS 변수로 묶어 light/dark 를 자동 처리한다. 세 컴포넌트 모두 data(레코드 배열) + xKey(x축 key) + series(그릴 계열) 형태로 호출하며, height 미지정 시 240px 다. prefers-reduced-motion 이 걸리면 애니메이션을 끄고, 데이터가 비면 EmptyState 로 대체한다. 변형: BarChart 에 stacked, AreaChart 에 gradient, series 항목에 dashed(예측 계열 점선). recharts 가 raw ~395KB 라 대시보드 첫 페인트 번들에서는 LazyCharts 변형을 권장한다.
예제
SSOT에 등록된 실제 API 기준 snippet입니다. standalone 배지만 독립 실행 단위이며, fragment는 주변 state·handler 문맥을 생략합니다.
import { LineChart } from "@axe/ui";const data = [ { month: "1월", actual: 120, forecast: 120 }, { month: "2월", actual: 138, forecast: 135 }, { month: "3월", actual: 152, forecast: 150 },];<LineChart data={data} xKey="month" series={[ { key: "actual", label: "실적" }, { key: "forecast", label: "예측", dashed: true }, ]} height={280} ariaLabel="월별 실적 대비 예측 추이"/>import { BarChart } from "@axe/ui";<BarChart data={[ { quarter: "Q1", direct: 40, channel: 24 }, { quarter: "Q2", direct: 52, channel: 30 }, ]} xKey="quarter" series={[ { key: "direct", label: "직접" }, { key: "channel", label: "채널" }, ]} stacked ariaLabel="분기별 채널 매출 구성"/>import { AreaChart } from "@axe/ui";<> <AreaChart data={aum} xKey="date" series={[{ key: "value", label: "AUM", color: "var(--accent)" }]} ariaLabel="일별 운용자산(AUM) 추이" ariaDescribedBy="aum-table" onPointClick={(p) => console.log(p)} /> {/* 색 그래프에 도달 못 하는 SR·키보드 사용자를 위한 동일 데이터 표 */} <table id="aum-table" className="axe-sr-only"> <caption>일별 운용자산</caption> <tbody> {aum.map((r) => ( <tr key={r.date}> <th scope="row">{r.date}</th> <td>{r.value}</td> </tr> ))} </tbody> </table></>Props
TSX 소스가 진실입니다. 주요 export 컴포넌트의 public API만 노출합니다.
| 이름 | 타입 | 필수 | 기본값 | 설명 |
|---|---|---|---|---|
data | Datum[] | 필수 | — | 레코드 배열. 각 원소는 x축 라벨(data[i][xKey])과 series 별 y값을 담는다. 빈 배열이면 EmptyState("데이터 없음")로 대체. |
xKey | string | 필수 | — | x축으로 쓸 key. data[i][xKey] 값이 카테고리 축 라벨. |
series | ChartSeries[] | 필수 | — | 그릴 계열 목록. 각 ChartSeries = { key: string(=data 의 y값 key), label?: string(범례/tooltip 표시명, 미지정 시 key), color?: string(미지정 시 semantic 팔레트 순환), dashed?: boolean(Line/Area 점선 — 예측 계열 등) }. |
height | number | — | 240 | 차트 컨테이너 높이(px). ResponsiveContainer 가 width 100% 를 채우므로 높이는 명시 권장. |
showLegend | boolean | — | — | 범례 표시. 미지정 시 series 가 2개 이상이면 자동 표시(series.length > 1). |
showGrid | boolean | — | true | CartesianGrid(점선 3 3) 표시. |
onPointClick | (point: Datum) => void | — | — | point/bar 클릭 콜백. 클릭된 activeTooltipIndex 의 data 원소를 그대로 넘긴다. 마우스 전용 — 키보드로는 도달 불가(a11y 참고). |
animate | boolean | — | — | recharts 진입 애니메이션. 미지정 시 prefers-reduced-motion: reduce 면 자동 false, 아니면 true. |
ariaLabel | string | — | — | role="img" 컨테이너의 aria-label — SR 사용자가 차트가 무엇인지 파악. 미지정 시 `"{n}-series chart"` 라는 무의미한 fallback 이 붙으므로 사실상 필수. |
ariaDescribedBy | string | — | — | 확장 설명 요소의 id(보통 화면에 숨긴 데이터 표 대체). 실제 수치를 SR·키보드 사용자에게 전달하는 채널. |
className | string | — | — | 루트 .axe-chart div 에 병합. |
stacked | boolean | — | false | [BarChart 전용] bar 를 누적(stack). false 면 group 배치 + 상단 모서리 라운드(3px). |
gradient | boolean | — | true | [AreaChart 전용] 영역 fill 에 linearGradient(0%→35% / 100%→2%) 적용. false 면 단색 fill(opacity 0.25). |
.axe-* 클래스 계약
React 밖에서도 같은 표면을 그리는 공개 계약입니다. stable은 minor 버전 안에서 이름을 바꾸지 않습니다.
| 클래스 | 안정성 | 용도 |
|---|---|---|
.axe-chart | stable | 루트 컨테이너 div — width 100% + height 지정자, text-primary. recharts SVG 를 감싼다. |
.axe-chart__tooltip | stable | 커스텀 tooltip 컨테이너(bg-elevated · border-subtle · shadow). recharts 기본 tooltip 대체. |
.axe-chart__tooltip-label | stable | tooltip 상단 x축 라벨(하단 border 구분선). |
.axe-chart__tooltip-list | stable | tooltip 내 계열 행 목록(flex column). |
.axe-chart__tooltip-row | stable | 계열 1개 행 — swatch · name · value 3열 grid. |
.axe-chart__tooltip-swatch | stable | 계열 색 표시 정사각 칩(10px, aria-hidden). |
.axe-chart__tooltip-name | stable | 계열 표시명(text-secondary). |
.axe-chart__tooltip-value | stable | 계열 값(text-primary, tabular-nums, semibold). |
.axe-chart--empty | internal | data 가 비었을 때 루트에 추가되어 EmptyState 를 감싼다. 컴포넌트가 emit 하지만 현재 전용 CSS 규칙은 없음(레이아웃은 .axe-chart 상속). |
접근성
키보드, ARIA, 구현 노트를 함께 검토합니다.
컨테이너 div 에 role="img" + aria-label(ariaLabel ?? `"{n}-series chart"`) 를 부여해 차트 전체를 하나의 이미지로 노출한다. ariaDescribedBy 로 확장 설명 요소를 연결할 수 있다. tooltip 색 swatch 는 aria-hidden.
recharts SVG 는 기본적으로 포커스·키보드 탐색이 불가하다 — 개별 point/bar 는 키보드로 도달할 수 없고 onPointClick 은 마우스 전용이다. 따라서 실제 수치가 중요하면 ariaDescribedBy 로 화면에 숨긴 데이터 표(.axe-sr-only)를 반드시 함께 제공해 SR·키보드 사용자가 값을 읽을 수 있게 한다. 색만으로 계열을 구분하지 않도록 label 을 항상 지정하고, 예측/추정 계열은 dashed 로 형태 단서를 더한다.