Skip to content
API 风格:

Tabs 탭 ​

같은 계층의 콘텐츠를 전환합니다. WAI-ARIA APG tabs pattern을 엄격하게 따릅니다: tablist/tab/tabpanel 세 역할 연동 + roving tabindex + 방향키 내비게이션.

기본 사용법 ​

기본 사용법
수묵 산문 콘텐츠.
vue
<script setup lang="ts">
</script>

<template>
  <LhTabs>
    <LhTabPane name="prose" label="산문">수묵 산문 콘텐츠.</LhTabPane>
    <LhTabPane name="poem" label="시">시의 격률 콘텐츠.</LhTabPane>
    <LhTabPane name="calligraphy" label="서예">서예 비첩 콘텐츠.</LhTabPane>
  </LhTabs>
</template>
vue
<script>
export default {}
</script>

<template>
  <LhTabs>
    <LhTabPane name="prose" label="산문">수묵 산문 콘텐츠.</LhTabPane>
    <LhTabPane name="poem" label="시">시의 격률 콘텐츠.</LhTabPane>
    <LhTabPane name="calligraphy" label="서예">서예 비첩 콘텐츠.</LhTabPane>
  </LhTabs>
</template>

카드 외형과 비활성화 ​

카드 외형과 비활성화
먹은 다섯 빛깔로 나뉜다.
vue
<script setup lang="ts">
</script>

<template>
  <LhTabs type="card">
    <LhTabPane name="ink" label="먹">먹은 다섯 빛깔로 나뉜다.</LhTabPane>
    <LhTabPane name="cinnabar" label="주" disabled>단사는 사용할 수 없다.</LhTabPane>
    <LhTabPane name="gold" label="금">등황으로 물들인다.</LhTabPane>
  </LhTabs>
</template>
vue
<script>
export default {}
</script>

<template>
  <LhTabs type="card">
    <LhTabPane name="ink" label="먹">먹은 다섯 빛깔로 나뉜다.</LhTabPane>
    <LhTabPane name="cinnabar" label="주" disabled>단사는 사용할 수 없다.</LhTabPane>
    <LhTabPane name="gold" label="금">등황으로 물들인다.</LhTabPane>
  </LhTabs>
</template>

하단 위치 ​

하단 위치
산의 기세가 장중하다.
vue
<script setup lang="ts">
</script>

<template>
  <LhTabs tab-position="bottom">
    <LhTabPane name="mountain" label="산">산의 기세가 장중하다.</LhTabPane>
    <LhTabPane name="water" label="물">물의 정취가 맑고 깊다.</LhTabPane>
  </LhTabs>
</template>
vue
<script>
export default {}
</script>

<template>
  <LhTabs tab-position="bottom">
    <LhTabPane name="mountain" label="산">산의 기세가 장중하다.</LhTabPane>
    <LhTabPane name="water" label="물">물의 정취가 맑고 깊다.</LhTabPane>
  </LhTabs>
</template>

닫기 가능과 추가 가능 ​

닫기 가능과 추가 가능
첫 번째 권의 콘텐츠.
vue
<script setup lang="ts">
import { ref } from 'vue'
const panes = ref([
  { name: 's1', label: '그림 권 1', content: '첫 번째 권의 콘텐츠.', disabled: false },
  { name: 's2', label: '그림 권 2', content: '두 번째 권의 콘텐츠.', disabled: false },
])
let index = 2

const removePane = (name) => {
  const target = panes.value.find((pane) => pane.name === name)
  if (target) panes.value.splice(panes.value.indexOf(target), 1)
}
const addPane = () => {
  index += 1
  panes.value.push({ name: `s${index}`, label: `그림 권 ${index}`, content: '새 권의 콘텐츠.', disabled: false })
}
</script>

<template>
  <!-- 닫기 가능과 추가 가능 -->
  <LhTabs closable addable tab-position="bottom" @tab-remove="removePane" @tab-add="addPane">
    <LhTabPane
      v-for="pane in panes"
      :key="pane.name"
      :name="pane.name"
      :label="pane.label"
      :disabled="pane.disabled"
    >{{ pane.content }}</LhTabPane>
  </LhTabs>
</template>
vue
<script>
export default {
  data() {
    return {
      panes: [
        { name: 's1', label: '그림 권 1', content: '첫 번째 권의 콘텐츠.', disabled: false },
        { name: 's2', label: '그림 권 2', content: '두 번째 권의 콘텐츠.', disabled: false },
      ],
      index: 2,
    }
  },
  methods: {
    removePane(name) {
      const target = this.panes.find((pane) => pane.name === name)
      if (target) this.panes.splice(this.panes.indexOf(target), 1)
    },
    addPane() {
      this.index += 1
      this.panes.push({ name: `s${this.index}`, label: `그림 권 ${this.index}`, content: '새 권의 콘텐츠.', disabled: false })
    },
  },
}
</script>

