Troubleshooting
This guide covers some of the more common issues you may run into when developing with Ionic Vue.
Have an issue that you think should be covered here? Let us know!
Failed to resolve component
[Vue warn]: Failed to resolve component: ion-button
If you see this warning, then it is likely you did not import your component from @ionic/vue. By default, all Ionic Vue components are locally registered, meaning you need to import them each time you want to use them.
Without importing the component, you will only get the underlying Web Component, and Vue-specific features such as v-model will not work.
To resolve this issue, you need to import the component from @ionic/vue and provide it to your Vue component:
<template>
<ion-button>Hello World</ion-button>
</template>
<script setup lang="ts">
import { IonButton } from '@ionic/vue';
</script>
Prefer to register your components globally once? We have you covered. Our Optimizing Your Build Guide shows you how to register Ionic Vue components globally as well as the potential downsides to be aware of when using this approach.
Slot attributes are deprecated
`slot` attributes are deprecated vue/no-deprecated-slot-attribute
The slots that are used in Ionic Vue are Web Component slots, which are different than the slots used in Vue 2. Unfortunately, the APIs for both are very similar, and your linter is likely getting the two confused.
All Ionic Vue starters ship with this rule turned off, but you can do it yourself by adding the following to your .eslintrc.js file:
module.exports = {
rules: {
'vue/no-deprecated-slot-attribute': 'off',
},
};
If you are using VSCode and have the Vetur plugin installed, you are likely getting this warning because of Vetur, not ESLint. By default, Vetur loads the default Vue 3 linting rules and ignores any custom ESLint rules.
To resolve this issue, you will need to turn off Vetur's template validation with vetur.validation.template: false. See the Vetur Linting Guide for more information.
Method on component is not a function
In order to access a method on an Ionic Framework component in Vue, you will need to access the underlying Web Component instance first:
// ✅ This is correct
ionContentRef.value.$el.scrollToBottom();
// ❌ This is incorrect and will result in an error.
ionContentRef.value.scrollToBottom();
In other framework integrations such as Ionic React, this is not needed as any ref you provide is automatically forwarded to the underlying Web Component instance. We are unable to do the same thing here due to limitations in how Vue manages refs.
See the Quickstart Guide for more information.
Page transitions are not working
In order for page transitions to work correctly, each page must have an ion-page component at the root:
<template>
<ion-page>
<ion-header>
<ion-toolbar>
<ion-title>Home</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">Hello World</ion-content>
</ion-page>
</template>
<script setup lang="ts">
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar } from '@ionic/vue';
</script>
See the IonPage documentation for more information.
Ionic events bound in JavaScript are not firing
When creating event listeners in JavaScript (i.e. addEventListener), event names should be written as kebab-case:
const modal = await modalController.create({
component: Modal
});
modal.addEventListener('ion-modal-did-present', () => {
...
});
await modal.present();
This is done to align with how developers bind events in their Vue templates by using kebab-case: https://vuejs.org/guide/essentials/component-basics.html#case-insensitivity
Blank white screen in Capacitor native build
If your app runs correctly in the browser but shows a blank white screen when launched in a Capacitor iOS or Android build, the most common cause is a non-default base in vite.config.js (or publicPath in vue.config.js for legacy Vue CLI projects).
This option is often added so the app can be hosted from a subdirectory, such as a GitHub Pages deploy:
// vite.config.js
export default defineConfig({
base: '/my-repo/',
});
In a Capacitor build the bundled assets are served from a local origin (capacitor://localhost on iOS and https://localhost on Android by default), so the prefixed paths never resolve and the app fails to bootstrap.
To fix it, reset base to / (or remove the option) before running npx cap copy. If you need both targets, keep a separate config file for each and select it at build time with vite build --config.
To confirm this is the cause, inspect the device log for 404s on the prefixed asset paths:
- Android: Run
adb logcatfrom the command line, or open Logcat in Android Studio. - iOS: Open Safari's Develop menu and inspect the Simulator or device webview.