Skip to content

Tabs

Organize related content into separate panels that users switch between without leaving the page. Tabs are ideal for settings screens, detail views, and any layout where showing everything at once would feel overwhelming. The active tab is controlled via v-model, so you can read or set it programmatically.

ts
import { CoarTabGroup, CoarTab } from '@cocoar/vue-ui';

Basic Tabs

Define your tabs inside a CoarTabGroup and render the matching panel content with v-if on the active tab ID. Users can click tabs or use the keyboard to switch between them.

Overview

This is the overview content. It provides a high-level introduction to the component.

vue
<template>
  <div>
    <CoarTabGroup v-model="activeTab">
      <CoarTab id="overview">Overview</CoarTab>
      <CoarTab id="features">Features</CoarTab>
      <CoarTab id="api">API</CoarTab>
      <CoarTab id="examples">Examples</CoarTab>
    </CoarTabGroup>
    <div style="padding: 16px; border: 1px solid var(--coar-border-neutral-secondary); border-top: none; border-radius: 0 0 8px 8px; min-height: 100px;">
      <div v-if="activeTab === 'overview'">
        <h4 style="margin: 0 0 8px;">Overview</h4>
        <p style="font-size: 13px;">This is the overview content. It provides a high-level introduction to the component.</p>
      </div>
      <div v-else-if="activeTab === 'features'">
        <h4 style="margin: 0 0 8px;">Features</h4>
        <ul style="padding-left: 16px; display: flex; flex-direction: column; gap: 4px; font-size: 13px;">
          <li>Keyboard navigation (Arrow keys, Home, End)</li>
          <li>ARIA tab panel pattern</li>
          <li>Controlled and uncontrolled modes</li>
          <li>Custom content in each panel</li>
        </ul>
      </div>
      <div v-else-if="activeTab === 'api'">
        <h4 style="margin: 0 0 8px;">API</h4>
        <p style="font-size: 13px;">Use <code>v-model</code> on <code>CoarTabGroup</code> to control the active tab programmatically.</p>
      </div>
      <div v-else-if="activeTab === 'examples'">
        <h4 style="margin: 0 0 8px;">Examples</h4>
        <p style="font-size: 13px;">See the demos below for more usage patterns.</p>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { CoarTabGroup, CoarTab } from '@cocoar/vue-ui';

const activeTab = ref('overview');
</script>

Settings Pattern

Tabs shine in settings pages where each category has its own form section. This pattern keeps the page compact and scannable while giving each section room to breathe.

General Settings

Display name
Email
Language
vue
<template>
  <div>
    <CoarTabGroup v-model="settingsTab">
      <CoarTab id="general">General</CoarTab>
      <CoarTab id="security">Security</CoarTab>
      <CoarTab id="notifications">Notifications</CoarTab>
      <CoarTab id="billing">Billing</CoarTab>
    </CoarTabGroup>
    <div style="padding: 16px; border: 1px solid var(--coar-border-neutral-secondary); border-top: none; border-radius: 0 0 8px 8px; min-height: 100px;">
      <div v-if="settingsTab === 'general'">
        <h4 style="margin: 0 0 8px;">General Settings</h4>
        <div style="display: flex; flex-direction: column; gap: 8px;">
          <div style="display: flex; align-items: center; justify-content: space-between; gap: 16px;">
            <span style="font-size: 13px;">Display name</span>
            <input type="text" value="John Doe" style="padding: 4px 8px; border: 1px solid var(--coar-border-neutral-secondary); border-radius: 6px; background: var(--coar-background-neutral-primary); color: var(--coar-text-neutral-primary); font-size: 13px; min-width: 160px;" />
          </div>
          <div style="display: flex; align-items: center; justify-content: space-between; gap: 16px;">
            <span style="font-size: 13px;">Email</span>
            <input type="email" value="john@example.com" style="padding: 4px 8px; border: 1px solid var(--coar-border-neutral-secondary); border-radius: 6px; background: var(--coar-background-neutral-primary); color: var(--coar-text-neutral-primary); font-size: 13px; min-width: 160px;" />
          </div>
          <div style="display: flex; align-items: center; justify-content: space-between; gap: 16px;">
            <span style="font-size: 13px;">Language</span>
            <select style="padding: 4px 8px; border: 1px solid var(--coar-border-neutral-secondary); border-radius: 6px; background: var(--coar-background-neutral-primary); color: var(--coar-text-neutral-primary); font-size: 13px; min-width: 160px;">
              <option>English</option>
              <option>German</option>
            </select>
          </div>
        </div>
      </div>
      <div v-else-if="settingsTab === 'security'">
        <h4 style="margin: 0 0 8px;">Security Settings</h4>
        <p style="font-size: 13px; color: var(--coar-text-neutral-secondary);">Manage your password and two-factor authentication settings.</p>
      </div>
      <div v-else-if="settingsTab === 'notifications'">
        <h4 style="margin: 0 0 8px;">Notification Preferences</h4>
        <p style="font-size: 13px; color: var(--coar-text-neutral-secondary);">Choose how you want to be notified about account activity.</p>
      </div>
      <div v-else-if="settingsTab === 'billing'">
        <h4 style="margin: 0 0 8px;">Billing & Plans</h4>
        <p style="font-size: 13px; color: var(--coar-text-neutral-secondary);">Manage your subscription and payment methods.</p>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { CoarTabGroup, CoarTab } from '@cocoar/vue-ui';

const settingsTab = ref('general');
</script>

Disabled Tabs

Disable individual tabs to prevent access to sections that are not yet available, require a higher permission level, or depend on completing a previous step first.

vue
<template>
  <CoarTabGroup>
    <CoarTab id="active1">Active</CoarTab>
    <CoarTab id="disabled1" :disabled="true">Disabled</CoarTab>
    <CoarTab id="active2">Active</CoarTab>
    <CoarTab id="disabled2" :disabled="true">Disabled</CoarTab>
  </CoarTabGroup>
</template>

<script setup lang="ts">
import { CoarTabGroup, CoarTab } from '@cocoar/vue-ui';
</script>

Accessibility

Keyboard Navigation

KeyAction
Left Arrow / Right ArrowMove between tabs
HomeFirst tab
EndLast tab
TabMove to panel content

API

CoarTabGroup Props

PropTypeDefaultDescription
v-modelstringfirst tab idID of the active tab

CoarTab Props

PropTypeDefaultDescription
idstringUnique tab identifier (required)
disabledbooleanfalseDisable this tab
loadingStrategy'lazy' | 'eager''lazy'lazy: content only rendered when active; eager: always in DOM

Released under the Apache-2.0 License.