<template>
  <!-- 닫기 가능과 추가 가능 -->
  <LhTabs closable addable tab-position="bottom" @tab-remove="removePane" @tab-add="addPane">
    <LhTabPane
      v-for="pane in panes"
      :key="pane.name"
      :name="pane.name"
      :label="pane.label"
      :disabled="pane.disabled"
    >{{ pane.content }}</LhTabPane>
  </LhTabs>
</template>

활성 탭을 닫으면 컴포넌트가 인접한 사용 가능한 탭으로 연동 전환하고 tab-remove를 발생시킵니다. 데이터 소스에서 해당 pane을 제거하는 것은 사용자의 책임입니다.

제어되는 사용법 ​

제어되는 사용법
수묵 콘텐츠.

현재 탭: mo

vue
<script setup lang="ts">
import { ref } from 'vue'
const active = ref('mo')
</script>

<template>
  <LhTabs v-model="active" type="card">
    <LhTabPane name="zh" label="국풍">국풍 콘텐츠.</LhTabPane>
    <LhTabPane name="mo" label="수묵">수묵 콘텐츠.</LhTabPane>
  </LhTabs>
</template>
vue
<script>
export default {
  data() {
    return { active: 'mo' }
  },
}
</script>

<template>
  <LhTabs v-model="active" type="card">
    <LhTabPane name="zh" label="국풍">국풍 콘텐츠.</LhTabPane>
    <LhTabPane name="mo" label="수묵">수묵 콘텐츠.</LhTabPane>
  </LhTabs>
</template>

Tabs API ​

LhTabs Props ​

프로퍼티설명타입기본값
modelValue현재 활성 탭의 name (v-model)string—
type외형"line" | "card"'line'
closable탭 닫기 가능 여부booleanfalse
addable추가 버튼 표시 여부booleanfalse
tabPosition탭 위치"top" | "bottom"'top'
sxsx 빠른 레이아웃 속성LhSxProps—

LhTabs Events ​

이벤트명설명콜백 매개변수
update:modelValue활성 탭 변경 (v-model)(name: string)
tab-change활성 탭 변경(name: string)
tab-remove탭 닫기(name: string)
tab-add추가 버튼 클릭—

LhTabPane Props ​

프로퍼티설명타입기본값
name탭 고유 식별자 (안정적인 키, 동적 수정은 권장하지 않음)string—
label탭 제목string''
disabled비활성화 여부booleanfalse

Slots ​

슬롯설명적용 컴포넌트
default탭 패널 (LhTabPane 목록)LhTabs
default패널 콘텐츠LhTabPane

무장애 ​

WAI-ARIA APG tabs pattern을 엄격하게 따릅니다:

  • 탭 머리는 role="tablist", 각 탭은 role="tab" (aria-selected + aria-controls), 패널은 role="tabpanel" (aria-labelledby + tabindex="0")
  • roving tabindex: 활성 탭만 Tab으로 포커스할 수 있고, 나머지는 tabindex="-1"입니다
  • 방향키로 사용 가능한 탭 사이를 이동하며 자동으로 활성화합니다 (비활성화 항목은 건너뜀), Home/End로 처음과 끝으로 이동합니다
  • closable일 때 Delete 키로 현재 탭을 닫을 수 있습니다. 닫기 아이콘은 aria-hidden 장식이며 키보드는 Delete를 사용해 버튼 중첩을 피합니다
  • 비활성화된 탭은 포커스 활성화할 수 없으며, tab-remove 등의 조작은 비활성화 항목에 효과가 없습니다

타입 정의 ​

이 컴포넌트가 외부로 노출하는 TypeScript 타입 구조는 다음과 같습니다 (packages/components/tabs/src/types.ts와 @lh-ui/share/core/* 소스에서 자동 추출, 각 항목을 펼쳐 전체 정의를 확인하세요. 프로퍼티 설명은 위쪽 Props 표를 참조하세요):

LhTabsProps
ts
export interface LhTabsProps {
  /** 현재 활성 탭의 name (v-model) */
  modelValue?: string
  /** 외형 */
  type?: LhTabsType
  /** 탭 닫기 가능 여부 */
  closable?: boolean
  /** 추가 버튼 표시 여부 */
  addable?: boolean
  /** 탭 위치 */
  tabPosition?: LhTabsPosition
  /** sx 빠른 레이아웃 속성 */
  sx?: LhSxProps
}
LhTabPaneProps
ts
export interface LhTabPaneProps {
  /** 탭 고유 식별자 (안정적인 키로 사용, 동적 수정은 권장하지 않음) */
  name: string
  /** 탭 제목 */
  label?: string
  /** 비활성화 여부 */
  disabled?: boolean
}
LhTabsType (출처: @lh-ui/share/core/tabs)
ts
/**
 * 탭 외형
 */
export type LhTabsType = 'line' | 'card'
LhTabsPosition (출처: @lh-ui/share/core/tabs)
ts
/**
 * 탭 위치
 */
export type LhTabsPosition = 'top' | 'bottom'

국풍의 아름다움으로 코드의 토대를 세웁니다