사람함께에이전트▾
사람 — 직접 정하고 책임지는 비즈니스 규칙과 흐름. 직접 읽어보세요.
함께 — 개념은 알아두고, 세부 규칙은 에이전트가 따릅니다.
에이전트 — 에이전트가 따르는 규칙과 레퍼런스. 필요할 때 찾아보세요.
스타일링 기반
화면마다 색을 직접 적으면(여기는 #ff493b, 저기는 빨간 utility class), 브랜드를 바꾸거나 다크 테마를 더할 때 하나하나 찾아 고쳐야 합니다. Akan은 색에 용도로 이름을 붙이고, 모든 화면이 그 이름을 쓰게 해서 이 문제를 피합니다.
Akan은 Tailwind CSS와 시맨틱 디자인 토큰 계층, 그리고 akanjs/ui 프리미티브를 기본 스타일링 기반으로 사용합니다. 그래서 앱 화면은 모든 색을 하드코딩하지 않고 primary, background, warning, destructive 같은 의도로 말합니다. 두 도구는 일을 이렇게 나눕니다:
Tailwind CSS
구조와 레이아웃
레이아웃, 간격, 반응형 동작, 일회성 조합을 빠르게 적는 utility 언어입니다. Tailwind CSS
flex gap-4 p-4 md:grid-cols-2토큰 + akanjs/ui
테마를 따라가는 색과 컴포넌트
테마를 따라가는 의미 기반 색 이름과 프리미티브(Button, Badge, Input, Field …)입니다.
bg-primary text-foreground <Button>이 페이지에서 쓰는 말
용어설명
semantic token
값이 아니라 역할로 이름 붙인 색입니다. primary, background, destructive 같은 이름입니다.
theme
모든 토큰에 대한 값 한 벌입니다. data-theme 속성이 어느 벌을 쓸지 고릅니다.
primitive
이미 토큰을 쓰도록 만들어진 akanjs/ui 컴포넌트입니다. Button, Input, Badge, Field 같은 것입니다.
custom property
--primary 같은 CSS 변수입니다. 토큰의 실체는 custom property입니다.
레이어가 함께 동작하는 방식

계층하는 일
tokens
브랜드 결정을 primary, background, warning, destructive 같은 이름으로 바꾼 것입니다.
recipes
토큰 클래스를 조합해 이름 붙인 모양 하나로 만드는 함수입니다. buttonRecipe가 그 예입니다.
components
그 이름들을 쓰는 akanjs/ui 프리미티브(Button, Input, Badge)와 Tailwind utility class입니다.
screens
raw color와 spacing 규칙을 반복하지 않고, 컴포넌트를 조립해 만든 비즈니스 화면입니다.
토큰은 page/styles.css에 선언하고, 이 파일이 Tailwind와 Akan UI 스타일도 함께 import합니다. 그 파일은 아래 '테마 시스템 선언 방식'에서, recipe 계층은 UI 레시피 문서에서 다룹니다.
디자인 시스템을 먼저 설계
처음부터 따로 디자인한 페이지는 조금씩 어긋납니다. 버튼은 옆 페이지보다 약간 더 둥글고, border는 약간 더 옅어집니다. 그래서 앱의 기본 컴포넌트 스타일을 먼저 정의하고, 페이지는 그 컴포넌트를 조립하기만 하게 만드세요.
- button, input, card, form, alert, tab, modal, navigation은 공유 클래스를 통해 같은 간격, radius, 텍스트 색, border, 상태 동작을 씁니다.
- 비즈니스 페이지는 색과 간격을 다시 정의하지 않고 디자인 시스템을 조립합니다.
- 가져온 모듈도 같은 Tailwind와 시맨틱 디자인 토큰을 쓰므로 일관되게 보입니다.
이렇게 만든 블록에는 색 값이 하나도 없고, 토큰 이름과 recipe만 있습니다:
테마를 바꾸면 블록 전체가 알아서 다시 칠해집니다. 안의 모든 클래스가 색이 아니라 토큰을 가리키기 때문입니다.
테마 시스템 선언 방식
컴포넌트는 bg-primary라고 한 번만 적습니다. 그것이 어떤 빨강인지는 앱 스타일 진입점이라는 파일 하나에서, 테마마다 한 번씩 정합니다. 선언은 네 단계입니다:
- Tailwind와 Akan UI 스타일을 import합니다.
- :root와 [data-theme] 아래에 테마별 원시 값을 CSS 변수로 정의합니다.
- @theme inline으로 그 변수들을 Tailwind 색 이름에 연결합니다.
- 테마 전환은 data-theme 속성만 바꾸면 됩니다. 다른 것은 바뀌지 않습니다.
apps/myapp/page/styles.css
글자가 올라가는 색에는 그 글자를 위한 -foreground 짝이 있습니다. bg-primary에는 text-primary-foreground가 짝이므로, primary 버튼 위 글자는 어느 테마에서나 잘 읽힙니다.


@theme inline이 var()를 참조하므로, 같은 클래스(bg-primary, text-foreground …)가 data-theme에 따라 다른 색으로 해석됩니다. 컴포넌트 클래스를 하나도 바꾸지 않고 light, dark, brand, admin 테마를 정의할 수 있습니다.
라이브러리 소유 토큰
테마를 따라가면 안 되는 색도 있습니다. 카카오 로그인 버튼은 라이트 테마에서도 다크 테마에서도 카카오 노랑입니다. 라이브러리의 컴포넌트에 이런 고정 색이 필요하면 라이브러리가 직접 선언합니다:
테마 토큰
테마를 따라갑니다
앱의 page/styles.css에 선언하고 @theme inline으로 연결합니다.
bg-primary라이브러리 토큰
어느 테마에서나 고정
libs/<lib>/ui/tokens.css에 순수 custom property로 한 번 선언합니다.
bg-[var(--kakao)]그 라이브러리에 닿는 앱은 이 파일을 자동으로, 자기 스타일시트보다 먼저 가져갑니다. 그래서 같은 변수를 둘 다 선언했다면 앱이 최종 결정권을 가집니다. 손으로 import할 것이 없고, 새 앱이 빠뜨릴 수도 없습니다.
libs/social/ui/tokens.css
libs/social/ui/KakaoButton.tsx


왜 Tailwind @theme 확장이 아닐까요? 색 어휘는 스타일시트 단위로 닫혀 있어서 bg-kakao는 CSS를 만들지 않습니다. 변수는 bg-[var(--kakao)]로 참조하세요. 색상 lint 규칙이 일부러 허용하는 형태입니다.
폰트 선언 방식
폰트는 루트 레이아웃에서 한 번 선언하고, 그다음부터는 다른 Tailwind 클래스처럼 씁니다. rootLayout() 체인의 .fonts() 단계에 배열을 넘기며, 항목마다 세 필드를 적습니다:
필드설명
name
폰트 이름입니다. font-<name> 클래스가 됩니다. 예: font-pretendard.
paths
폰트 파일마다 항목 하나입니다. 파일 경로(src)와 그 파일이 맡는 weight를 적습니다.
default
폰트 클래스를 따로 주지 않았을 때 앱 전체가 쓰는 폰트입니다. 기본 폰트는 하나만 둘 수 있습니다.
apps/myapp/page/_layout.tsx
이제 각 이름이 클래스가 됩니다. 클래스를 주지 않은 글자는 기본 폰트, 여기서는 Pretendard를 씁니다:
Using font classes