Vue NativeVue Native
Guide
Components
Composables
Navigation
Architecture
  • iOS
  • Android
  • macOS
GitHub
Guide
Components
Composables
Navigation
Architecture
  • iOS
  • Android
  • macOS
GitHub
  • Getting Started

    • Introduction
    • Installation
    • Your First App
    • Project Structure
  • Core Concepts

    • Components
    • Styling
    • Theming
    • TypeScript
    • Navigation
    • Navigation Components
    • Native Modules
    • Native Code Blocks
    • Hot Reload
  • UI Patterns

    • Forms and v-model
    • Shared Element Transitions
    • Teleport
    • Custom Native Components (escape hatch)
  • Quality & Debugging

    • Testing
    • Debugging
    • Error Handling
  • Platform Hardening

    • Security
    • Accessibility
    • Performance
  • Integration Guides

    • State Management
    • Deep Linking & Universal Links
    • State Persistence
    • Push Notifications
    • Error Reporting & Monitoring
  • Tooling

    • Managed Workflow
    • VS Code Extension
    • Neovim Plugin
  • Building & Releasing

    • Building Native Apps
    • Deployment & App Store Submission
  • Reference

    • Upgrade Guide
    • Migrating from React Native
    • Known Limitations & Platform Differences
    • Troubleshooting

Navigation Components

Vue Native provides tab bar and drawer navigation components for common navigation patterns.

VTabBar

Tab bar navigation for switching between views.

Basic Usage

<script setup>
import { ref } from '@thelacanians/vue-native-runtime'

const activeTab = ref('home')

const tabs = [
  { id: 'home', label: 'Home', icon: '🏠' },
  { id: 'search', label: 'Search', icon: '🔍' },
  { id: 'profile', label: 'Profile', icon: '👤' },
]

function handleTabChange(tabId) {
  console.log('Selected tab:', tabId)
}
</script>

<template>
  <VView style="{ flex: 1 }">
    <!-- Content based on active tab -->
    <HomeView v-if="activeTab === 'home'" />
    <SearchView v-else-if="activeTab === 'search'" />
    <ProfileView v-else-if="activeTab === 'profile'" />
    
    <!-- Tab bar at bottom -->
    <VTabBar
      :tabs="tabs"
      :activeTab="activeTab"
      @change="handleTabChange"
    />
  </VView>
</template>

With Badges

<script setup>
const tabs = [
  { id: 'home', label: 'Home', icon: '🏠' },
  { id: 'notifications', label: 'Alerts', icon: '🔔', badge: 3 },
  { id: 'messages', label: 'Messages', icon: 'đŸ’Ŧ', badge: '99+' },
]
</script>

<template>
  <VTabBar :tabs="tabs" :activeTab="activeTab" />
</template>

Top Position

<VTabBar
  :tabs="tabs"
  :activeTab="activeTab"
  position="top"
/>

Props

PropTypeDefaultDescription
tabsTabConfig[]-Array of tab configurations
activeTabstring-Currently active tab ID
modelValuestring-Active tab ID/name for v-model
position'top' | 'bottom''bottom'Tab bar position
activeColorstring'#007AFF'Active icon and label color
inactiveColorstring'#8E8E93'Inactive icon and label color
backgroundColorstring'#fff'Tab bar background color

TabConfig

type TabConfig = {
  label: string       // Tab label text
  icon?: string       // Tab icon text (for example, an emoji)
  badge?: number | string // Optional badge count
} & (
  | { id: string; name?: string }
  | { id?: string; name: string }
)

Events

EventParamsDescription
changetabId: stringEmitted when tab is selected
update:modelValuetabId: stringEmitted for v-model updates

VDrawer

Drawer (side menu) navigation component.

Basic Usage

<script setup>
import { ref } from '@thelacanians/vue-native-runtime'

const drawerOpen = ref(false)

function navigateTo(page) {
  console.log('Navigate to:', page)
  drawerOpen.value = false
}
</script>

<template>
  <VView style="{ flex: 1 }">
    <!-- Main content -->
    <VButton title="Open Menu" @press="() => drawerOpen = true" />
    
    <!-- Drawer -->
    <VDrawer v-model:open="drawerOpen">
      <VDrawer.Section title="Menu">
        <VDrawer.Item
          icon="🏠"
          label="Home"
          @press="navigateTo('home')"
        />
        <VDrawer.Item
          icon="âš™ī¸"
          label="Settings"
          @press="navigateTo('settings')"
        />
        <VDrawer.Item
          icon="â„šī¸"
          label="About"
          @press="navigateTo('about')"
        />
      </VDrawer.Section>
    </VDrawer>
  </VView>
</template>

With Header

<VDrawer v-model:open="drawerOpen">
  <template #header>
    <VView style="{ padding: 20, backgroundColor: '#007AFF' }">
      <VText style="{ color: '#fff', fontSize: 20, fontWeight: 'bold' }">
        My App
      </VText>
      <VText style="{ color: '#fff', opacity: 0.8 }">
        user@example.com
      </VText>
    </VView>
  </template>
  
  <VDrawer.Item icon="🏠" label="Home" />
  <VDrawer.Item icon="âš™ī¸" label="Settings" />
</VDrawer>

Right Position

<VDrawer
  v-model:open="drawerOpen"
  position="right"
  :width="300"
>
  <!-- Drawer content -->
</VDrawer>

With Badges

<VDrawer.Item
  icon="đŸ“Ŧ"
  label="Messages"
  :badge="5"
  @press="navigateTo('messages')"
/>

<VDrawer.Item
  icon="🔔"
  label="Notifications"
  :badge="'99+'"
  @press="navigateTo('notifications')"
/>

Disabled Items

<VDrawer.Item
  icon="🔒"
  label="Premium"
  disabled
  @press="showPremiumUpsell"
