Appearance
Responsive Tabs
ResponsiveTabs 컴포넌트는 화면 너비나 컨테이너 공간이 부족할 때, 초과되는 탭을 드롭다운 메뉴로 자동 숨김 처리하는 반응형 탭 UI입니다.
Architecture
ResponsiveTabs.vue: 탭들을 감싸는 Wrapper 컴포넌트입니다.ResizeObserver를 활용하여 컴포넌트의 가로 폭을 실시간으로 감지하고, 화면에 표시할 수 있는ResponsiveTab의 개수를 동적으로 계산합니다. 잘리는 탭들은MenuBox를 이용해 더보기 메뉴 하위에 드롭다운 형태로 표시됩니다.ResponsiveTab.vue:SecondaryTab.vue컴포넌트와 동일한 속성과 스타일을 공유하지만, 가려진 상태를 처리할 수 있는hidden로직에 특화된 탭 컴포넌트입니다.
Features
- 반응형 탭 (Responsive Layouts):
ResizeObserver를 통해 창의 크기가 변할 때마다 탭의 크기를 계산하고 "더보기" 버튼 안에 숨기거나 다시 나타나도록 처리합니다. - 자동 포커싱 스크롤: "더보기" 드롭다운 메뉴 안에서 현재 선택된 탭이 활성화 상태일 경우, 해당 메뉴를 열면 자동으로 해당 탭으로 스크롤되는 기능을 포함합니다 (MenuBox와 MenuContainer 기본 동작 연동).
- 접근성(Accessibility): 기존 키보드 내비게이션(Arrow Key 등)을 그대로 유지하며 탭 전환이 가능합니다.
Props
ResponsiveTabs
tabs(TabContraction<T>['item'][]): 화면에 표시될 대상 탭들의 배열 객체.activeTab(TabKey): 현재 선택/활성화된 탭의 키 (Key).tabIdentifier(string): 탭 요소들의 v-forkey부여를 위한 고유 접두사 (Optional).
ResponsiveTab
tabKey(TabKey): 탭을 고유하게 식별하기 위한 값 (필수).label(string): 탭에 표시할 텍스트 라벨 (필수).icon(string): 탭의 아이콘 종류 (Optional).disabled(boolean): 탭 비활성화 여부 지정 (기본값: false, Optional).badgeContent(number): 숫자 뱃지 표시 내용 (Optional).hidden(boolean): Responsive 계산에 의해 현재 탭이 숨김 처리되어야 하는지 여부 (Optional).
Used Packages
@vueuse/core(ResizeObserver,useElementBounding)@vueuse/components(vOnClickOutside)MenuBox,MenuContainer(내부 드롭다운 처리)
Example
Selected Tab: tab1
:::demo
vue
<template>
<div
style="width: 100%; max-width: 400px; border: 1px solid var(--gray-300); padding: 8px; border-radius: 4px; resize: horizontal; overflow: auto;"
>
<responsive-tabs
:tabs="tabsData"
:active-tab="currentActiveTab"
@select:tab="handleTabSelect"
/>
</div>
<div style="margin-top: 24px">Selected Tab: {{ currentActiveTab }}</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { ResponsiveTabs, ICON_TYPE } from '@jennifersoft/vue-components-v2';
const tabsData = [
{ tabKey: 'tab1', label: 'Dashboard' },
{ tabKey: 'tab2', label: 'Management' },
{ tabKey: 'tab3', label: 'Settings', disabled: true },
{ tabKey: 'tab4', label: 'Profile' },
{ tabKey: 'tab5', label: 'Notifications', badgeContent: 'C' },
{ tabKey: 'tab6', label: 'Billing' },
{ tabKey: 'tab7', label: 'API Keys', icon: ICON_TYPE.key },
{ tabKey: 'tab8', label: 'Security Logs' },
{ tabKey: 'tab9', label: 'Analytics' },
{ tabKey: 'tab10', label: 'Deployments' },
{ tabKey: 'tab11', label: 'Webhooks' },
{ tabKey: 'tab12', label: 'Integrations' },
{ tabKey: 'tab13', label: 'Advanced Settings' },
];
const currentActiveTab = ref('tab1');
const handleTabSelect = (key: string | number | symbol) => {
currentActiveTab.value = key as string;
};
</script>:::