컴포넌트/버튼

ExpandButton (확장버튼)

VanillaFront 2026. 9. 9. 15:19

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 (바로 다음에 정의된 형제 컴포넌트)