| name | ionic-vue |
| description | Guides the agent through Ionic Vue development patterns — project structure, Vue-specific Ionic components (IonPage, IonRouterOutlet, IonTabs), navigation with Vue Router and useIonRouter, Ionic lifecycle hooks (onIonViewWillEnter, onIonViewDidEnter, onIonViewWillLeave, onIonViewDidLeave), composable utilities (useIonRouter, useBackButton, useKeyboard), tab-based routing, lazy loading, platform detection with isPlatform, and troubleshooting common Vue-specific issues. Do not use for general Ionic component theming or CLI usage (use ionic-app-development), creating a new Ionic app (use ionic-app-creation), Capacitor-specific Vue patterns without Ionic (use capacitor-vue), upgrading Ionic versions (use ionic-app-upgrades), or non-Vue frameworks like Angular or React. |
| metadata | {"author":"capawesome-team","source":"https://github.com/capawesome-team/skills/tree/main/skills/ionic-vue"} |
Ionic Vue
Develop Ionic apps with Vue — project structure, components, navigation, lifecycle hooks, composables, and Vue-specific patterns.
Prerequisites
- Ionic Framework 7 or 8 with
@ionic/vue.
- Vue 3.
- Node.js and npm installed.
- For iOS: Xcode installed.
- For Android: Android Studio installed.
Agent Behavior
- Auto-detect before asking. Check the project for
package.json dependencies (@ionic/vue, vue, @capacitor/core), platforms (android/, ios/), build tools (vite.config.ts), and TypeScript usage. Only ask the user when something cannot be detected.
- Guide step-by-step. Walk the user through the process one step at a time. Never present multiple unrelated questions at once.
- Adapt to the project. Detect whether the project uses
<script setup> (Composition API) or Options API and generate code that matches the existing style. Default to <script setup lang="ts"> for new files unless the project uses a different pattern.
Procedures
Step 1: Analyze the Project
Auto-detect the following by reading project files:
- Ionic version: Read
@ionic/vue version from package.json.
- Vue version: Read
vue version from package.json.
- Capacitor version: Read
@capacitor/core version from package.json (if present).
- TypeScript: Check if
tsconfig.json exists and if .vue files use <script setup lang="ts">.
- Platforms: Check which directories exist (
android/, ios/).
- Router config: Locate the router file (typically
src/router/index.ts).
- Project template: Determine if the project uses tabs, side-menu, or blank template by examining the router configuration and
App.vue.
Step 2: Project Structure
A standard Ionic Vue project follows this structure:
project-root/
├── android/ # Android native project (generated by Capacitor)
├── ios/ # iOS native project (generated by Capacitor)
├── public/
├── src/
│ ├── components/ # Reusable Vue components
│ ├── composables/ # Custom composables
│ ├── router/
│ │ └── index.ts # Vue Router configuration (uses @ionic/vue-router)
│ ├── theme/
│ │ └── variables.css # Ionic CSS custom properties
│ ├── views/ # Page components (routed views)
│ ├── App.vue # Root component (contains IonApp + IonRouterOutlet)
│ └── main.ts # Entry point (installs IonicVue plugin)
├── capacitor.config.ts # Capacitor configuration
├── package.json
├── tsconfig.json
└── vite.config.ts
If the project does not follow this structure, adapt all guidance to the project's actual directory layout. Do not restructure the project unless the user explicitly asks.
Step 3: App Entry Point and Root Component
The entry point src/main.ts installs the IonicVue plugin and mounts the app:
import { createApp } from 'vue';
import { IonicVue } from '@ionic/vue';
import App from './App.vue';
import router from './router';
import '@ionic/vue/css/core.css';
import '@ionic/vue/css/normalize.css';
import '@ionic/vue/css/structure.css';
import '@ionic/vue/css/typography.css';
import '@ionic/vue/css/padding.css';
import '@ionic/vue/css/float-elements.css';
import '@ionic/vue/css/text-alignment.css';
import '@ionic/vue/css/text-transformation.css';
import '@ionic/vue/css/flex-utils.css';
import '@ionic/vue/css/display.css';
import './theme/variables.css';
const app = createApp(App).use(IonicVue).use(router);
router.isReady().then(() => {
app.mount('#app');
});
The root App.vue contains IonApp and IonRouterOutlet:
<template>
<ion-app>
<ion-router-outlet />
</ion-app>
</template>
<script setup lang="ts">
import { IonApp, IonRouterOutlet } from '@ionic/vue';
</script>
Step 4: Components and IonPage
Read references/components.md for detailed component patterns.
Key rules:
- Import all Ionic components from
@ionic/vue — e.g., import { IonButton, IonContent, IonPage } from '@ionic/vue'.
- Every routed page must use
IonPage as its root template element. Without it, page transitions break and Ionic lifecycle hooks do not fire.
- Access Web Component methods via
$el — e.g., contentRef.value.$el.scrollToBottom(300).
- Import icons as SVG references from
ionicons/icons — never pass icon names as strings.
- Use
v-model on Ionic form components (IonInput, IonToggle, IonSelect, IonCheckbox, IonRange).
- Use kebab-case for Ionic event names in templates — e.g.,
@ion-change, @ion-infinite.
Step 5: Navigation and Routing
Read references/navigation.md for detailed routing patterns.
Key principles:
- Import
createRouter from @ionic/vue-router, not from vue-router. The Ionic version wraps Vue Router to enable page transitions.
- Declarative navigation: Use
router-link attribute on Ionic components with optional router-direction and router-animation.
- Programmatic navigation: Use the
useIonRouter composable for Ionic-specific transitions, or useRouter from vue-router for standard navigation.
- Lazy load routes with
component: () => import('@/views/DetailPage.vue').
- Tab routing: Use nested routes with
IonTabs and IonRouterOutlet. Each tab maintains its own navigation stack.
- Never cross-route between tabs — only tab bar buttons should switch tabs. Use
IonModal for views shared across tabs.
Step 6: Lifecycle Hooks
Read references/lifecycle.md for detailed lifecycle patterns.
Key principles:
IonRouterOutlet keeps pages in the DOM. Vue's onMounted fires only once per page, not on every visit.
- Use Ionic lifecycle hooks to run logic on every page visit:
onIonViewWillEnter — Refresh data every time the page appears.
onIonViewDidEnter — Start animations or focus inputs after the page transition finishes.
onIonViewWillLeave — Save state or unsubscribe.
onIonViewDidLeave — Clean up off-screen resources.
- Ionic lifecycle hooks require
IonPage as the root element.
- Only router-mapped components receive lifecycle hooks — child components do not.
Step 7: Composables and Utilities
Read references/composables.md for detailed composable documentation.
Available composables and utilities from @ionic/vue:
| Function | Purpose |
|---|
useIonRouter() | Programmatic navigation with transition control |
useBackButton(priority, handler) | Handle Android hardware back button |
useKeyboard() | Reactive keyboard visibility and height |
onIonViewWillEnter(cb) | Lifecycle: page about to show |
onIonViewDidEnter(cb) | Lifecycle: page fully visible |
onIonViewWillLeave(cb) | Lifecycle: page about to hide |
onIonViewDidLeave(cb) | Lifecycle: page fully hidden |
isPlatform(name) | Check current platform (ios, android, hybrid, etc.) |
getPlatforms() | Get array of all matching platform identifiers |
Step 8: Platform Detection
Use isPlatform from @ionic/vue to conditionally execute platform-specific logic:
<script setup lang="ts">
import { isPlatform } from '@ionic/vue';
const isIOS = isPlatform('ios');
const isAndroid = isPlatform('android');
const isNative = isPlatform('hybrid');
const isMobileWeb = isPlatform('mobileweb');
</script>
<template>
<div>
<p v-if="isNative">Running as a native app</p>
<p v-else>Running in a browser</p>
</div>
</template>
Supported identifiers: android, capacitor, cordova, desktop, electron, hybrid, ios, ipad, iphone, mobile, mobileweb, phablet, pwa, tablet.
Step 9: Build and Run
After implementing changes:
npm run build
npx cap sync
npx cap run android
npx cap run ios
For development with live reload:
ionic serve
For native live reload:
ionic cap run android --livereload --external
ionic cap run ios --livereload --external
Error Handling
Failed to resolve component: ion-*: The Ionic component is not imported. Add the missing import from @ionic/vue in the <script> section (e.g., import { IonButton } from '@ionic/vue').
- Page transitions not working: Verify that the page component uses
IonPage as its root template element. Without IonPage, transitions and lifecycle hooks silently fail.
- Ionic lifecycle hooks not firing: Ensure
IonPage is the root element and the component is directly mapped to a route in the router configuration. Lifecycle hooks do not fire on child components.
Method on component is not a function: Access the underlying Web Component via $el — e.g., ref.value.$el.scrollToBottom(), not ref.value.scrollToBottom().
- Slot attribute deprecation warning: Ionic uses Web Component slots, which linters misidentify as deprecated Vue 2 slots. Disable the ESLint rule:
'vue/no-deprecated-slot-attribute': 'off'.
- Event listeners not firing: Use kebab-case event names in templates (
ion-modal-did-present) and in addEventListener calls. Do not use camelCase.
useIonRouter or useBackButton fails: These composables use Vue's inject() internally and must be called inside setup() or <script setup>, not in standalone functions or callbacks.
- Tab navigation loses state: Each tab maintains its own stack. Do not use
router.go() with non-linear (tab-based) routing. Use useIonRouter().push() or router-link instead.
- Vue
onMounted fires only once: IonRouterOutlet caches pages in the DOM. Use onIonViewWillEnter instead of onMounted for logic that must run every time the page is shown.
- Content overlaps tab bar or header: The page component is missing
IonPage as the root element. IonPage sets up the proper flexbox layout.
Related Skills
ionic-app-development — General Ionic development guidance: components, theming, CLI usage.
ionic-app-creation — Create a new Ionic app from scratch.
capacitor-vue — Capacitor-specific Vue patterns (plugins, hooks, services) without Ionic Framework.
ionic-app-upgrades — Upgrade Ionic Framework to a newer version.