Accordion
관련 정보를 세로로 묶어 두고 항목마다 머리를 눌러 상세를 펼치는 목록 — 카드 혜택 · 유의사항처럼 상세가 길어 다 펼쳐 두면 화면이 몇 배로 길어지는 자리에 쓴다. 하나만 접고 펴는 자리는 Collapsible, 단계가 있는 고르는 나무는 Tree View, 하위 줄을 접는 목록은 List 의 하위 줄이다.
구조는 당근 SEED Accordion(rootage accordion.json · accordion-item.json, @seed-design/react 2.0.0 — Apache-2.0)을 따른다 — 트리거(앞 아이콘 · 제목 · 설명 · 꺾쇠)와 펼친 내용, 변형 둘(inline · separated), 회전 · 펼침 300ms, 누르면 좌우 6 들어온 바탕 + 콘텐츠만 축소. 크기는 SEED medium 하나이고, 여럿 열기 · "모두 펼치기" · 상세 없는 항목 · 카드 상세의 쓰임은 groo 가 정했다(2026-10-10 사용자 결정). 값은 groo 토큰이고, SEED 와 다른 자리는 맨 아래 "SEED 와 다른 점" 에 적었다. 옛 Accordion 스펙(Radix 베이스 · 아래 선만 · 꺾쇠 16 · 하나만 여는 모드 · 불투명도 막힘)을 대신한다.
수치 원본은 accordion.yaml이다. 수치 표 자리([표: …])와 그림 자리([그림: …])는 사이트가 그 파일로 그린다 — GitHub 에서는 그 파일 · 그림 코드로 가는 링크로 보인다.
직접 골라 보기
변형(inline · separated) · 설명 · 앞 아이콘 · 상세 없는 항목 · 막힘 · 모션 줄이기를 고르면 스펙대로 그린 아코디언과 그 코드가 바뀐다. 트리거를 눌러 펼치고, 초점을 두고 ↓ ↑ · Home · End · Enter 를 눌러 볼 수 있다 — "모두 펼치기" 도 함께 있다.
혜택 상세 · 12건
화면 읽기트리거에 초점을 두면 읽는 글이 나온다
import { useState } from "react"
import {
Accordion,
AccordionContent,
AccordionExpandAll,
AccordionHeader,
AccordionItem,
AccordionPlainItem,
AccordionTrigger,
} from "@/components/ui/accordion"
const [open, setOpen] = useState<string[]>([]) // 처음에는 모두 접힘
const expandable = ["pay", "coffee", "telecom", "movie"] // 상세가 있는 항목
<AccordionHeader title={"혜택 상세 · 12건"}>
<AccordionExpandAll controls="benefit-detail" values={open} expandable={expandable} onValuesChange={setOpen} />
</AccordionHeader>
<Accordion id="benefit-detail" variant="separated" values={open} onValuesChange={setOpen}>
<AccordionItem value="pay">
<AccordionTrigger title="온라인 간편결제 · 배달앱 · 해외 직구 통합 할인" description="네이버페이 · 카카오페이 · 토스페이 결제 시 이용금액의 10% 결제일 할인(월 최대 2만 원)" />
<AccordionContent>{details.pay}</AccordionContent>
</AccordionItem>
<AccordionItem value="coffee">
<AccordionTrigger title="커피" description="골목커피 · 숲속다방 · 달빛로스터리 50% 할인" />
<AccordionContent>{details.coffee}</AccordionContent>
</AccordionItem>
{/* 상세가 없으면 그냥 줄 — 막힌 트리거로 그리지 않는다 */}
<AccordionPlainItem title="대중교통" description="버스 · 지하철 10% 청구할인" />
<AccordionItem value="telecom">
<AccordionTrigger title="통신" description="SKT · KT · LG U+ 자동이체 5천 원 할인" />
<AccordionContent>{details.telecom}</AccordionContent>
</AccordionItem>
{/* 상세가 없으면 그냥 줄 — 막힌 트리거로 그리지 않는다 */}
<AccordionPlainItem title="편의점" description="GS25 · CU · 세븐일레븐 5% 할인" />
<AccordionItem value="movie">
<AccordionTrigger title="영화" description="CGV · 롯데시네마 · 메가박스 4천 원 할인" />
<AccordionContent>{details.movie}</AccordionContent>
</AccordionItem>
</Accordion>Anatomy
| 부위 | 설명 |
|---|---|
| ⓐ Trigger | 트리거 — 줄 전체가 누르는 자리. 머리말(h3) 안의 단추다. |
| ⓑ Prefix Icon | 앞 아이콘 — 22, 있을 때만. |
| ⓒ Title | 제목 — 16 / 22 · 500. 무엇의 상세인지 — 늘 줄을 바꾼다. |
| ⓓ Description | 설명 — 13 / 18 · 500 · 옅은 색. 제목 아래 한 줄 요약, 있을 때만. |
| ⓔ Chevron | 꺾쇠 — 20. 접혀 있으면 아래, 펼치면 위. |
| ⓕ Panel | 펼친 내용 — 14 / 22 · fg-neutral-muted. 안에서 스크롤하지 않는다. |
| ⓖ Divider | 항목 사이 선 — inline 만, 좌우 24 들인다. |
| ⓗ Expand All | 모두 펼치기 — 목록 머리 오른쪽 글 단추. 펼치면 "모두 접기". |
한 트리거는 두 층이다 — 바탕 층(누름 · 호버 바탕)과 콘텐츠 층(앞 아이콘 · 본문 · 꺾쇠). 누르면 바탕이 좌우 6 들어와 모서리 10 으로 둥글어지고, 콘텐츠 층만 2px 거리로 준다 — List 줄과 같은 짜임이다(기초 Feedback v104 — "목록 줄 · 아코디언은 콘텐츠만").
부위
| 부위 | 설명 |
|---|---|
root | 아코디언 — 항목을 세로로 잇는다. 항목은 2개 이상(하나면 Collapsible) |
item | 항목 하나 — 트리거 + 펼친 내용. separated 는 Card 면 |
heading | 머리말 — 트리거를 감싼다(heading > button). 모양은 없다 |
trigger | 트리거 — 줄 전체가 누르는 자리(button) |
background | 트리거 바탕 층 — 누름 · 호버 바탕. 줄지 않는다 |
content | 트리거 콘텐츠 층 — 앞 아이콘 · 본문 · 꺾쇠. 누르면 이 층만 준다 |
prefixIcon | 앞 아이콘 — 있을 때만 |
body | 본문 — 제목 + 설명 |
title | 제목 — 무엇의 상세인지(이름) |
description | 설명 — 있을 때만, 제목 아래 한 줄 요약 |
chevron | 꺾쇠 — 오른쪽 끝. 펼치면 위를 가리킨다 |
panel | 펼친 내용 — 높이로 펼치고 접는다. 안에서 스크롤하지 않는다 |
panelText | 펼친 내용의 글 — 표 · 목록 · 칸을 넣으면 그쪽 규칙 |
divider | 항목 사이 선 — inline 만 |
header | 목록 머리 — 시트 · 대화상자에서 아코디언 위 한 줄(제목 + 모두 펼치기). 카드 안이면 카드 머리가 이 자리다 |
headerTitle | 목록 머리 제목 — "혜택 상세 · 12건" |
expandAll | 모두 펼치기 — 목록 머리 오른쪽 글 단추(groo 확장). 펼치면 "모두 접기" |
focusRing | 키보드 포커스 링(웹) — 트리거 안쪽 |
Properties
Variant
SEED 의 두 변형을 그대로 둔다(사용자 결정 1B).
inline(기본) — 연속 목록 + 항목 사이 선. 화면 · 카드 안에서 목록으로 읽히는 자리 — 카드 상세의 혜택 · 유의사항. 선은 List 의 들인 선과 같다 — 1pxstroke-neutral-subtle· 좌우 24 · 첫 항목 위와 마지막 항목 아래에는 긋지 않는다.separated— 항목마다 Card 모양(1pxstroke-neutral-weak테두리 · 모서리 16 · 사이 8 · 그림자 없음 — 면은 칠하지 않는다). 항목 하나하나가 따로 읽히는 정보 묶음 — 카드 혜택 상세 시트 · 대화상자. 면은 놓인 표면 그대로다(시트 · 대화상자의bg-layer-floating). 그래서separated는 흰 표면(시트 · 대화상자 · 띠 · 흰 화면) 위에만 둔다 — 회색 바닥 위의 접는 목록은 흰 면(카드 · 띠 — 어느 화면이 어느 쪽인지는 DESIGN.md Layout 의 "화면 바탕") 안의inline이다(2026-10-21 사용자 결정 — 03-G 결정 7 A — 항목 면을 흰색으로 칠하는 안은 고르지 않았다). 띠 안에 테두리 카드를 두지 않는 규칙의 예외다(2026-10-22 사용자 결정 2B). SEED 의 모서리 12 · 사이 12 는 카드에서 거절된 값이라 쓰지 않는다(데이터 표시 5A).
두 변형 모두 트리거 · 눌림 · 꺾쇠 · 펼침은 같고 면만 다르다. 모든 아코디언을 카드 모양으로 하는 안(1C)과 지금처럼 자리마다 짜는 안(1A)은 고르지 않았다.
변형
| variant | 간격 | item 모서리 | item 테두리 | item 테두리 두께 | item 그림자 | item 넘침 | divider 높이 | divider 좌우 바깥 여백 | divider 배경 | divider 보이기 | 설명 |
|---|---|---|---|---|---|---|---|---|---|---|---|
inline (기본) | — | — | — | — | — | — | 1px | spacing-x6 24px — 들인 선 24 — List 의 들인 선과 같다(SEED dividerPaddingX 12 의 groo 짝) | color-stroke-neutral-subtle #EDEFF3 · 다크 #353B4D — SEED dividerColor 와 같은 역할 | 항목 사이 — 첫 항목 위 · 마지막 항목 아래에는 긋지 않는다(Divider — 마지막 선 금지) | 연속 목록 + 들인 사이 선 — 화면 · 카드 안 목록(기본) |
separated | spacing-x2 8px — Card 사이 8(사용자 결정 1B) — SEED separated medium 12 는 카드에서 거절됐다(데이터 표시 5A) | radius-r4 16px — Card 면 16(SEED r3 12) — 안의 누름 바탕은 16 − 6 = 10 으로 동심 | color-stroke-neutral-weak #E5E8EF · 다크 #404757 — Card 테두리 — SEED separated strokeColor 와 같은 역할 | 1px | none — 그림자 없음 — Card 면 | hidden — 누름 바탕 · 펼친 내용을 모서리에서 자른다 — 포커스 링은 안쪽이라 잘리지 않는다 | — | — | — | — | 항목마다 Card 면 — 항목 하나하나가 따로 읽히는 정보 묶음(카드 혜택 상세 시트 · 대화상자) |
Size
크기는 SEED medium 하나다 — 폰 · 데스크톱이 같다(사용자 결정 2A). 트리거는 위아래 16 · 좌우 24(화면 가장자리 규칙 — SEED 16), 제목 16 / 22 · 500 fg-neutral, 설명 13 / 18 · 500 fg-neutral-subtle(제목 아래 2), 꺾쇠 20 fg-neutral-subtle, 앞 아이콘 22 — 앞 아이콘 · 본문 · 꺾쇠 사이는 12 다. 제목만이면 54, 설명이 있으면 74 이고, 제목이 줄을 바꾸면 늘어난다. List 줄 · 카드 머리와 같은 16 이라 한 화면 안에서 글 크기가 갈리지 않는다. 데스크톱에서 커지는 SEED large(제목 20 · 설명 16 · 꺾쇠 24)와 지금의 14 는 고르지 않았다.
설명 있음 · 없음
| description | trigger 최소 높이 | 설명 |
|---|---|---|
none (기본) | — | 제목만 — 트리거 54(기본) |
shown | 74px — 위아래 16 + 제목 22 + 2 + 설명 18 | 제목 + 설명 — 트리거 74 |
트리거
| 속성 | 값 | 비고 |
|---|---|---|
| 최소 높이 | 54px | 위아래 16 + 제목 22. 제목이 줄을 바꾸면 늘어난다 |
| 상하 여백 | spacing-x4 16px | SEED medium paddingY x4 |
| 좌우 여백 | spacing-global-gutter 24px | 화면 가장자리 규칙 24(SEED global-gutter 16) |
| 글 맞춤 | left | |
| 커서 | pointer | |
| 터치 영역 | 트리거 전체 | 줄 폭 × 54 이상 — 꺾쇠만이 아니라 줄 전체가 누르는 자리(SEED). AA ✓ · AAA ✓ |
콘텐츠 층
| 속성 | 값 | 비고 |
|---|---|---|
| 간격 | spacing-x3 12px | 앞 아이콘 ↔ 본문 ↔ 꺾쇠 12 — SEED prefix paddingRight · suffixIcon paddingLeft x3 |
| 세로 맞춤 | center | 제목이 여러 줄이어도 앞 아이콘 · 꺾쇠는 트리거 가운데 |
| 전환 대상 | scale | |
| 전환 시간 | motion-duration-pressed-scale 150ms | |
| 전환 곡선 | motion-ease-pressed-scale cubic-bezier(0, 0, 0.15, 1) |
앞 아이콘
| 속성 | 값 | 비고 |
|---|---|---|
| 앞 아이콘 | 22px | 있을 때만 — SEED medium prefixIcon 22 |
| 앞 아이콘 색 | color-fg-neutral #1A1F2E · 다크 #F5F6FA |
본문
| 속성 | 값 | 비고 |
|---|---|---|
| 간격 | spacing-x0_5 2px | 제목 ↔ 설명 2 |
제목
| 속성 | 값 | 비고 |
|---|---|---|
| 글자 | text-t5 16px / 22px | |
| 굵기 | 500 | SEED medium |
| 글자·아이콘 | color-fg-neutral #1A1F2E · 다크 #F5F6FA | |
| 줄 수 | none | 늘 줄을 바꾼다 — 말줄임 · 줄 수 제한 없음(사용자 결정 10A, 단어 단위 v114) |
설명
| 속성 | 값 | 비고 |
|---|---|---|
| 글자 | text-t3 13px / 18px | |
| 굵기 | 500 | SEED accordion-item description medium — 머리 제목 500 과 한 벌. 글자 역할 R9 의 "여닫는 머리 설명"(2026-10-17 사용자 결정 01T-005 — 줄 설명 400 에 맞추지 않는다) |
| 글자·아이콘 | color-fg-neutral-subtle #62697A · 다크 #A2A8B7 | |
| 줄 수 | none | 늘 줄을 바꾼다 |
꺾쇠
| 속성 | 값 | 비고 |
|---|---|---|
| 크기 | 20px | lucide chevron-down — 접혀 있으면 아래 |
| 색 | color-fg-neutral-subtle #62697A · 다크 #A2A8B7 | 흰 면 5.50 · 다크 6.09(시트 5.27) |
| 회전 | 0deg | |
| 전환 대상 | rotate | |
| 전환 시간 | motion-duration-d6 300ms | |
| 전환 곡선 | motion-ease-easing cubic-bezier(0.35, 0, 0.35, 1) |
펼친 내용
펼친 내용은 트리거와 같은 좌우 24, 아래 16 안에 둔다 — 위 여백은 0 이라 트리거 아래 16 에 바로 이어진다. 글은 text-article-note(14 / 22 — 긴 글 보조) · fg-neutral-muted 다. SEED 의 AccordionContent 는 여백 · 글자가 없어 쓰는 쪽이 정하는데, groo 는 혜택 상세처럼 긴 설명이 대부분이라 이 글 모양을 기본으로 둔다. 앞 아이콘이 있어도 펼친 내용은 24 에서 시작한다 — 줄 폭을 쓴다. 내용이 길어도 패널 안에서 스크롤하지 않는다 — 페이지 · 시트 본문이 스크롤한다(SEED "Content Panel 내 스크롤 지양").
펼친 내용
| 속성 | 값 | 비고 |
|---|---|---|
| 보이기 | 숨김 | 접혀 있으면 내용을 그리지 않는다 — 보조 기술도 읽지 않는다(앱도) |
| 위 여백 | 0px | |
| 좌우 여백 | spacing-global-gutter 24px | 트리거와 같은 24 — 앞 아이콘이 있어도 같다. 펼친 내용은 줄 폭을 쓴다 |
| 아래 여백 | spacing-x4 16px | 트리거 위아래와 같은 16 |
| 최대 높이 | none | 패널 안에서 스크롤하지 않는다 — 길면 페이지 · 시트 본문이 스크롤한다(SEED Don't) |
펼친 내용의 글
| 속성 | 값 | 비고 |
|---|---|---|
| 글자 | text-article-note 14px / 22px | 14 / 22 — 긴 글 보조. 비교 페이지가 그린 14 / 22 가 이 토큰 그대로다 |
| 굵기 | 400 | |
| 글자·아이콘 | color-fg-neutral-muted #535866 · 다크 #B7BDCC | 흰 면 7.11 · 다크 7.70(시트 6.67) |
상세가 없는 항목
목록 가운데 상세가 없는 항목(혜택 "대중교통" — 요약뿐)은 트리거가 아닌 그냥 줄이다(사용자 결정 5A) — 꺾쇠가 없고, 머리말 · 단추로 감싸지 않아 Tab 이 건너뛰며, 글만 읽힌다. 위아래 16 · 좌우 24 · 글 크기가 다른 항목과 같아 높이와 글 시작이 같다. 누르거나 올려도 바탕이 생기지 않는다. 막힌 트리거(5B — "사용할 수 없음" 으로 읽혀 혜택이 막힌 것처럼 들린다)와 꺾쇠만 뒤집히는 줄(5C — 눌러도 열리는 것이 없다)은 고르지 않았다.
상세 있음 · 없음
| detail | 머리말 단계 | trigger 커서 | trigger 터치 영역 | chevron 보이기 | 설명 |
|---|---|---|---|---|---|
expandable (기본) | — | — | — | — | 상세가 있는 항목 — 트리거(기본) |
none | 없음 — 머리말 · 단추로 감싸지 않는다 — 글만 읽힌다(Tab 이 건너뛴다) | default — 트리거가 아니다 — 같은 위아래 16 · 좌우 24 로 높이 · 글 시작이 다른 항목과 같다(사용자 결정 5A) | 없음 — 누르는 줄이 아니다 | none — 꺾쇠를 두지 않는다 — 막힌 트리거 · 꺾쇠만 뒤집히는 줄은 고르지 않았다(5B · 5C) | 상세가 없는 항목 — 그냥 줄. 꺾쇠 없음 · 트리거 아님 · 높이와 글 시작은 같다 |
모두 펼치기
여럿을 함께 열고(사용자 결정 4A), 목록 머리 오른쪽에 "모두 펼치기" 글 단추를 둔다 — groo 확장이다(SEED 에 없다). 상세가 있는 항목을 모두 펼치고, 모두 펼쳐져 있으면 글이 "모두 접기" 로 바뀐다. 모양은 Card 머리 동작과 같은 글 버튼(SEED Text Button)이다 — 14 · 700 · fg-neutral-muted, 아이콘 없이 보이는 36(좌우 14) · 누르는 44(2026-10-16 사용자 결정 — 글자 역할 D2, DESIGN.md Typography 의 "글자 역할" R16). 머리가 카드 머리면 그 오른쪽 동작 자리에, 시트 · 대화상자면 목록 머리 줄(제목 16 / 22 · 700 + 건수 — 카드 머리와 같은 글, 높이 36 · 아래 8)의 오른쪽에 둔다. 하나만 여는 모드(4C — 다른 항목을 열면 앞 항목이 닫힌다)와 단추 없이 하나씩 여는 안(4B)은 고르지 않았다. 큰 글자에서 오른쪽 동작이 머리 폭의 절반을 넘으면 제목 아래 줄 오른쪽 끝으로 내린다 — 제목은 한 줄 전체 폭으로 읽히고 머리가 버튼 한 줄(36)만큼 높아진다. 평소(100% · 130%)는 한 줄 그대로다. Button 짝의 반 폭 판정과 같고, 카드 머리 · 아코디언 목록 머리 · List Header 가 같은 규칙이다(2026-10-21 사용자 결정 — 03-G 결정 4 A, https://claude.ai/artifact/A3oCdxNvDwkNBPFPE36bmF). 판정 — 동작의 보이는 상자 폭(글 + 좌우 14 · 14)에서 끝 블리드 14(머리 여백으로 내어 걸리는 몫)를 빼고 사이 8 를 더한 값이 머리 안쪽 폭의 절반 이하면 한 줄, 넘으면 내린다. 레시피의 flex 줄바꿈(제목 최소 50%)이 그대로 이 셈이다 — 예: 머리 안쪽 300 이면 "모두 펼치기" 보이는 상자 156 까지 한 줄 · 157 부터 내려간다(카드 머리 · 아코디언 목록 머리 156 / 157 · List Header 는 사이가 10 이라 154 / 155). 결정 페이지(https://claude.ai/artifact/A3oCdxNvDwkNBPFPE36bmF) · 보류 둘 결정 페이지(https://claude.ai/artifact/7ENKeRYQMzFijZHnf5kaP7)의 그림은 상자 폭 ≤ 절반으로 그렸다 — 이 셈과 6 이하로 갈려 그림의 어느 경우도 달라지지 않는다(200% 에서 360 화면 "모두 펼치기" 154 는 한 줄, 320 화면 "전체 보기" 130 은 한 줄 · "모두 펼치기" 는 내려감). 웹 · 앱 모두 이 셈으로 판정한다.
목록 머리
| 속성 | 값 | 비고 |
|---|---|---|
| 최소 높이 | 36px | 모두 펼치기의 보이는 상자와 같은 높이 — 제목과 한 줄(2026-10-16 글자 역할 D2 — 글 버튼 36, 전 32) |
| 세로 맞춤 | center | |
| 가로 맞춤 | space-between | |
| 간격 | spacing-x2 8px | |
| 아래 바깥 여백 | spacing-x2 8px | 머리 ↔ 첫 항목 8 — separated 의 카드 사이와 같다 |
목록 머리 제목
| 속성 | 값 | 비고 |
|---|---|---|
| 글자 | text-t5 16px / 22px | Card 머리 제목과 같다 — 건수를 붙인다("혜택 상세 · 12건") |
| 굵기 | 700 | |
| 글자·아이콘 | color-fg-neutral #1A1F2E · 다크 #F5F6FA |
모두 펼치기
| 속성 | 값 | 비고 |
|---|---|---|
| 높이 | 36px | 보이는 상자 — SEED Text Button(minHeight x9), Card 머리 동작과 같은 모양(card.yaml headerAction). 2026-10-16 사용자 결정 — 글자 역할 D2 |
| 왼쪽 여백 | spacing-x3_5 14px | |
| 오른쪽 여백 | spacing-x3_5 14px | 좌우 14 — 줄 끝에서는 오른쪽 14 만큼 바깥으로 내어 글자 끝이 머리 여백에 선다 |
| 모서리 | radius-r2 8px | |
| 글자 | text-t4 14px / 19px | |
| 굵기 | 700 | SEED Text Button t4 · bold — 2026-10-16 사용자 결정 글자 역할 D2(전 500) |
| 글자·아이콘 | color-fg-neutral-muted #535866 · 다크 #B7BDCC | SEED Text Button fg.neutral-muted — 2026-10-16 사용자 결정 글자 역할 D2(전 subtle). 아이콘은 두지 않는다(전 chevrons-up-down · chevrons-down-up 16) — 글이 "모두 펼치기" · "모두 접기" 로 바뀌며 상태를 말한다 |
| 터치 영역 | 44 × 44 | 보이는 36 위아래로 4 씩 · 옆은 글 폭 + 여백. AA ✓ · AAA ✓ |
| 글 | 모두 펼치기 · 모두 접기 | 상세가 있는 항목이 모두 펼쳐져 있으면 "모두 접기" — 하나라도 접혀 있으면 "모두 펼치기" |
| 자리 | 목록 머리 오른쪽 | 시트 · 대화상자 목록 머리, 카드 머리의 오른쪽 동작 자리 |
| 전환 대상 | background-color | |
| 전환 시간 | motion-duration-color-transition 150ms | |
| 전환 곡선 | motion-ease-easing cubic-bezier(0.35, 0, 0.35, 1) |
State
| 상태 | 모습 |
|---|---|
enabled | 바탕 없음 · 꺾쇠 아래(펼침이면 위) |
hovered | 웹 — 누름과 같은 바탕(v106) — 좌우 6 들어온 bg-layer-default-pressed, 모서리 10 |
focused | 웹 — 키보드 포커스에만 트리거 안쪽 링 2px. separated 는 항목 모서리를 따라 14 |
pressed | 호버와 같은 바탕 + 콘텐츠 층만 2px 거리 축소(v104) |
disabled | 앞 아이콘 · 제목 · 설명 · 꺾쇠가 모두 fg-disabled — 흐리게 하지 않는다(v106). 상세가 없는 항목을 막힌 트리거로 그리지 않는다 |
상태 — 바탕 · 콘텐츠 · 포커스 링
| 상태 | background 바탕 들임 | background 모서리 | background 배경 | content 배율 | 링 두께 | 링 간격 | 링 색 | focusRing 모서리 |
|---|---|---|---|---|---|---|---|---|
enabled 기본 | 0px | 0px | transparent | — | — | — | — | — |
hovered 웹 — 누름과 같은 바탕(v106), 축소 없음 | spacing-x1_5 6px — 바탕이 좌우 6 들어온다(SEED marginX x1_5) | radius-r2_5 10px — SEED cornerRadius x2_5 — separated 면(16) 안에서도 16 − 6 = 10 으로 동심 | color-bg-layer-default-pressed #F7F8FD · 다크 #353B4D — SEED bg.transparent-pressed 의 불투명 짝 — 시트 · 대화상자 위에서도 같은 값(bg-layer-floating-pressed 와 같다) | — | — | — | — | — |
focused 웹 — 키보드 포커스에만 트리거 안쪽 링 | 0px | 0px | transparent | — | 2px | -2px — 트리거 안쪽 — 카드 · 시트가 바깥 링을 자르지 않게(지금 웹 카드 혜택은 카드 셸에 잘려 안 보인다) | color-stroke-focus-ring #1A1F2E · 다크 #F5F6FA | 0px — inline — 줄과 같은 각진 링(List 와 같다) |
pressed 바탕 + 콘텐츠만 2px 거리 축소(v104) | spacing-x1_5 6px | radius-r2_5 10px | color-bg-layer-default-pressed #F7F8FD · 다크 #353B4D | 2px 거리 축소 — 콘텐츠 층만(SEED scaleScope content) — 기준 길이 max(높이, 폭 ÷ 4, 24) 에서 2px(v104) | — | — | — | — |
상태 — 글 · 꺾쇠
| 상태 | 앞 아이콘 색 | title 글자·아이콘 | description 글자·아이콘 | chevron 색 |
|---|---|---|---|---|
enabled 기본 | color-fg-neutral #1A1F2E · 다크 #F5F6FA | color-fg-neutral #1A1F2E · 다크 #F5F6FA | color-fg-neutral-subtle #62697A · 다크 #A2A8B7 | color-fg-neutral-subtle #62697A · 다크 #A2A8B7 — 흰 면 5.50 · 다크 6.09(시트 5.27) |
disabled 전용 색(v106) — 불투명도로 흐리게 하지 않는다 | color-fg-disabled #8A91A0 · 다크 #838997 | color-fg-disabled #8A91A0 · 다크 #838997 | color-fg-disabled #8A91A0 · 다크 #838997 | color-fg-disabled #8A91A0 · 다크 #838997 |
separated 의 포커스 링
| 상태 | 링 두께 | 링 간격 | 링 색 | focusRing 모서리 |
|---|---|---|---|---|
enabled 기본 | — | — | — | — |
focused 웹 — 키보드 포커스에만 트리거 안쪽 링 | 2px | -2px — 트리거 안쪽 — 카드 · 시트가 바깥 링을 자르지 않게(지금 웹 카드 혜택은 카드 셸에 잘려 안 보인다) | color-stroke-focus-ring #1A1F2E · 다크 #F5F6FA | radius-r3_5 14px — 항목 모서리 16 − 링 들임 2 = 14 — 트리거가 항목 맨 위라 모서리를 따른다 |
펼침
| open | chevron 회전 | panel 보이기 | 설명 |
|---|---|---|---|
collapsed (기본) | — | — | 접힘 — 머리만 보인다. 처음에는 모두 접힘(기본) |
expanded | 180deg — 위로 — SEED Expanded | 보임 — 펼쳐도 저절로 스크롤 · 초점 이동하지 않는다 — 초점은 트리거에 그대로(SEED) | 펼침 — 꺾쇠가 위, 내용이 보인다 |
모션
| 전환 | 시간 | 곡선 | 대상 | 비고 |
|---|---|---|---|---|
펼침 · 접힘 — 높이 | motion-duration-d6 300ms | motion-ease-easing cubic-bezier(0.35, 0, 0.35, 1) | height | SEED expandHeight · collapseHeight d6 · easing(사용자 결정 3A). 펼칠 때 저절로 스크롤하지 않는다 |
꺾쇠 — 회전 | motion-duration-d6 300ms | motion-ease-easing cubic-bezier(0.35, 0, 0.35, 1) | rotate | 0 → 180° — 높이와 같은 시간. 모션 줄이기면 바로 뒤집힌다 |
모션 줄이기 — 펼침 · 접힘 | motion-duration-d3 150ms | motion-ease-easing cubic-bezier(0.35, 0, 0.35, 1) | opacity | 높이를 움직이지 않고 내용이 150ms 서서히 나타나고 사라진다(v104 — 200ms 넘는 움직임은 150ms 서서히) |
누름 · 호버 — 바탕 | motion-duration-color-transition 150ms | motion-ease-easing cubic-bezier(0.35, 0, 0.35, 1) | background-color, inset, border-radius | 바탕이 좌우 6 들어오며 모서리 10 으로 둥글어진다 — 모두 펼치기 단추의 바탕도 같은 시간 |
누름 — 콘텐츠 | motion-duration-pressed-scale 150ms | motion-ease-pressed-scale cubic-bezier(0, 0, 0.15, 1) | scale | 콘텐츠 층만 2px 거리 축소 — 모션 줄이기면 하지 않는다 |
꺾쇠는 180° 돌고 내용은 높이로 펼쳐지고 접힌다 — 둘 다 300ms motion-ease-easing(SEED d6, 사용자 결정 3A). 모션 줄이기면 높이를 움직이지 않고 내용이 150ms 서서히 나타나고 사라지며, 꺾쇠는 바로 뒤집힌다(v104). 200ms(3B)와 움직임 없음(3C)은 고르지 않았다.
Guidelines
언제 쓰나
| 이런 자리 | 쓰는 것 |
|---|---|
| 관련 상세를 여럿 묶고, 다 펼치면 화면이 몇 배로 길어진다(카드 혜택 · 유의사항) | Accordion — 항목 2개 이상 |
| 상세 하나를 접고 편다(분할 내역 · 빠르게 맞추기 · 상세 검색 조건) | Collapsible — 같은 트리거 모양 |
| 부모 · 하위 두 단계 목록에서 줄은 편집, 하위만 접는다(카테고리) | List 하위 줄 — 줄 앞 꺾쇠 단추 |
| 여러 단계에서 하나를 고른다(부서) | Tree View |
| 짧아서 늘 보여도 되는 내용 | 접지 않는다 — 그냥 보인다 |
항목은 2개 이상이다 — 하나를 접고 펴는 것은 Collapsible 이다(SEED Don't — 단일 Item). 처음에는 모두 접혀 있다.
여럿을 함께 연다
두 혜택을 나란히 견주며 읽을 수 있게 다른 항목을 닫지 않는다. 열 개를 한 번에 펼쳐 비교할 때는 "모두 펼치기" 를 누른다 — 열 번 누르지 않는다. 다른 항목을 열면 앞 항목이 닫히는 하나만 열기는 두지 않는다 — 닫히는 항목 때문에 누른 자리가 위로 밀려 올라간다.
펼쳐도 그 자리에
펼쳐도 화면을 저절로 스크롤하지 않고 초점도 트리거에 그대로 둔다 — 내용이 길면 페이지 · 시트 본문이 스크롤한다(SEED — "자동 스크롤 및 포커스 이동은 기본값으로 지원하지 않습니다"). 패널 안에 높이를 정해 스크롤 상자를 만들지 않는다 — 스크롤이 겹쳐 손가락이 어느 쪽을 움직이는지 모른다(SEED "Content Panel 내 스크롤 지양").
카드 상세의 혜택 · 유의사항
카드 상세 화면의 혜택 · 유의사항은 웹 · 앱 모두 카드 안의 inline 아코디언이다(사용자 결정 6A — 지금 앱은 혜택 상세 본문까지 다 펼쳐 보인다). 카드 머리(제목 "혜택 · 12건" · 오른쪽 모두 펼치기) 아래 트리거가 카드 가장자리까지 가고, 카드 아래 여백은 8 이다 — 마지막 트리거의 아래 16 과 합쳐 보이는 24(Card body="accordion"). 혜택 상세 시트 · 대화상자는 separated 다(1B). 유의사항은 설명 없이 제목만 있는 트리거다(펼치면 상세). 앱 유의사항의 주황 상자를 둘지는 이번 결정 밖이다 — 비교 페이지는 웹과 같은 카드 면으로 그렸다. 둘 다 펼친 목록(6B)은 고르지 않았다.
제목은 자르지 않는다
제목 · 설명은 늘 줄을 바꿔 다 보인다(단어 단위 — v114). 84자 유의사항 제목도 한 줄 말줄임으로 자르지 않는다 — 펼쳐도 상세(다른 글)만 나와 잘린 제목은 어디에서도 다 읽을 수 없다. 잘린 글을 펼치는 "더 보기" 도 두지 않는다(사용자 결정 10A).
글
제목은 무엇의 상세인지 명사로("커피" · "연회비 · 카드 발급 후 첫 달 실적 기준"), 설명은 그 항목의 한 줄 요약이다("골목커피 · 숲속다방 · 달빛로스터리 50% 할인"). 펼친 내용의 줄바꿈 문자는 그대로 줄을 바꾼다 — 상세가 "■ …" 줄들로 오는 자리. 모두 펼치기의 글은 "모두 펼치기" · "모두 접기" 다.
코드
레시피 recipes/shadcn/components/ui/accordion.tsx 를 쓴다(Radix Accordion type="multiple" 위에 짜도 된다). 아래 미리보기는 스펙 값으로 그린 모습이다.
Accordion— 아코디언.variant("inline"기본 ·"separated") ·values·defaultValues·onValuesChange(values)(펼친 항목의value목록 — 늘 여럿을 함께 연다, 하나만 여는 모드는 없다) ·disabled(전체) ·id(모두 펼치기가 가리킨다), 나머지는div속성. 처음에는 모두 접힘(defaultValues없음).AccordionItem— 항목.value(필수) ·disabled.AccordionTrigger—title(필수) ·description·prefixIcon·headingLevel(2~6, 기본3). 머리말 안의 단추(aria-expanded·aria-controls)를 그리고, 꺾쇠 20 은 트리거가 그린다. 트리거 사이↓↑(돌아가며) ·Home·End를 받는다.AccordionContent— 펼친 내용. 0 / 24 / 16 · 14 / 22 ·fg-neutral-muted· 줄바꿈 문자를 지킨다. 접혀 있으면 그리지 않는다. 높이 300ms · 모션 줄이기면 150ms 서서히.AccordionPlainItem— 상세가 없는 항목.title(필수) ·description·prefixIcon. 단추 · 머리말 · 꺾쇠가 없고 높이 · 글 시작은 트리거와 같다.AccordionHeader— 시트 · 대화상자의 목록 머리.title(필수 — 건수를 붙인다) · 자식(오른쪽 — 모두 펼치기). 카드 안이면 쓰지 않고CardHeader가 그 자리다.AccordionExpandAll— 모두 펼치기.controls(아코디언의id) ·values·expandable(상세가 있는 항목의value목록) ·onValuesChange(values). 모두 펼쳐져 있으면 "모두 접기" — 글은 단추가 정한다. 아코디언과 같은values를 쥔다.
혜택 상세 — 시트 · 대화상자(separated)
혜택 상세 · 12건
import { useState } from "react"
import {
Accordion,
AccordionContent,
AccordionExpandAll,
AccordionHeader,
AccordionItem,
AccordionPlainItem,
AccordionTrigger,
} from "@/components/ui/accordion"
const [open, setOpen] = useState<string[]>([]) // 처음에는 모두 접힘
const expandable = benefits.filter((b) => b.detail).map((b) => b.id)
<AccordionHeader title={`혜택 상세 · ${benefits.length}건`}>
<AccordionExpandAll controls="benefit-detail" values={open} expandable={expandable} onValuesChange={setOpen} />
</AccordionHeader>
<Accordion id="benefit-detail" variant="separated" values={open} onValuesChange={setOpen}>
{benefits.map((b) =>
b.detail ? (
<AccordionItem key={b.id} value={b.id}>
<AccordionTrigger title={b.category} description={b.summary} />
<AccordionContent>{b.detail}</AccordionContent>
</AccordionItem>
) : (
// 상세가 없으면 그냥 줄 — 막힌 트리거로 그리지 않는다
<AccordionPlainItem key={b.id} title={b.category} description={b.summary} />
),
)}
</Accordion>카드 상세 — 혜택(inline)
import { useState } from "react"
import {
Accordion,
AccordionContent,
AccordionExpandAll,
AccordionItem,
AccordionPlainItem,
AccordionTrigger,
} from "@/components/ui/accordion"
import { Card, CardHeader, CardTitle } from "@/components/ui/card"
const [open, setOpen] = useState<string[]>([])
const expandable = benefits.filter((b) => b.detail).map((b) => b.id)
{/* 카드 제목이 h2 라 트리거는 h3(기본) — 트리거가 카드 가장자리까지, 카드 아래 8 */}
<Card body="accordion">
<CardHeader>
<CardTitle>혜택 · {benefits.length}건</CardTitle>
<AccordionExpandAll controls="card-benefits" values={open} expandable={expandable} onValuesChange={setOpen} />
</CardHeader>
<Accordion id="card-benefits" values={open} onValuesChange={setOpen}>
{benefits.map((b) =>
b.detail ? (
<AccordionItem key={b.id} value={b.id}>
<AccordionTrigger title={b.category} description={b.summary} />
<AccordionContent>{b.detail}</AccordionContent>
</AccordionItem>
) : (
<AccordionPlainItem key={b.id} title={b.category} description={b.summary} />
),
)}
</Accordion>
</Card>Behavior
| 인터랙션 | 동작 |
|---|---|
트리거 누르기 · Enter · Space | 그 항목만 펼치고 접는다 — 다른 항목은 그대로(여럿). 초점은 트리거에 그대로, 저절로 스크롤하지 않는다 |
↓ · ↑ | 다음 · 앞 트리거로 — 끝에서 처음으로 돌아간다. 상세가 없는 줄 · 막힌 트리거는 건너뛴다 |
Home · End | 첫 · 끝 트리거 |
Tab | 트리거 → 펼친 내용 안의 초점 가는 것 → 다음 트리거. 상세가 없는 줄은 건너뛴다 |
| 모두 펼치기 | 상세가 있는 항목을 모두 펼친다 → 글이 "모두 접기". 하나라도 접혀 있으면 다시 "모두 펼치기". 초점은 단추에 그대로 |
| 상세가 없는 줄 | 누르기 · 키보드 없음 — 바탕도 생기지 않는다 |
| Disabled | 누르기 · 키보드 불가, 화살표 이동에서 빠진다. 펼친 채 막히면 내용은 그대로 보인다 |
| 모션 줄이기 | 높이 움직임 없이 150ms 서서히 · 꺾쇠는 바로 · 누름 축소 없음 |
Accessibility
| 기준 | 검증 |
|---|---|
| WCAG 1.4.3 Color contrast(글자 ≥ 4.5:1) | 제목 fg-neutral 흰 면 16.41 · 다크 13.42(시트 11.62), 설명 fg-neutral-subtle 5.50 · 6.09(시트 5.27, 누름 바탕 5.18 · 4.68), 모두 펼치기 fg-neutral-muted 7.11 · 7.70(시트 6.67, 누름 바탕 6.70 · 5.93), 펼친 내용 fg-neutral-muted 7.11 · 7.70(시트 6.67) ✓. 막힘 fg-disabled 는 기준 밖(비활성 UI) |
| WCAG 1.4.11 Non-text contrast(≥ 3:1) | 꺾쇠 fg-neutral-subtle 5.50 · 6.09 ✓. 사이 선(1.15 · 1.30) · separated 테두리(1.23 · 1.56)는 묶음을 나눌 뿐이다 — 펼침은 꺾쇠 · 내용이 알린다. 키보드 포커스 링 Desk 8.38 · 6.10 · HR 8.17 · 6.07 ✓ |
| WCAG 1.4.1 Use of color | 펼침은 꺾쇠 방향과 보이는 내용으로 알린다 ✓ |
| WCAG 2.1.1 Keyboard | Tab · Enter · Space · ↓ ↑ · Home · End ✓ |
| WCAG 2.4.3 Focus order | 펼쳐도 초점은 트리거에 — 펼친 내용은 트리거 바로 뒤 차례 ✓ |
| WCAG 2.4.7 Focus visible | 트리거 안쪽 링 2px — 카드 · 시트의 overflow: hidden 에 잘리지 않는다 ✓ |
| WCAG 2.5.8 Target Size — Minimum(AA ≥ 24×24) | 트리거 줄 전체 54 이상 · 모두 펼치기 44 ✓ |
| WCAG 2.5.5 Target Size — Enhanced(AAA ≥ 44×44) | 트리거 54 이상 · 모두 펼치기 44(보이는 36 위아래 4 씩) ✓ |
| WCAG 4.1.2 Name, Role, Value | 트리거는 heading > button — 이름은 제목 + 설명, aria-expanded · aria-controls(펼친 내용의 id). 모두 펼치기는 aria-controls(아코디언 id)이고 이름은 보이는 글("모두 펼치기" · "모두 접기") ✓ |
| ARIA | APG Accordion — 머리말 단계는 놓인 자리를 따른다(기본 h3). 펼친 내용에 role="region" 을 두지 않는다 — 함께 열리는 항목이 많아 랜드마크가 늘어난다(APG). 상세가 없는 줄은 머리말 · 단추가 아닌 글이다. 앱은 트리거를 Semantics(button: true, expanded: …) 로, 접힌 내용은 의미 트리에서 뺀다 — 이름은 제목 + 설명뿐이다 |
| Reduced motion | 높이 움직임 없이 150ms 서서히(v104) · 꺾쇠는 바로 · 누름 축소 없음 |
Do / Don't
✅ Do
- 상세가 긴 항목 여럿을 묶어 화면을 짧게 — 항목은 둘 이상.
- 트리거 줄 전체를 누르게 하고, 제목은 줄을 바꿔 다 보인다.
- 여럿을 함께 열고, 목록 머리 오른쪽에 모두 펼치기.
- 상세가 없는 항목은 그냥 줄로 — 높이 · 글 시작은 같게.
- 펼쳐도 초점 · 스크롤을 그대로 두고, 길면 페이지가 스크롤하게.
❌ Don't
- 꺾쇠만 누르게 하기 · 글 단추로 트리거 만들기.
- 다른 항목을 열면 앞 항목을 닫기.
- 상세가 없는 항목을 막힌 트리거로 · 꺾쇠만 뒤집히게.
- 패널 안에 스크롤 상자 · 펼칠 때 저절로 스크롤 · 초점 옮기기.
- 제목 · 설명을 말줄임 · 줄 수로 자르기.
- 늘 보여도 되는 짧은 내용을 접기 · 항목 하나짜리 아코디언.
- 불투명도로 흐린 막힘 · 펼침 상태 없는 트리거(앱은 의미 노드에 펼침 상태).
Specification
accordion.yaml 의 규칙을 하나도 빼지 않고 조건마다 그린다 — 웹 · 앱이 Accordion 을 만들 때 이 값을 그대로 쓴다. 조건이 없는 Base 가 모든 조합에 걸리고, 뒤의 규칙이 앞의 같은 값을 덮는다. 상태는 enabled 에서 바뀌는 값만 적었다.
Base
| 부위 | 상태 | 속성 | 값 |
|---|---|---|---|
root | enabled | 간격gap | 0pxinline — 항목 사이는 선이 가른다(separated 는 8) |
| 항목items | 2개 이상항목이 하나면 Collapsible 이다(SEED Don't — 단일 Item) | ||
item | enabled | 배경background | transparent놓인 면 그대로 — 화면 · 시트 · 대화상자 · 카드 |
heading | enabled | 머리말 단계level | h3SEED headingLevel 기본 3 — 놓인 자리의 머리말 차례에 맞춘다. 대화상자 · 시트 · 카드 제목(h2) 아래면 h3, 그 위 머리말이 h3 이면 h4 |
trigger | enabled | 최소 높이minHeight | 54px위아래 16 + 제목 22. 제목이 줄을 바꾸면 늘어난다 |
| 상하 여백paddingY | spacing-x416pxSEED medium paddingY x4 | ||
| 좌우 여백paddingX | spacing-global-gutter24px화면 가장자리 규칙 24(SEED global-gutter 16) | ||
| 커서cursor | pointer | ||
| 터치 영역touchTarget | 트리거 전체줄 폭 × 54 이상 — 꺾쇠만이 아니라 줄 전체가 누르는 자리(SEED). AA ✓ · AAA ✓ | ||
| 글 맞춤textAlign | left | ||
background | enabled | 바탕 들임insetX | 0px |
| 모서리radius | 0px | ||
| 배경background | transparent | ||
| 전환 대상transitionProperty | background-color, inset, border-radius누르면 바탕이 안쪽으로 들어오며 둥글어진다(List 와 같다) | ||
| 전환 시간transitionDuration | motion-duration-color-transition150ms | ||
| 전환 곡선transitionEasing | motion-ease-easingcubic-bezier(0.35, 0, 0.35, 1) | ||
content | enabled | 간격gap | spacing-x312px앞 아이콘 ↔ 본문 ↔ 꺾쇠 12 — SEED prefix paddingRight · suffixIcon paddingLeft x3 |
| 세로 맞춤alignItems | center제목이 여러 줄이어도 앞 아이콘 · 꺾쇠는 트리거 가운데 | ||
| 전환 대상transitionProperty | scale | ||
| 전환 시간transitionDuration | motion-duration-pressed-scale150ms | ||
| 전환 곡선transitionEasing | motion-ease-pressed-scalecubic-bezier(0, 0, 0.15, 1) | ||
prefixIcon | enabled | 앞 아이콘size | 22px있을 때만 — SEED medium prefixIcon 22 |
| 앞 아이콘 색color | fg-neutral#1A1F2E다크 #F5F6FA | ||
body | enabled | 간격gap | spacing-x0_52px제목 ↔ 설명 2 |
title | enabled | 글자·아이콘foreground | fg-neutral#1A1F2E다크 #F5F6FA |
| 글자typography | text-t516px / 22px | ||
| 굵기fontWeight | 500SEED medium | ||
| 줄 수lineClamp | none늘 줄을 바꾼다 — 말줄임 · 줄 수 제한 없음(사용자 결정 10A, 단어 단위 v114) | ||
description | enabled | 글자·아이콘foreground | fg-neutral-subtle#62697A다크 #A2A8B7 |
| 글자typography | text-t313px / 18px | ||
| 굵기fontWeight | 500SEED accordion-item description medium — 머리 제목 500 과 한 벌. 글자 역할 R9 의 "여닫는 머리 설명"(2026-10-17 사용자 결정 01T-005 — 줄 설명 400 에 맞추지 않는다) | ||
| 줄 수lineClamp | none늘 줄을 바꾼다 | ||
chevron | enabled | 크기size | 20pxlucide chevron-down — 접혀 있으면 아래 |
| 색color | fg-neutral-subtle#62697A다크 #A2A8B7흰 면 5.50 · 다크 6.09(시트 5.27) | ||
| 회전rotate | 0deg | ||
| 전환 대상transitionProperty | rotate | ||
| 전환 시간transitionDuration | motion-duration-d6300ms | ||
| 전환 곡선transitionEasing | motion-ease-easingcubic-bezier(0.35, 0, 0.35, 1) | ||
panel | enabled | 최대 높이maxHeight | none패널 안에서 스크롤하지 않는다 — 길면 페이지 · 시트 본문이 스크롤한다(SEED Don't) |
| 좌우 여백paddingX | spacing-global-gutter24px트리거와 같은 24 — 앞 아이콘이 있어도 같다. 펼친 내용은 줄 폭을 쓴다 | ||
| 위 여백paddingTop | 0px | ||
| 아래 여백paddingBottom | spacing-x416px트리거 위아래와 같은 16 | ||
| 보이기display | 숨김접혀 있으면 내용을 그리지 않는다 — 보조 기술도 읽지 않는다(앱도) | ||
panelText | enabled | 글자·아이콘foreground | fg-neutral-muted#535866다크 #B7BDCC흰 면 7.11 · 다크 7.70(시트 6.67) |
| 글자typography | text-article-note14px / 22px14 / 22 — 긴 글 보조. 비교 페이지가 그린 14 / 22 가 이 토큰 그대로다 | ||
| 굵기fontWeight | 400 | ||
header | enabled | 최소 높이minHeight | 36px모두 펼치기의 보이는 상자와 같은 높이 — 제목과 한 줄(2026-10-16 글자 역할 D2 — 글 버튼 36, 전 32) |
| 아래 바깥 여백marginBottom | spacing-x28px머리 ↔ 첫 항목 8 — separated 의 카드 사이와 같다 | ||
| 간격gap | spacing-x28px | ||
| 세로 맞춤alignItems | center | ||
| 가로 맞춤justifyContent | space-between | ||
headerTitle | enabled | 글자·아이콘foreground | fg-neutral#1A1F2E다크 #F5F6FA |
| 글자typography | text-t516px / 22pxCard 머리 제목과 같다 — 건수를 붙인다("혜택 상세 · 12건") | ||
| 굵기fontWeight | 700 | ||
expandAll | enabled | 높이height | 36px보이는 상자 — SEED Text Button(minHeight x9), Card 머리 동작과 같은 모양(card.yaml headerAction). 2026-10-16 사용자 결정 — 글자 역할 D2 |
| 왼쪽 여백paddingLeft | spacing-x3_514px | ||
| 오른쪽 여백paddingRight | spacing-x3_514px좌우 14 — 줄 끝에서는 오른쪽 14 만큼 바깥으로 내어 글자 끝이 머리 여백에 선다 | ||
| 모서리radius | radius-r28px | ||
| 글자·아이콘foreground | fg-neutral-muted#535866다크 #B7BDCCSEED Text Button fg.neutral-muted — 2026-10-16 사용자 결정 글자 역할 D2(전 subtle). 아이콘은 두지 않는다(전 chevrons-up-down · chevrons-down-up 16) — 글이 "모두 펼치기" · "모두 접기" 로 바뀌며 상태를 말한다 | ||
| 글자typography | text-t414px / 19px | ||
| 굵기fontWeight | 700SEED Text Button t4 · bold — 2026-10-16 사용자 결정 글자 역할 D2(전 500) | ||
| 터치 영역touchTarget | 44 × 44보이는 36 위아래로 4 씩 · 옆은 글 폭 + 여백. AA ✓ · AAA ✓ | ||
| 전환 대상transitionProperty | background-color | ||
| 전환 시간transitionDuration | motion-duration-color-transition150ms | ||
| 전환 곡선transitionEasing | motion-ease-easingcubic-bezier(0.35, 0, 0.35, 1) | ||
| 자리position | 목록 머리 오른쪽시트 · 대화상자 목록 머리, 카드 머리의 오른쪽 동작 자리 | ||
| 글label | 모두 펼치기 · 모두 접기상세가 있는 항목이 모두 펼쳐져 있으면 "모두 접기" — 하나라도 접혀 있으면 "모두 펼치기" | ||
background | hovered | 바탕 들임insetX | spacing-x1_56px바탕이 좌우 6 들어온다(SEED marginX x1_5) |
| 모서리radius | radius-r2_510pxSEED cornerRadius x2_5 — separated 면(16) 안에서도 16 − 6 = 10 으로 동심 | ||
| 배경background | bg-layer-default-pressed#F7F8FD다크 #353B4DSEED bg.transparent-pressed 의 불투명 짝 — 시트 · 대화상자 위에서도 같은 값(bg-layer-floating-pressed 와 같다) | ||
expandAll | hovered | 배경background | bg-layer-default-pressed#F7F8FD다크 #353B4D |
expandAll | focused | 외곽선outlineColor | stroke-focus-ringDesk#0147AD다크 #7AA9F6HR#075B3C다크 #2ABE84 |
| 외곽선 두께outlineWidth | 2px모두 펼치기 단추의 키보드 링 — Card 머리 동작과 같다(card.yaml focused) | ||
| 외곽선 간격outlineOffset | 2px단추 바깥 | ||
focusRing | focused | 링 두께width | 2px |
| 모서리radius | 0pxinline — 줄과 같은 각진 링(List 와 같다) | ||
| 링 색color | stroke-focus-ringDesk#0147AD다크 #7AA9F6HR#075B3C다크 #2ABE84 | ||
| 링 간격offset | -2px트리거 안쪽 — 카드 · 시트가 바깥 링을 자르지 않게(지금 웹 카드 혜택은 카드 셸에 잘려 안 보인다) | ||
background | pressed | 바탕 들임insetX | spacing-x1_56px |
| 모서리radius | radius-r2_510px | ||
| 배경background | bg-layer-default-pressed#F7F8FD다크 #353B4D | ||
content | pressed | 배율scale | 2px 거리 축소콘텐츠 층만(SEED scaleScope content) — 기준 길이 max(높이, 폭 ÷ 4, 24) 에서 2px(v104) |
expandAll | pressed | 배경background | bg-layer-default-pressed#F7F8FD다크 #353B4D |
| 배율scale | 2px 거리 축소글 단추만 — Card 머리 동작과 같다 | ||
trigger | disabled | 커서cursor | not-allowed누르기 · 펼치기 불가 — 상세가 없는 항목은 막힌 트리거가 아니라 그냥 줄(detail none) |
prefixIcon | disabled | 앞 아이콘 색color | fg-disabled#8A91A0다크 #838997 |
title | disabled | 글자·아이콘foreground | fg-disabled#8A91A0다크 #838997 |
description | disabled | 글자·아이콘foreground | fg-disabled#8A91A0다크 #838997 |
chevron | disabled | 색color | fg-disabled#8A91A0다크 #838997 |
variant=inline
| 부위 | 상태 | 속성 | 값 |
|---|---|---|---|
divider | enabled | 높이height | 1px |
| 좌우 바깥 여백marginX | spacing-x624px들인 선 24 — List 의 들인 선과 같다(SEED dividerPaddingX 12 의 groo 짝) | ||
| 배경background | stroke-neutral-subtle#EDEFF3다크 #353B4DSEED dividerColor 와 같은 역할 | ||
| 보이기display | 항목 사이첫 항목 위 · 마지막 항목 아래에는 긋지 않는다(Divider — 마지막 선 금지) |
variant=separated
| 부위 | 상태 | 속성 | 값 |
|---|---|---|---|
root | enabled | 간격gap | spacing-x28pxCard 사이 8(사용자 결정 1B) — SEED separated medium 12 는 카드에서 거절됐다(데이터 표시 5A) |
item | enabled | 모서리radius | radius-r416pxCard 면 16(SEED r3 12) — 안의 누름 바탕은 16 − 6 = 10 으로 동심 |
| 테두리borderColor | stroke-neutral-weak#E5E8EF다크 #404757Card 테두리 — SEED separated strokeColor 와 같은 역할 | ||
| 테두리 두께borderWidth | 1px | ||
| 그림자shadow | none그림자 없음 — Card 면 | ||
| 넘침overflow | hidden누름 바탕 · 펼친 내용을 모서리에서 자른다 — 포커스 링은 안쪽이라 잘리지 않는다 | ||
focusRing | focused | 모서리radius | radius-r3_514px항목 모서리 16 − 링 들임 2 = 14 — 트리거가 항목 맨 위라 모서리를 따른다 |
open=expanded
| 부위 | 상태 | 속성 | 값 |
|---|---|---|---|
chevron | enabled | 회전rotate | 180deg위로 — SEED Expanded |
panel | enabled | 보이기display | 보임펼쳐도 저절로 스크롤 · 초점 이동하지 않는다 — 초점은 트리거에 그대로(SEED) |
description=shown
| 부위 | 상태 | 속성 | 값 |
|---|---|---|---|
trigger | enabled | 최소 높이minHeight | 74px위아래 16 + 제목 22 + 2 + 설명 18 |
detail=none
| 부위 | 상태 | 속성 | 값 |
|---|---|---|---|
heading | enabled | 머리말 단계level | 없음머리말 · 단추로 감싸지 않는다 — 글만 읽힌다(Tab 이 건너뛴다) |
trigger | enabled | 커서cursor | default트리거가 아니다 — 같은 위아래 16 · 좌우 24 로 높이 · 글 시작이 다른 항목과 같다(사용자 결정 5A) |
| 터치 영역touchTarget | 없음누르는 줄이 아니다 | ||
chevron | enabled | 보이기display | none꺾쇠를 두지 않는다 — 막힌 트리거 · 꺾쇠만 뒤집히는 줄은 고르지 않았다(5B · 5C) |
background | hovered | 바탕 들임insetX | 0px |
| 모서리radius | 0px | ||
| 배경background | transparent바탕이 생기지 않는다 — 누를 것이 아니다 | ||
background | pressed | 바탕 들임insetX | 0px |
| 모서리radius | 0px | ||
| 배경background | transparent | ||
content | pressed | 배율scale | 없음줄지 않는다 |
SEED 와 다른 점
- 트리거 좌우 24(
spacing-global-gutter— groo 화면 가장자리 규칙). SEED 는 16. inline사이 선은 List 의 들인 선 — 좌우 24. SEED 는 12(색은 같은stroke-neutral-subtle).separated면은 groo Card 면 — 모서리 16 · 사이 8. SEED 는 12 · 12(medium) — 데이터 표시 라운드에서 카드에 거절된 값이다.- 누름 바탕은 불투명한
bg-layer-default-pressed— SEED bg.transparent-pressed 는 투명도가 있어 검사기가 받지 않는다(v102). 들임 6 · 모서리 10 · 콘텐츠만 축소는 SEED 그대로다. - 크기는 medium 하나 — SEED large(PC 대응 — 제목 20 · 설명 16 · 꺾쇠 24 · 위아래 20)는 두지 않는다. SEED react 의
responsive도 없다. - 늘 여럿을 함께 열고 "모두 펼치기" 를 둔다 — SEED react 의 기본은 하나만이고 모두 펼치기가 없다.
- 상세가 없는 항목은 그냥 줄 — SEED 에 규칙이 없다.
- 펼친 내용의 글 모양을 정한다(
text-article-note·fg-neutral-muted· 0 / 24 / 16) — SEED AccordionContent 는 여백 · 글자가 없다. - 포커스 링(웹)은 groo 가 정했다 — 트리거 안쪽 2px(
separated는 모서리 14). SEED 는 아코디언의 포커스 링을 적지 않았다.
Migration notes
2026-10-22 — separated 는 흰 표면 위 · 예시 이름
separated 를 두는 자리를 "흰 표면 위에만" 으로 남기고 화면 이름은 DESIGN.md Layout "화면 바탕" 으로 보냈다 — 띠 안 테두리 카드 금지의 예외로 적었다(https://claude.ai/artifact/KrXqAymDPz1JKL5AWqdwKS 2B · 3B). 예시의 실제 카페 이름을 지어낸 이름(골목커피 · 숲속다방 · 달빛로스터리)으로 바꿨다 — 사이트 그림 · 레시피 예제 · 미리보기도 같이.
2026-10-21 — 목록 머리 큰 글자 · separated 자리(03-G)
결정 4 A — 목록 머리의 "모두 펼치기" 가 반 폭을 넘으면 제목 아래 줄로(레시피 AccordionHeader flex-wrap · 제목 최소 50%). 결정 7 A — separated 는 흰 표면 위에만, md 의 "Card 면" 을 "Card 모양(테두리 · 모서리 · 사이)" 으로 바로 적었다(yaml 은 처음부터 투명). 비교 페이지 https://claude.ai/artifact/A3oCdxNvDwkNBPFPE36bmF.
2026-10-16 — 모두 펼치기를 SEED Text Button 으로(글자 역할 D2)
사용자가 글자 역할 비교 페이지에서 글 버튼을 SEED Text Button 한 벌로 정했다(D2 A). 모두 펼치기는 Card 머리 동작과 같은 모양이라 함께 바뀐다 — 14 · 500 · fg-neutral-subtle · 보이는 32 · 아이콘 16 → 14 · 700 · fg-neutral-muted · 보이는 36(좌우 14) · 아이콘 없음 · 누르는 44(위아래 4). 시트 · 대화상자의 목록 머리 줄도 32 → 36. 옛 스펙은 accordion.history/v-pre-text-roles.*.
2026-10-10 — SEED Accordion 으로 다시 쓴다
사용자가 펼치고 접기 · 나누기 비교 페이지에서 정했다 — SEED 두 변형(1B — inline 기본 · separated 는 Card 면 16 · 1px · 사이 8), SEED medium 하나(2A — 제목 16 / 22 · 500 · 설명 13 / 18 · 꺾쇠 20 · 54 · 74, 폰 · 데스크톱 같음), 꺾쇠 180° · 높이 300ms ease-easing · 모션 줄이기면 150ms 서서히(3A), 여럿 + "모두 펼치기"(4A — 누르는 44 · 펼치면 "모두 접기"), 상세 없는 항목은 그냥 줄(5A), 카드 상세 혜택은 웹 · 앱 모두 접는 목록(6A), 잘린 글은 자르지 않는다(10A). 그리고 "따라오는 것" — heading > button(기본 h3) · aria-expanded · aria-controls · Enter Space · ↓ ↑ 돌아가며 · Home End · 트리거 전체가 누르는 자리 · 항목 2개 이상 · 펼칠 때 자동 스크롤 · 초점 이동 없음 · 패널 안 스크롤 없음 · 줄 좌우 24 · 선은 List 선 · 눌림은 List 눌림 · 꺾쇠 fg-neutral-subtle · 제목은 늘 줄바꿈 · 막힘은 전용 색 · 앱 의미 노드(단추 + 펼침 상태, 접힌 내용은 읽지 않는다). 지금 제품 모양(1A) · separated 만(1C) · medium + 데스크톱 large(2B) · 지금 14(2C) · 200ms(3B) · 움직임 없음(3C) · 단추 없음(4B) · 하나만(4C) · 막힌 트리거(5B) · 꺾쇠만 뒤집힘(5C) · 둘 다 펼친 목록(6B)은 고르지 않았다. 옛 스펙은 accordion.history/v-pre-seed-collapse.* 에 남겼다.
| 옛 Accordion | 새 Accordion |
|---|---|
Radix Accordion 베이스 · 하나만(single 기본) · 여럿 | 늘 여럿 + 모두 펼치기 — 하나만 여는 모드는 없다 |
외곽 없이 아래 선만(border-default) · 끝까지 | inline 들인 선 24(마지막 선 없음) · separated Card 면 |
트리거 위아래 16 · 좌우 0 · title-sm 16 · 500 | 위아래 16 · 좌우 24 · 제목 16 / 22 · 500 + 설명 13 / 18 · 500 · 54 · 74 |
꺾쇠 16 text-secondary · 200ms(motion-duration-base — 옛 이름) | 꺾쇠 20 fg-neutral-subtle · 300ms ease-easing(d6) |
| 호버는 글자색 · 바탕 없음 | 누름 · 호버 바탕(들임 6 · 모서리 10) + 콘텐츠만 2px |
펼친 내용 body-md · text-secondary · 아래 16 | text-article-note 14 / 22 · fg-neutral-muted · 0 / 24 / 16 |
| 포커스 링 바깥 2px 띄움 | 트리거 안쪽 2px — 카드 · 시트에 잘리지 않는다 |
| 막힘 불투명도 0.5 | 전용 색 fg-disabled · 상세가 없는 항목은 그냥 줄 |
| "헤딩은 사용처에서 H3/H4 wrap 권장" | 트리거가 머리말을 그린다 — headingLevel(기본 3) |
제품은 앱 적용 단계에서 옮긴다(2026-10-09 조사 — Desk 웹은 크로미움에 띄워 쟀고, Desk 앱은 위젯 테스트, HR 은 렌더로 쟀다). 아코디언 부품을 쓰는 곳은 셋 다 0 이고, 자리마다 손으로 짰다.
- 웹 카드 혜택 상세(대화상자 · 폰 서랍) — 항목마다 카드(모서리 8 · 1px #EDEFF3 1.15) · 안쪽 14 / 16 · 제목 14 / 700 · 값 12.5 / 700 브랜드(눈금 밖 글자) · 꺾쇠 16 바꿔치기 · 움직임 0 ·
aria-expanded0 · 머리말 0(pages/card-benefit/ui/CardBenefitDetailDialog.tsx:262-470, D4 · D22). 키보드 포커스 링이 카드 셸overflow: hidden에 통째로 잘려 보이지 않는다(:262-267 · 399-402, D1). 상세가 없는 2건은 꺾쇠만 위로 뒤집힌다(:472, D5). 모두 펼치기는 accent sm 90.6 × 32 · 12 / 500 이다.separated· 모두 펼치기 44 로. - 웹 카드 상세 혜택 · 유의사항 —
ul.divide-y줄마다 Radix Collapsible · 끝까지 선 #EDEFF3 · 호버bg-muted/40(1.03) · 배지 + 14 / 500 · tw-animate 200ms ease-out · 머리말 0(widgets/card-detail/ui/AvailableBenefitsList.tsx:49-94·CardCautionList.tsx:23-58). 상세가 없으면<button disabled>라 "사용할 수 없음" 으로 읽힌다(AvailableBenefitsList.tsx:60·CardCautionList.tsx:34, D5). 혜택 본문은 왼쪽 60 인데 제목은 16 이라 44 어긋난다(AvailableBenefitsList.tsx:83, D16). 유의사항 제목은truncate라 84자 가운데 데스크톱 612 / 751px · 폰 282 / 751px 만 보인다(CardCautionList.tsx:37, D11). 카드 안inline(Card body="accordion") · 제목 줄바꿈으로. - 앱 혜택 시트 —
PCard bordered(모서리 12) · 제목 14 bold · 요약 13 boldfgBrand· 조건 배지가 다음 줄 · 꺾쇠 16 150ms linear · 본문SizeTransition200ms(features/card/presentation/card_benefit_detail_sheet.dart:164-210 · 479-590). 트리거 의미 노드에 단추 · 펼침 상태가 없고 접힌 상세 본문까지 이름으로 읽는다(:498-590·shared/widgets/p_collapsible.dart:94-100, D2). 본문 왼쪽 24 ↔ 트리거 16(:578-583, D16), 상세가 없으면 꺾쇠만 돈다(:568-590, D5). - 앱 카드 상세 — 혜택은 접지 않고 상세 본문까지 다 보이고, 유의사항은 주황 상자 안 caption 줄이며 상자 전체가 한 덩어리로 읽힌다(
features/card/presentation/card_detail_screen.dart:153-236 · 399-410, D15 · D2). 웹과 같은 카드 안inline으로 — 유의사항 트리거도 단추 + 펼침 상태로 읽힌다. 주황 상자를 둘지는 이번 결정 밖이다. - 모션 줄이기 — 펼침이 줄이기를 따르는 곳이 0 이다(웹
reducedMotion: reduce렌더 · 앱disableAnimations위젯 테스트 모두 그대로 움직였다, D9). 시간도 0 · 150 · 200ms 로 제각각이다. - 쓰지 않는 것 — 앱
shared/widgets/p_accordion.dart(PAccordion·PAccordionMultiple— 옛 스펙을 옮긴 것, 쓰는 곳 0)는 이 스펙으로 다시 만들거나 걷는다(D21). 웹에는accordion.tsx·@radix-ui/react-accordion이 없다(조사 S1 — 옛 스펙이 적은 "기존 accordion.tsx" 는 없었다). - 스펙 글 — DESIGN.md v70 Accordion(트리거 바탕 · 테두리 · 호버 바탕 · 투명도 펼침 ·
region)이 이 스펙과 반대였다(조사 S6) — "펼치고 접기 · 나누기" 절로 바꿨다.
이전 기록
- 2026-05 — site 에 맞춤. 외곽 없이 아래 선만 ·
title-sm트리거 ·body-md내용 · 꺾쇠 16 · 200ms 로 정리했다(옛 preview 의 카드형 외곽을 걷음). 이번에 모두 바뀌었다.