MobileNav
The bottom tab bar for a MobileShell. MobileNav is a grid frame; each MobileNavItem becomes one equal-width tab, so the bar adapts to any number of items.
<script setup lang="ts">
import { ref } from 'vue'
import { MobileNav, MobileNavItem, Avatar } from 'frappe-ui'
const tab = ref('home')
</script>
<template>
<div
class="mx-auto w-[360px] overflow-hidden border-b border-l border-r bg-surface-white"
>
<MobileNav>
<MobileNavItem
label="Home"
icon="lucide-house"
:active="tab === 'home'"
@click="tab = 'home'"
/>
<MobileNavItem
label="Notifications"
icon="lucide-bell"
:active="tab === 'notifications'"
@click="tab = 'notifications'"
/>
<MobileNavItem
label="Search"
icon="lucide-search"
:active="tab === 'search'"
@click="tab = 'search'"
/>
<MobileNavItem label="You" :active="tab === 'you'" @click="tab = 'you'">
<template #default="{ active }">
<Avatar
label="Jane Doe"
size="md"
:class="active ? 'ring-2 ring-outline-gray-4' : ''"
/>
</template>
</MobileNavItem>
</MobileNav>
</div>
</template>MobileNavItem
Each item takes a label, an icon (or a default slot for custom content like an avatar), and a to target. It renders a router link when navigating somewhere new, and — when it's already the current route — a button that scrolls the shell's scroll container to the top instead of re-navigating.
active controls the highlight and is independent of the current route, so one tab can stay lit across a whole section (e.g. Home across every community route) while tapping it still navigates home. When active is omitted it defaults to whether to matches the current route. The default slot receives { active } so custom content — an avatar, a badge — can react to the highlight:
<MobileNavItem label="You" :to="{ name: 'More' }" :active="isMoreRoute">
<template #default="{ active }">
<UserAvatar :user="me" :class="{ 'ring-2 ring-outline-gray-4': active }" />
</template>
</MobileNavItem>Like SidebarItem, MobileNavItem is router-optional: mounted without vue-router it degrades to a plain <a>/<button> with no warnings, so it works in docs, tests, and embedded use.
API Reference
MobileNav
| Slot | Payload |
|---|---|
default | {} |
MobileNavItem
Show types
import type { Component } from 'vue'
import type { RouteLocationRaw } from 'vue-router'
/**
* `MobileNav` (the bar) has no props — it's a grid frame for `MobileNavItem`s.
*/
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
export interface MobileNavProps {}
export interface MobileNavItemProps {
/** Label under the icon; also the accessible name. */
label: string
/**
* Icon CSS class, e.g. `lucide-home`, or a component. Ignored when the
* default slot is used (for a custom glyph or an avatar).
*/
icon?: string | Component
/**
* Navigation target. Renders a router link. Tapping the item while it is
* already the current route scrolls the shell to the top instead of
* re-navigating.
*/
to?: RouteLocationRaw
/**
* Highlight this item. Independent of the current route so one tab can stay
* lit across a whole section (e.g. Home across community routes). Defaults to
* whether `to` resolves to the current route.
*/
active?: boolean
}Label under the icon; also the accessible name.
Icon CSS class, e.g. `lucide-home`, or a component. Ignored when the default slot is used (for a custom glyph or an avatar).
Navigation target. Renders a router link. Tapping the item while it is already the current route scrolls the shell to the top instead of re-navigating.
Highlight this item. Independent of the current route so one tab can stay lit across a whole section (e.g. Home across community routes). Defaults to whether `to` resolves to the current route.
| Slot | Payload |
|---|---|
default | { active: boolean; } |
| Event | Payload |
|---|---|
click | [event: MouseEvent] |