Skip to content
API 风格:

Tabs タブ ​

同じ階層のコンテンツを切り替えます。WAI-ARIA APG の tabs pattern に厳密に準拠:tablist/tab/tabpanel の 3 ロール連携 + 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>

クローズ可能と追加可能 ​

クローズ可能と追加可能
第 1 巻のコンテンツ。
vue
<script setup lang="ts">
import { ref } from 'vue'
const panes = ref([
  { name: 's1', label: '画巻 1', content: '第 1 巻のコンテンツ。', disabled: false },
  { name: 's2', label: '画巻 2', content: '第 2 巻のコンテンツ。', 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: '第 1 巻のコンテンツ。', disabled: false },
        { name: 's2', label: '画巻 2', content: '第 2 巻のコンテンツ。', 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'

国風の美で、コードの基を築く