카테고리 없음

ButtonGroup (버튼그룹)

VanillaFront 2026. 9. 9. 17:15

Va.ButtonGroup — 상호 배타적 선택을 자동화하는 버튼 컨테이너

여러 버튼을 나란히 담고, 하나가 선택되면 나머지는 자동으로 해제되는 라디오형 컨테이너입니다. Va.Div를 상속해 레이아웃 컨테이너 특성을 그대로 갖고, 그 위에 그룹 배타 선택 로직만 얹은 얇은 확장.

  • 클래스: Va.ButtonGroup  va_component.js:17484
  • short name: buttonGroup
  • 상속: Va.Div (다른 버튼 계열과 달리 Component 직속 아님)
  • isContainer: true
  • 베이스 CSS: va-div (Div의 것을 그대로 씀 — 자체 va-button-group 클래스 없음)


1. 기본 사용

{
    tagName: 'buttonGroup',
    layout: 'ds-flex fd-row ai-center gap-s',
    tags: [
        { tagName: 'toggleButton', text: '왼쪽 정렬' },
        { tagName: 'toggleButton', text: '가운데 정렬' },
        { tagName: 'toggleButton', text: '오른쪽 정렬' }
    ]
}

사용자가 어떤 버튼을 클릭하면:

  1. 그룹 안 모든 자식이 unselect() 호출됨
  2. toggleButton이면 unpress()까지 호출됨
  3. 클릭된 버튼만 select() (+toggleButton이면 press()) 됨

결과 — 언제나 하나만 선택된 라디오 UI가 자동으로 완성.


2. 다른 버튼/컨테이너와의 차이

항목Va.DivVa.ButtonGroup개별 Va.ToggleButton 나열

레이아웃 ✓ (Div 상속) ✕ (부모가 제공해야)
배타 선택 자동 ✕ (수동 처리 필요)
toggleButton press/unpress 자동 처리
이벤트 발화 없음 없음 (개별 버튼이 발화)
자체 상태 없음 없음 pressed

한 줄 요약: "여러 버튼을 라디오처럼 만드는 얇은 마법 컨테이너".


3. 속성

독자적 속성이 없습니다va_component.js:17489-17491에서 properties, events를 배열 spread만 하고 아무것도 추가하지 않습니다.

Va.Div의 모든 속성이 그대로 유효:

속성설명

layout Flex/Grid 레이아웃 (예: 'ds-flex fd-row ai-center gap-s')
mobileLayout 모바일 전용 레이아웃
style / mobileStyle 인라인 스타일
mediaQuery 반응형 속성
border, padding, margin  Div 공통

그룹 자체가 어떻게 정렬될지(가로/세로/gap)는 전적으로 layout 속성에 달려 있습니다.


4. 이벤트

독자 이벤트 없음. 그룹 자체는 이벤트를 dispatch하지 않고, 개별 자식 버튼의 이벤트에 의존합니다.

{
    tagName: 'buttonGroup',
    tags: [
        {
            tagName: 'toggleButton',
            text: '옵션 1',
            onClick: 'onOption1'    // ← 각 버튼이 자기 이벤트 처리
        },
        {
            tagName: 'toggleButton',
            text: '옵션 2',
            onClick: 'onOption2'
        }
    ]
}

⚠️ "어떤 게 선택됐는지" 이벤트가 없음 — Combobox처럼 change(selectedIndex) 같은 통합 이벤트가 그룹에서 발화되지 않습니다. 필요하면 개별 버튼 onClick에서 처리하거나, getChildComponents()로 순회해서 selected/pressed 상태를 조회해야 합니다.


5. 메서드

커스텀 메서드 없음 — Va.Div의 것을 그대로 씁니다.

메서드설명

append(button) 오버라이드됨 — 자식 추가 시 자동으로 배타 선택 클릭 핸들러 바인딩
getChildComponents() 자식 버튼 조회 (Component 공통)
removeChild(child) 자식 제거

append의 특별한 동작

동적으로 버튼을 추가할 때도 배타 선택이 유지됩니다 (va_component.js:17521-17536):

onAppend() {
    const btn = new Va.Button({ text: '동적 추가' });
    this.getRef('refButtonGroup').append(btn);
    // ← 여기 시점부터 이 새 버튼도 그룹의 배타 선택에 참여
}

Demo의 onAppend가 정확히 이 패턴을 보여줍니다 → DemoButtonGroup.js:13-23


6. 어떻게 동작하나 (내부 로직)

두 곳에서 배타 선택 핸들러를 바인딩합니다:

mounted() — 초기 자식들 (va_component.js:17504-17520)

mounted(){
    let buttons = this.getChildComponents();
    for(let i=0; i < buttons.length; i++){
        this._bindEvent(buttons[i].element, 'click', (evt) => {
            for(let j=0; j < buttons.length; j++){
                buttons[j].unselect();
                if(buttons[j].tagName == 'toggleButton'){
                    buttons[j].unpress();
                }
            }
            buttons[i].select();
            if(buttons[i].tagName == 'toggleButton'){
                buttons[i].press();
            }
        })
    }
}

append(button) — 동적으로 추가되는 자식 (va_component.js:17521-17536)

동일한 로직을 새 버튼에도 붙임.

주목할 점:

  • unselect() / select()는 모든 자식에게 호출되지만, 이 메서드가 없는 컴포넌트를 넣으면 크래시합니다. 자식은 반드시 select/unselect를 가진 버튼 계열이어야 합니다.
  • toggleButton만 press/unpress가 추가로 호출됨 — 다른 종류 버튼과 섞으면 시각 상태가 서로 어긋날 수 있습니다.

7. 내부 구조

<div elname="element" class="va-div [layout classes]">
  <!-- 자식 버튼들이 여기 flex/grid 레이아웃대로 나열됨 -->
  <button class="va-button">…</button>
  <button class="va-button">…</button>
  ...
</div>

전용 CSS 클래스 없음 — _beginClassBuild('va-button-group') 같은 호출이 없습니다. CSS만으로 그룹 시각 표현(붙어있는 세그먼트 버튼 같은 look)을 강조하려면 style/layout에 직접 규칙을 넣거나 커스텀 클래스를 추가해야 합니다.


8. 언제 쓰나

ButtonGroup이 맞을 때

  • 라디오형 옵션 선택을 버튼 UI로 표현할 때 (텍스트 정렬 L/C/R, 뷰 모드 List/Grid, 기간 필터 Day/Week/Month)
  • 세그먼트 컨트롤 (iOS Segmented Control 유사)
  • 툴바에서 상호 배타적 모드 전환 (편집/보기/디자인)
  • 동적으로 버튼이 추가돼도 배타 선택을 유지해야 하는 상황

다른 걸 쓸 때

  • 다중 선택 필터 (여러 개 동시 선택 가능) → 단순 Div 안에 ToggleButton 여러 개, 배타 로직 안 씀
  • 단순한 여러 버튼 나열 (선택 개념 없음) → Va.Rows / Va.Div
  • 값이 있는 폼 필드 → Va.RadioGroup / Va.RadioGroupField
  • 드롭다운 형태의 옵션 선택 → Va.Combobox / Va.SegmentedControl