본문으로 건너뛰기
데이터 / chart

Chart

recharts 를 axe 토큰으로 감싼 얇은 wrapper — LineChart · BarChart · AreaChart 3종이 동일한 data/xKey/series API 를 공유.
데이터chartStatic specimenchart차트그래프graph
01 · Specimen

먼저 보고, 그다음 계약을 읽습니다

recharts 를 axe 토큰으로 감싼 얇은 wrapper — LineChart · BarChart · AreaChart 3종이 동일한 data/xKey/series API 를 공유.

Workbench 불러오는 중…
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 변형을 권장한다.

02 · Use

예제

SSOT에 등록된 실제 API 기준 snippet입니다. standalone 배지만 독립 실행 단위이며, fragment는 주변 state·handler 문맥을 생략합니다.

01실적 대비 예측 (LineChart, dashed 계열)tsxfragment
실적 대비 예측 (LineChart, dashed 계열)
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="월별 실적 대비 예측 추이"/>
02채널 구성 (BarChart stacked)tsxfragment
채널 구성 (BarChart stacked)
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="분기별 채널 매출 구성"/>
03AUM 추이 + SR 표 대체 (AreaChart, ariaDescribedBy)tsxfragment
AUM 추이 + SR 표 대체 (AreaChart, ariaDescribedBy)
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></>
03 · React

Props

TSX 소스가 진실입니다. 주요 export 컴포넌트의 public API만 노출합니다.

이름타입필수기본값설명
dataDatum[]필수레코드 배열. 각 원소는 x축 라벨(data[i][xKey])과 series 별 y값을 담는다. 빈 배열이면 EmptyState("데이터 없음")로 대체.
xKeystring필수x축으로 쓸 key. data[i][xKey] 값이 카테고리 축 라벨.
seriesChartSeries[]필수그릴 계열 목록. 각 ChartSeries = { key: string(=data 의 y값 key), label?: string(범례/tooltip 표시명, 미지정 시 key), color?: string(미지정 시 semantic 팔레트 순환), dashed?: boolean(Line/Area 점선 — 예측 계열 등) }.
heightnumber240차트 컨테이너 높이(px). ResponsiveContainer 가 width 100% 를 채우므로 높이는 명시 권장.
showLegendboolean범례 표시. 미지정 시 series 가 2개 이상이면 자동 표시(series.length > 1).
showGridbooleantrueCartesianGrid(점선 3 3) 표시.
onPointClick(point: Datum) => voidpoint/bar 클릭 콜백. 클릭된 activeTooltipIndex 의 data 원소를 그대로 넘긴다. 마우스 전용 — 키보드로는 도달 불가(a11y 참고).
animatebooleanrecharts 진입 애니메이션. 미지정 시 prefers-reduced-motion: reduce 면 자동 false, 아니면 true.
ariaLabelstringrole="img" 컨테이너의 aria-label — SR 사용자가 차트가 무엇인지 파악. 미지정 시 `"{n}-series chart"` 라는 무의미한 fallback 이 붙으므로 사실상 필수.
ariaDescribedBystring확장 설명 요소의 id(보통 화면에 숨긴 데이터 표 대체). 실제 수치를 SR·키보드 사용자에게 전달하는 채널.
classNamestring루트 .axe-chart div 에 병합.
stackedbooleanfalse[BarChart 전용] bar 를 누적(stack). false 면 group 배치 + 상단 모서리 라운드(3px).
gradientbooleantrue[AreaChart 전용] 영역 fill 에 linearGradient(0%→35% / 100%→2%) 적용. false 면 단색 fill(opacity 0.25).
04 · Any stack

.axe-* 클래스 계약

React 밖에서도 같은 표면을 그리는 공개 계약입니다. stable은 minor 버전 안에서 이름을 바꾸지 않습니다.

클래스안정성용도
.axe-chartstable루트 컨테이너 div — width 100% + height 지정자, text-primary. recharts SVG 를 감싼다.
.axe-chart__tooltipstable커스텀 tooltip 컨테이너(bg-elevated · border-subtle · shadow). recharts 기본 tooltip 대체.
.axe-chart__tooltip-labelstabletooltip 상단 x축 라벨(하단 border 구분선).
.axe-chart__tooltip-liststabletooltip 내 계열 행 목록(flex column).
.axe-chart__tooltip-rowstable계열 1개 행 — swatch · name · value 3열 grid.
.axe-chart__tooltip-swatchstable계열 색 표시 정사각 칩(10px, aria-hidden).
.axe-chart__tooltip-namestable계열 표시명(text-secondary).
.axe-chart__tooltip-valuestable계열 값(text-primary, tabular-nums, semibold).
.axe-chart--emptyinternaldata 가 비었을 때 루트에 추가되어 EmptyState 를 감싼다. 컴포넌트가 emit 하지만 현재 전용 CSS 규칙은 없음(레이아웃은 .axe-chart 상속).
비-React 소비 노트
본 컴포넌트는 recharts(React) 위에 서 있어 순수 CSS-only 로는 소비할 수 없다 — HTML 마크업만으로 재현 불가. .axe-chart__tooltip* 클래스는 컴포넌트가 렌더하는 tooltip 을 테마가 재스타일하기 위한 계약이다. components.css가 data-display.css와 feedback.css를 모두 import하므로 표준 진입점 하나면 스타일은 완결된다.
05 · Inclusive

접근성

키보드, ARIA, 구현 노트를 함께 검토합니다.

ARIA

컨테이너 div 에 role="img" + aria-label(ariaLabel ?? `"{n}-series chart"`) 를 부여해 차트 전체를 하나의 이미지로 노출한다. ariaDescribedBy 로 확장 설명 요소를 연결할 수 있다. tooltip 색 swatch 는 aria-hidden.

Notes

recharts SVG 는 기본적으로 포커스·키보드 탐색이 불가하다 — 개별 point/bar 는 키보드로 도달할 수 없고 onPointClick 은 마우스 전용이다. 따라서 실제 수치가 중요하면 ariaDescribedBy 로 화면에 숨긴 데이터 표(.axe-sr-only)를 반드시 함께 제공해 SR·키보드 사용자가 값을 읽을 수 있게 한다. 색만으로 계열을 구분하지 않도록 label 을 항상 지정하고, 예측/추정 계열은 dashed 로 형태 단서를 더한다.

06 · Judgment

권장 · 지양

권장
  • ariaLabel 을 항상 지정한다(미지정 fallback 은 무의미).
  • 실제 수치가 중요하면 ariaDescribedBy 로 .axe-sr-only 데이터 표를 함께 제공한다.
  • 각 series.label 을 지정해 색뿐 아니라 이름으로도 계열을 구분한다.
  • 예측·추정 계열은 dashed 로 실선/점선을 섞어 형태 단서를 준다.
  • 대시보드 첫 화면 차트는 LazyCharts 변형으로 recharts 청크를 지연 로드한다.
지양
  • onPointClick 에 필수 정보 접근을 의존하지 말 것 — 마우스 전용이라 키보드로 도달 불가.
  • 6개 이상 계열을 색 지정 없이 두지 말 것 — semantic 팔레트가 5색에서 순환해 색이 겹친다.
  • 색만으로 계열 의미를 구분하지 말 것(color-blind·흑백 인쇄).
  • recharts 무게(~395KB)를 first-paint 번들에 싣지 말 것.
검색창을 열면 컴포넌트 인덱스를 불러옵니다.