ExpandButton (확장버튼)
Va.ExpandButton — 인라인 확장/축소 버튼
버튼을 누르면 바로 아래에 컨텐츠 영역이 슬라이드로 펼쳐지는 컴포넌트입니다. MenuButton과 달리 팝업(floating)이 아니라 인라인으로 자식을 드러내므로, 뒤에 오는 콘텐츠를 밀어냅니다. 아코디언 항목, 접이식 카드, 세부 옵션 토글 같은 UI에 쓰입니다.
- 클래스: Va.ExpandButton — va_component.js:13780
- short name: expandButton
- 상속: Va.Component
- isContainer: true — 자식으로 아무 컴포넌트나 담을 수 있음 (button, menuItem, 심지어 중첩 expandButton도 가능)
- 베이스 CSS: va-expand-button, 확장 영역은 va-menu-expand

1. 기본 사용
{
tagName: 'expandButton',
text: '고급 설정',
tags: [
{ tagName: 'button', text: '옵션 1' },
{ tagName: 'button', text: '옵션 2' },
{ tagName: 'button', text: '옵션 3' }
]
}
버튼 클릭 → 아래로 세 개 버튼이 슬라이드하며 펼쳐짐. 다시 누르면 접힘.
중첩 (재귀 확장)
{
tagName: 'expandButton',
text: 'Level 1',
tags: [
{ tagName: 'button', text: 'item' },
{
tagName: 'expandButton',
text: 'Level 2',
tags: [
{ tagName: 'button', text: 'sub item' }
]
}
]
}
트리형 접이 메뉴가 자연스럽게 만들어집니다 — DemoExpandButton의 Method Test 섹션 참조 (DemoExpandButton.js:813-834).
2. Va.MenuButton과의 차이 (가장 헷갈리는 부분)
항목Va.MenuButtonVa.ExpandButton
| 자식 표시 방식 | floating 팝업 (레이아웃 밀어내지 않음) | 인라인 (뒤 콘텐츠를 밀어냄) |
| 팝업 위치 계산 | 뷰포트 뒤집기, IntersectionObserver, hiddenArea 이동 | 없음 — 그냥 그 자리에서 펼침 |
| 오토하이드 | ✓ (외부 클릭 시 자동 닫힘) | ✕ (한 번 열면 다시 눌러야 접힘) |
| 키보드 네비 | Esc/Tab/Enter/↓↑ 처리 | 기본 focus만 |
| data / template | ✓ (자동 menuItem 생성) | ✕ — tags로 직접 자식 지정 |
| 자식 타입 | 주로 menuItem | 임의 컴포넌트 (button/menuItem/expandButton 등) |
| 화살표 아이콘 | 열림/닫힘 아이콘 1개 (menuIcon) | 열림/닫힘 아이콘 2개 (menuIcon + menuIconExpand) |
| 아이콘 위치 | 항상 우측 | menuIconPosition으로 좌/우 지정 가능 |
| 서브메뉴 재귀 | ✓ (data.list) | 인라인 중첩만 (팝업 아님) |
| 콜백 | itemClick / select | 없음 — 자식 각자가 이벤트 소유 |
한 줄 요약: MenuButton은 "드롭다운 메뉴", ExpandButton은 "아코디언".
3. 주요 속성
버튼 표현 (Button/MenuButton과 공통)
속성설명
| text / innerHTML | 버튼 라벨 |
| icon, iconPosition, iconOnly | 좌측(또는 지정 위치) 아이콘 |
| appearance, shape, size | 시각 스타일 |
| disabled | 비활성화 |
| badge | 배지 부착 |
| stopPropagation | 이벤트 버블링 차단 (기본 true) |
확장 아이콘 (열림/닫힘 표시)
속성기본값설명
| menuIcon | 'ico_chevron_down' | 닫힘 상태 표시 아이콘 |
| menuIconExpand | 'ico_chevron_up' | 열림 상태 표시 아이콘 |
| menuIconVisible | true | 아이콘 표시 여부 |
| menuIconPosition | 'right' | 아이콘 위치 ('left'|'right') |
MenuButton과 결정적 차이 — 열림/닫힘 아이콘을 별도로 지정할 수 있습니다. 아코디언 UI에서 + / - 같은 명확한 상태 표시에 유용합니다.
{
tagName: 'expandButton',
text: '접기/펼치기',
menuIcon: 'ico_add', // 닫힘 → +
menuIconExpand: 'ico_subtract', // 열림 → −
tags: [ ... ]
}
확장 영역
속성설명
| expanded | 현재 확장 상태 (boolean) |
| expandChildCheck | 자식이 없으면 확장 안 함 (기본 true) |
| popWidth | (선언되어 있지만 인라인이라 실효 제한적) |
4. 이벤트
이벤트발생 시점
| click | 버튼 클릭 (매번, 상태 토글과 함께) |
| expand | 펼쳐질 때 |
| collapse | 접힐 때 |
| beforePop | 상태 변경 직전 |
| afterPop | 상태 변경 직후 |
| hidePop | 숨김 요청 시 |
| focus / blur | 포커스 진입/이탈 |
| contextmenu | 우클릭 |
| iconClick | 좌측 icon (menuIcon이 아닌 사용자 지정 icon) 클릭 |
이벤트 순서: 클릭 시 beforePop → 상태 토글 → update() → click → afterPop → (expand 또는 collapse) (va_component.js:13845-13864)
주의: MenuButton과 달리 itemClick / select가 없습니다. 자식(내부 버튼 등)의 클릭은 자식 컴포넌트가 각자 처리합니다.
5. 메서드
메서드설명
| setText(text) / setInnerHTML(html) | 라벨 변경 |
| setIcon(icon) | 아이콘 변경 |
| setAppearance(v) / setShape(v) / setSize(v) | 시각 속성 변경 |
| setDisabled(bool) | 비활성화 |
| expand() | 펼치기 |
| collapse() | 접기 |
| focus() / blur() | 포커스 제어 |
| hidePop() | 팝업 숨김 (레거시 인터페이스, 인라인이라 실효 제한) |
showPop()은 껍데기 함수만 있고 실제 동작은 update() 내부에서 expandElement.style.display로 처리됩니다.
6. 내부 구조
<div elname="element" class="va-expand-button">
<div elname="inner" class="expand-button-inner">
<button elname="button" class="va-button" tabindex="0">
<span elname="buttonInner" class="button-inner">
<!-- menuIconPosition='right'일 때 (기본) -->
<span elname="content" class="button-content">
<span elname="icon" class="icon">…</span> ← icon 지정 시
<span elname="text" class="text">라벨</span>
</span>
<span elname="menuIcon" class="icon menu ico_chevron_down">…</span>
<span cpname="badge">…</span> ← badge 지정 시
</span>
</button>
<div elname="expand" class="va-menu-expand" style="display:none">
<div elname="expandInner" class="menu-expand-inner">
<!-- 자식 컴포넌트들이 여기 렌더됨 (containerElement) -->
</div>
</div>
</div>
</div>
핵심은 expandElement가 element의 형제가 아니라 자손이라는 점입니다 — 그래서 인라인 흐름 안에서 자연스럽게 펼쳐집니다. MenuButton은 열릴 때 hiddenArea로 옮기지만, ExpandButton은 절대 옮기지 않습니다.
7. 애니메이션 (열림/닫힘 전환)
update()에서 상태 변경 시 CSS 애니메이션을 리셋해 재실행합니다 (va_component.js:13947-13974):
this.expandElement.style.animation = 'none';
this.expandElement.offsetHeight; // reflow 강제
this.expandElement.style.animation = '';
닫힘 시: collapsing 클래스 추가 → 300ms 대기 → display:none 처리. 열림 시엔 즉시 display:block. 이 300ms가 slide-up 애니메이션 시간과 맞아떨어집니다.
8. 언제 쓰나
ExpandButton이 맞을 때
- 아코디언 (FAQ, 폼 섹션 접기)
- "고급 옵션 보기" 같은 인라인 토글
- 트리 뷰의 접이식 노드 (재귀 구조 지원)
- 사이드바 카테고리 (하위 항목이 뒤 콘텐츠를 밀어내야 자연스러운 상황)
- 리스트 항목 상세 펼치기
다른 걸 쓸 때
- 뒤 콘텐츠를 밀어내면 안 됨 (플로팅 필요) → Va.MenuButton
- 액션 여러 개 중 하나 선택 → Va.MenuButton / Va.SplitButton
- 단순 열기/닫기 (버튼도 필요 없음) → Va.Details / Va.Summary
- 데스크톱은 팝업, 모바일은 인라인 → Va.ResponsiveButton (바로 다음에 정의된 형제 컴포넌트)