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
| Prop | Type | Default | Description |
|---|---|---|---|
tabs | TabConfig[] | - | Array of tab configurations |
activeTab | string | - | Currently active tab ID |
modelValue | string | - | Active tab ID/name for v-model |
position | 'top' | 'bottom' | 'bottom' | Tab bar position |
activeColor | string | '#007AFF' | Active icon and label color |
inactiveColor | string | '#8E8E93' | Inactive icon and label color |
backgroundColor | string | '#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
| Event | Params | Description |
|---|---|---|
change | tabId: string | Emitted when tab is selected |
update:modelValue | tabId: string | Emitted 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
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | false | Whether drawer is open |
position | 'left' | 'right' | 'left' | Drawer position |
width | number | 280 | Drawer width in pixels |
overlayColor | string | 'rgba(0,0,0,0.5)' | Backdrop color |
closeOnPress | boolean | true | Close on item press |
closeOnPressOutside | boolean | true | Close when the backdrop is pressed |
VDrawer.Item
| Prop | Type | Default | Description |
|---|---|---|---|
icon | string | '' | Icon (emoji or name) |
label | string | - | Item label |
active | boolean | false | Marks the current item and exposes selected accessibility state |
badge | number | string | null | Badge count |
disabled | boolean | false | Disabled state |
Events
VDrawer
| Event | Params | Description |
|---|---|---|
update:open | open: boolean | Emitted when open state changes |
open | - | Emitted when drawer becomes visible |
close | - | Emitted when drawer closes |
VDrawer.Item
| Event | Params | Description |
|---|---|---|
press | - | Emitted when item is pressed |
Slots
VDrawer
header- Drawer header contentdefault- Drawer content (receivesclosefunction)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" />