KRDS React Button 컴포넌트 설계 - variant, 접근성, cva 패턴
HANUI 시작하기 시리즈
(7편)- 1.KRDS React 컴포넌트 라이브러리 HANUI - 그냥 가져다 쓰세요
- 2.shadcn/ui 방식의 KRDS React 컴포넌트 - 왜 npm 패키지가 아닌가
- 3.KRDS 디자인 토큰 Tailwind CSS 적용 방법 - 17px 폰트, 색상 시스템
- 4.KRDS React Button 컴포넌트 설계 - variant, 접근성, cva 패턴
- 5.KRDS React Form 컴포넌트 - Input, Select, 자동 접근성 연결
- 6.Next.js + HANUI 프로젝트 세팅 가이드
- 7.KRDS MegaMenu 완전정복 — 공공 웹사이트 네비게이션 만들기
KRDS 가이드라인 따라서 React Button 컴포넌트 만들어본 적 있어요? 그냥 <button> 쓰면 되는 거 아닌가요?
맞아요. 근데 KRDS 따라서 만들고, 웹접근성 챙기고, variant 관리하고, 로딩 상태 처리하고... 하다 보면 버튼 하나가 200줄이 돼요.
오늘은 HANUI Button을 왜 이렇게 만들었는지 얘기해볼게요.
variant가 8개인 이유
KRDS 가이드 보면 버튼 스타일이 진짜 많아요. Primary, Secondary, Tertiary는 기본이고, 상황에 따라 Danger, Success도 필요하고.
처음엔 "이렇게 많이 필요해?" 했는데, 실제 프로젝트 하다 보면 다 쓰게 돼요.
class-variance-authority 쓰는 이유
variant 관리할 때 보통 이렇게 하잖아요.
이거 타입 안전하지 않아요. variant="asdf" 넣어도 에러 안 나요.
cva 쓰면?
variant="asdf" 넣으면 TypeScript 에러 나요. 자동완성도 되고요.
접근성, 이렇게 챙겼어요
1. 포커스 링
키보드 사용자가 현재 포커스 위치를 알 수 있어야 해요. outline 지우고 ring으로 대체했어요.
2. 로딩 상태
로딩 중일 때:
aria-busy="true"자동 적용disabled자동 적용 (중복 클릭 방지)- 스피너 아이콘 표시
3. 아이콘 전용 버튼 경고
텍스트 없는 버튼은 스크린 리더가 뭔지 모르잖아요. 개발 모드에서 경고 띄워서 까먹지 않게 했어요.
asChild 패턴
Next.js에서 Link 쓸 때 이런 문제 있잖아요.
asChild 쓰면?
Button의 스타일은 유지하면서, 실제로는 Link로 렌더링돼요. Radix UI의 Slot 패턴이에요.
href 지원
링크인데 버튼처럼 보여야 할 때 있잖아요.
내부에서 href 있으면 자동으로 <a> 태그로 바꿔요.
아이콘 넣기
아이콘 위치를 prop으로 받아요. children 안에서 순서 맞추느라 고생할 필요 없어요.
전체 API
마무리
버튼 하나에 이렇게 많은 게 들어가요.
- 8개 variant, 6개 size
- 로딩 상태 + 스피너
- 접근성 (포커스 링, aria 속성, 개발 경고)
- 아이콘 지원
- 링크 버튼, asChild 패턴
직접 만들면 하루는 걸려요. HANUI 쓰면?
10초.
HANUI
KRDS 기반 React 컴포넌트 라이브러리. 공공 웹 개발을 더 쉽게.