/>

Props

VDrawer

PropTypeDefaultDescription
openbooleanfalseWhether drawer is open
position'left' | 'right''left'Drawer position
widthnumber280Drawer width in pixels
overlayColorstring'rgba(0,0,0,0.5)'Backdrop color
closeOnPressbooleantrueClose on item press
closeOnPressOutsidebooleantrueClose when the backdrop is pressed

VDrawer.Item

PropTypeDefaultDescription
iconstring''Icon (emoji or name)
labelstring-Item label
activebooleanfalseMarks the current item and exposes selected accessibility state
badgenumber | stringnullBadge count
disabledbooleanfalseDisabled state

Events

VDrawer

EventParamsDescription
update:openopen: booleanEmitted when open state changes
open-Emitted when drawer becomes visible
close-Emitted when drawer closes

VDrawer.Item

EventParamsDescription
press-Emitted when item is pressed

Slots

VDrawer

  • header - Drawer header content
  • default - Drawer content (receives close function)
  • footer - Content rendered after the drawer items

Patterns

Tab + Drawer Combination

<script setup>
import { ref } from '@thelacanians/vue-native-runtime'

const drawerOpen = ref(false)
const activeTab = ref('home')

const tabs = [
  { id: 'home', label: 'Home', icon: '🏠' },
  { id: 'explore', label: 'Explore', icon: '🔍' },
  { id: 'profile', label: 'Profile', icon: '👤' },
]
</script>

<template>
  <VView style="{ flex: 1 }">
    <!-- Main content -->
    <VButton 
      title="☰ Menu" 
      @press="() => drawerOpen = true"
      style="{ position: 'absolute', top: 20, left: 20, zIndex: 100 }"
    />
    
    <!-- Tab content -->
    <HomeView v-if="activeTab === 'home'" />
    <ExploreView v-else-if="activeTab === 'explore'" />
    <ProfileView v-else-if="activeTab === 'profile'" />
    
    <!-- Drawer -->
    <VDrawer v-model:open="drawerOpen">
      <VDrawer.Section title="Navigation">
        <VDrawer.Item
          icon="🏠"
          label="Home"
          @press="() => { activeTab = 'home'; drawerOpen = false }"
        />
        <VDrawer.Item
          icon="🔍"
          label="Explore"
          @press="() => { activeTab = 'explore'; drawerOpen = false }"
        />
        <VDrawer.Item
          icon="👤"
          label="Profile"
          @press="() => { activeTab = 'profile'; drawerOpen = false }"
        />
      </VDrawer.Section>
      
      <VDrawer.Section title="More">
        <VDrawer.Item icon="âš™ī¸" label="Settings" />
        <VDrawer.Item icon="â„šī¸" label="About" />
      </VDrawer.Section>
    </VDrawer>
    
    <!-- Tab bar -->
    <VTabBar
      :tabs="tabs"
      :activeTab="activeTab"
      @change="(tab) => activeTab = tab"
    />
  </VView>
</template>

Programmatic Control

// Access drawer methods
const drawerRef = ref(null)

function openDrawer() {
  drawerOpen.value = true
}

function closeDrawer() {
  drawerOpen.value = false
}

// Access tab bar methods
function switchToTab(tabId: string) {
  activeTab.value = tabId
}

With Navigation

<script setup>
import { useRouter } from '@thelacanians/vue-native-navigation'

const router = useRouter()
const drawerOpen = ref(false)

function navigateTo(route) {
  router.push(route)
  drawerOpen.value = false
}
</script>

<template>
  <VDrawer v-model:open="drawerOpen">
    <VDrawer.Item
      icon="🏠"
      label="Home"
      @press="navigateTo('home')"
    />
    <VDrawer.Item
      icon="📊"
      label="Dashboard"
      @press="navigateTo('dashboard')"
    />
  </VDrawer>
</template>

Styling

Custom Tab Bar Styles

<VTabBar
  :tabs="tabs"
  :activeTab="activeTab"
  :style="{
    backgroundColor: '#000',
    borderTopWidth: 0,
  }"
/>

Custom Drawer Styles

<VDrawer
  v-model:open="drawerOpen"
  :style="{
    backgroundColor: '#1a1a1a',
  }"
>
  <VDrawer.Item
    :style="{
      borderBottomColor: '#333',
    }"
  />
</VDrawer>

Accessibility

Both components include built-in accessibility support:

  • Tab items have role="tab" and proper selection state
  • Drawer items have role="menuitem"
  • Screen reader announcements

Custom Accessibility

<VTabBar
  :tabs="tabs"
  :activeTab="activeTab"
  :accessibilityLabel="`Tab bar, ${activeTab} selected`"
/>

<VDrawer.Item
  icon="âš™ī¸"
  label="Settings"
  accessibilityLabel="Open settings menu"
  accessibilityHint="Double-tap to navigate to settings"
/>

Troubleshooting

Tab bar not showing

Problem: Tab bar doesn't appear.

Solution: Ensure parent has flex: 1 and tab bar has proper positioning:

<VView style="{ flex: 1 }">
  <VTabBar ... />
</VView>

Drawer not closing

Problem: Drawer stays open after item press.

Solution: Use closeOnPress prop or manually close:

<VDrawer 
  v-model:open="drawerOpen"
  :closeOnPress="true"
>
  <VDrawer.Item @press="() => drawerOpen = false" />
</VDrawer>

Tab change not detected

Problem: @change event not firing.

Solution: Ensure you're using the correct event name and handler:

<VTabBar @change="handleTabChange" />

Related

  • Navigation Guide
  • VButton Component
  • VView Component
Edit this page
Last Updated: 7/28/26, 4:10 PM
Contributors: github-actions[bot]
Prev
Navigation
Next
Native Modules