Skip to content
Open
Show file tree
Hide file tree
Changes from 50 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
c152d58
docs(vue): add context to code blocks small change to surrounding tex…
soundproofboot Jul 14, 2025
59cef22
docs(vue): add context to code blocks and small changes to surroundin…
soundproofboot Jul 14, 2025
2233653
docs(vue): add context to code blocks and small changes to surroundin…
soundproofboot Jul 14, 2025
6a21dbf
docs(vue): add context to code blocks and small changes to surroundin…
soundproofboot Jul 14, 2025
3635891
docs(vue): add context to code blocks and small changes to surroundin…
soundproofboot Jul 14, 2025
6fb72c4
docs(vue): add context to code blocks and small changes to surroundin…
soundproofboot Jul 16, 2025
bc40cfb
docs(vue): run linter
soundproofboot Jul 16, 2025
1cc3efe
Update docs/vue/your-first-app/3-saving-photos.md
soundproofboot Oct 4, 2025
c29ede6
docs(vue): change name of takePhoto method to addNewToGallery to matc…
soundproofboot Oct 4, 2025
b2926ff
docs(vue): add missing title and head tags to match Angular pages
soundproofboot Oct 4, 2025
c0caf4b
docs(vue): add title to page 7
soundproofboot Oct 4, 2025
05a1aff
Merge branch 'yourFirstAppVue' of https://github.com/soundproofboot/i…
soundproofboot Oct 4, 2025
1907917
docs(vue): update your first app page
thetaPC Oct 22, 2025
e9971d9
docs(vue): update your first app page
thetaPC Oct 22, 2025
6fe3e0a
docs(vue): update your first app page
thetaPC Oct 22, 2025
be5b3a6
docs(vue): update taking photos page
thetaPC Oct 23, 2025
1f92946
docs(vue): update saving photos page
thetaPC Oct 23, 2025
25a2392
docs(vue): update loading photos page
thetaPC Oct 23, 2025
f908015
docs(vue): update adding mobile page
thetaPC Oct 24, 2025
6283f01
docs(vue): update live reload page
thetaPC Oct 24, 2025
32d4b9e
docs(vue): update your first app pages
thetaPC Oct 25, 2025
7663914
docs(vue): update your first app pages
thetaPC Oct 25, 2025
9ec7bdf
docs(vue): update your first app pages
thetaPC Oct 28, 2025
0b6df68
docs(vue): udate live reload page
thetaPC Oct 28, 2025
9669c12
Merge branch 'main' into yourFirstAppVue
thetaPC Oct 28, 2025
3975801
docs(vue): update your first app pages
thetaPC Oct 28, 2025
fa0b5a5
Merge branch 'yourFirstAppVue' of github.com:soundproofboot/ionic-doc…
thetaPC Oct 28, 2025
cfabe13
Correct apostrophe formatting in distribution guide
thetaPC Oct 28, 2025
4a08306
docs(vue): update your first app pages for v7
thetaPC Oct 29, 2025
504f0e1
docs(vue): remove first header
thetaPC Nov 6, 2025
ecf302c
docs(vue): remove exclamation marks
thetaPC Nov 6, 2025
3b15eb1
docs(vue): add Camera
thetaPC Nov 6, 2025
2414d2f
docs(vue): change wording
thetaPC Nov 6, 2025
34fdce3
docs(vue): update existing code comment
thetaPC Nov 6, 2025
5bc6bd2
docs(vue): remove period at the end of comments
thetaPC Nov 6, 2025
a179341
docs(vue): update method string
thetaPC Nov 6, 2025
a0d3257
docs(vue): update repo url note
thetaPC Nov 6, 2025
6132931
docs(vue): add deployment text
thetaPC Nov 6, 2025
60659ef
docs(vue): switch to important note
thetaPC Nov 6, 2025
ee3d5e6
docs(vue): update close text
thetaPC Nov 6, 2025
98c520d
docs(vue): use readFile
thetaPC Nov 6, 2025
b59639b
docs(vue): use slice
thetaPC Nov 6, 2025
233761a
Update docs/vue/your-first-app.md
thetaPC Nov 6, 2025
ce98715
docs(vue): use better title example
thetaPC Nov 6, 2025
940c1bb
docs(vue): add missing comment
thetaPC Nov 6, 2025
5945f1a
docs(vue): add file path
thetaPC Nov 6, 2025
d3cbf40
docs(vue): remove change comment
thetaPC Nov 6, 2025
a9c2c52
docs(vue): remove import
thetaPC Nov 6, 2025
81db1c3
docs(vue): add surrounding code
thetaPC Nov 6, 2025
cef88ca
docs(vue): add styles comment
thetaPC Nov 6, 2025
eb865fe
Update docs/vue/your-first-app/4-loading-photos.md
thetaPC Nov 7, 2025
5ba9292
docs(vue): add better title example on v7
thetaPC Nov 7, 2025
e9d8ba7
Merge branch 'yourFirstAppVue' of github.com:soundproofboot/ionic-doc…
thetaPC Nov 7, 2025
d082cdc
docs(vue): remove Capacitor sentence
thetaPC Nov 7, 2025
b78bb35
docs(vue): update imports
thetaPC Nov 7, 2025
ee1a9c7
docs(vue): remove periods from comments
thetaPC Nov 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
185 changes: 125 additions & 60 deletions docs/vue/your-first-app.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ sidebar_label: Build Your First App
---

<head>
<title>Vue Step-by-Step Tutorial: Run Your First Ionic App with Vue</title>
<title>Build Your First Ionic Mobile App with Vue | Ionic Capacitor Camera</title>
<meta
name="description"
content="This Vue tutorial, teaches the fundamentals of Ionic app development by creating a realistic app step-by-step. Learn to run your first Ionic app with Vue."
content="This Vue tutorial teaches the fundamentals of Ionic app development by creating a realistic app step-by-step. Learn to run your first Ionic app with Vue."
/>
</head>

Expand All @@ -30,11 +30,11 @@ We'll create a Photo Gallery app that offers the ability to take photos with you

Highlights include:

- One Vue-based codebase that runs on the web, iOS, and Android using Ionic Framework [UI components](https://ionicframework.com/docs/components).
- One Vue-based codebase that runs on the web, iOS, and Android using Ionic Framework [UI components](../components.md).
- Deployed as a native iOS and Android mobile app using [Capacitor](https://capacitorjs.com), Ionic's official native app runtime.
- Photo Gallery functionality powered by the Capacitor [Camera](https://capacitorjs.com/docs/apis/camera), [Filesystem](https://capacitorjs.com/docs/apis/filesystem), and [Preferences](https://capacitorjs.com/docs/apis/preferences) APIs.
- Photo Gallery functionality powered by the Capacitor [Camera](../native/camera.md), [Filesystem](../native/filesystem.md), and [Preferences](../native/preferences.md) APIs.

Find the complete app code referenced in this guide [on GitHub](https://github.com/ionic-team/photo-gallery-capacitor-vue).
Find the [complete app code](https://github.com/ionic-team/tutorial-photo-gallery-vue) referenced in this guide on GitHub.

## Download Required Tools

Expand All @@ -43,9 +43,8 @@ Download and install these right away to ensure an optimal Ionic development exp
- **Node.js** for interacting with the Ionic ecosystem. [Download the LTS version here](https://nodejs.org/en/).
- **A code editor** for... writing code! We are fans of [Visual Studio Code](https://code.visualstudio.com/).
- **Command-line interface/terminal (CLI)**:
- **Windows** users: for the best Ionic experience, we recommend the built-in command line (cmd) or the Powershell
CLI, running in Administrator mode.
- **Mac/Linux** users, virtually any terminal will work.
- **Windows** users: for the best Ionic experience, we recommend the built-in command line (cmd) or the Powershell CLI, running in Administrator mode.
- **Mac/Linux** users: virtually any terminal will work.

## Install Ionic Tooling

Expand All @@ -56,7 +55,7 @@ To open a terminal in Visual Studio Code, go to Terminal -> New Terminal.
:::

```shell
npm install -g @ionic/cli@latest native-run
npm install -g @ionic/cli native-run cordova-res
```

:::note
Expand Down Expand Up @@ -89,45 +88,61 @@ npm install @capacitor/camera @capacitor/preferences @capacitor/filesystem

### PWA Elements

Some Capacitor plugins, including the Camera API, provide the web-based functionality and UI via the Ionic [PWA Elements library](https://github.com/ionic-team/pwa-elements).
Some Capacitor plugins, including the [Camera API](../native/camera.md), provide the web-based functionality and UI via the Ionic [PWA Elements library](https://github.com/ionic-team/pwa-elements).

It's a separate dependency, so install it next:

```shell
npm install @ionic/pwa-elements
```

After installation, open up the project in your code editor of choice.

Next, import `@ionic/pwa-elements` by editing `src/main.ts`.

```tsx
// Above the createApp() line
```ts
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';

import { IonicVue } from '@ionic/vue';
// CHANGE: Add the following import
import { defineCustomElements } from '@ionic/pwa-elements/loader';

/* ...existing Ionic styles... */

/* Theme variables */
import './theme/variables.css';

// CHANGE: Call the element loader before the createApp() call
defineCustomElements(window);

const app = createApp(App).use(IonicVue).use(router);

router.isReady().then(() => {
app.mount('#app');
});
```

That’s it! Now for the fun part - let’s see the app in action.

## Run the App

Run this command in your shell:
Run this command next:

```shell
ionic serve
```

And voilà! Your Ionic app is now running in a web browser. Most of your app can be built and tested right in the browser, greatly increasing development and testing speed.

## Photo Gallery!!!
## Photo Gallery

There are three tabs. Click on the Tab2 tab. It’s a blank canvas, aka the perfect spot to transform into a Photo Gallery. The Ionic CLI features Live Reload, so when you make changes and save them, the app is updated immediately!
There are three tabs. Click on the "Tab2" tab. It’s a blank canvas, aka the perfect spot to transform into a Photo Gallery. The Ionic CLI features Live Reload, so when you make changes and save them, the app is updated immediately!

![Animated GIF showing the live reload feature in an Ionic app, with changes in code immediately updating the app in a web browser.](/img/guides/vue/first-app/live-reload.gif 'Live Reload Feature in Ionic App')

Open `/src/views/Tab2.vue`. We see:
Open `/src/views/Tab2Page.vue`. We see:

```html
```vue
<template>
<ion-page>
<ion-header>
Expand All @@ -146,30 +161,72 @@ Open `/src/views/Tab2.vue`. We see:
</ion-content>
</ion-page>
</template>
```

`ion-header` represents the top navigation and toolbar, with "Tab 2" as the title. Let’s rename it:

```html
<ion-title>Photo Gallery</ion-title>
<script setup lang="ts">
import { IonPage, IonHeader, IonToolbar, IonTitle, IonContent } from '@ionic/vue';
import ExploreContainer from '@/components/ExploreContainer.vue';
</script>
```

We put the visual aspects of our app into `<ion-content>`. In this case, it’s where we’ll add a button that opens the device’s camera as well as displays the image captured by the camera. But first, remove the `ExploreContainer` component, beginning with the import statement:
`ion-header` represents the top navigation and toolbar, with "Tab 2" as the title (there are two of them due to iOS [Collapsible Large Title](../api/title.md#collapsible-large-titles) support). Rename both `ion-title` elements to:

```tsx
import ExploreContainer from '@/components/ExploreContainer.vue';
```vue
<template>
<ion-page>
<ion-header>
<ion-toolbar>
<!-- CHANGE: Update title -->
<ion-title>Photo Gallery</ion-title>
</ion-toolbar>
</ion-header>
<ion-content :fullscreen="true">
<ion-header collapse="condense">
<ion-toolbar>
<!-- CHANGE: Update title -->
<ion-title size="large">Photo Gallery</ion-title>
</ion-toolbar>
</ion-header>

<!-- ...existing code... -->
</ion-content>
</ion-page>
</template>
```

Next, remove the `ExploreContainer` node from the HTML markup in the `template`.
We put the visual aspects of our app into `<ion-content>`. In this case, it’s where we’ll add a button that opens the device’s camera as well as displays the image captured by the camera. Start by adding a [floating action button](../api/fab.md) (FAB) to the bottom of the page and set the camera image as the icon.

```html
<ExploreContainer name="Tab 2 page" />
```
```vue
<template>
<ion-page>
<ion-header>
<ion-toolbar>
<ion-title>Photo Gallery</ion-title>
</ion-toolbar>
</ion-header>
<ion-content :fullscreen="true">
<ion-header collapse="condense">
<ion-toolbar>
<ion-title size="large">Photo Gallery</ion-title>
</ion-toolbar>
</ion-header>

<!-- CHANGE: Add the floating action button. -->
<ion-fab vertical="bottom" horizontal="center" slot="fixed">
<ion-fab-button>
<ion-icon :icon="camera"></ion-icon>
</ion-fab-button>
</ion-fab>

We'll replace it with a [floating action button](https://ionicframework.com/docs/api/fab) (FAB). First, update the imports within the `<script setup>` tag to include the Camera icon as well as some of the Ionic components we'll use shortly:
<!-- CHANGE: Remove or comment out <ExploreContainer /> -->
<!-- <ExploreContainer name="Tab 2 page" /> -->
</ion-content>
</ion-page>
</template>

```tsx
<script setup lang="ts">
// CHANGE: Add import from `ionicons/icons`
import { camera, trash, close } from 'ionicons/icons';
// CHANGE: Update import from `@ionic/vue` to include necessary Ionic components
import {
IonPage,
IonHeader,
Expand All @@ -184,37 +241,45 @@ import {
IonCol,
IonImg,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A lot of these imports are unused:

Image

They seem to be used later on. Do we want to show the imports being added when they're actually used?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was leaning towards showing them as they get added but I ended up working on this too much that I decided to leave it in as is.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm okay. I think it would be a better user experience if they didn't have errors in their IDE while going through the steps. Maybe we can make a follow-up task for this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Decided to fit it in!

} from '@ionic/vue';
// CHANGE: Remove or comment out the ExploreContainer import
// import ExploreContainer from '@/components/ExploreContainer.vue';
</script>
```

Since our pages are generated as [Vue Single File Components](https://vuejs.org/api/sfc-spec.html) using the [`<script setup>`](https://vuejs.org/api/sfc-script-setup.html#script-setup) syntax these items are now exposed for use in our template.
Next, open `src/views/TabsPage.vue`. Change the label to "Photos" and the `ellipse` icon to `images` for the middle tab button.

Add the FAB to the bottom of the page. Use the camera image as the icon, and call the `takePhoto()` function when this button is clicked (to be implemented soon):

```html
<ion-content :fullscreen="true">
<ion-fab vertical="bottom" horizontal="center" slot="fixed">
<ion-fab-button @click="takePhoto()">
<ion-icon :icon="camera"></ion-icon>
</ion-fab-button>
</ion-fab>
</ion-content>
```

We’ll be creating the `takePhoto` method and the logic to use the Camera and other native features in a moment.

Next, open `src/views/TabsPage.vue`, remove the `ellipse` icon from the import and import the `images` icon instead:
```vue
<template>
<ion-page>
<ion-tabs>
<ion-router-outlet></ion-router-outlet>
<ion-tab-bar slot="bottom">
<ion-tab-button tab="tab1" href="/tabs/tab1">
<ion-icon aria-hidden="true" :icon="triangle" />
<ion-label>Tab 1</ion-label>
</ion-tab-button>

<ion-tab-button tab="tab2" href="/tabs/tab2">
<!-- CHANGE: Update icon. -->
<ion-icon aria-hidden="true" :icon="images" />
<!-- CHANGE: Update label. -->
<ion-label>Photos</ion-label>
</ion-tab-button>

<ion-tab-button tab="tab3" href="/tabs/tab3">
<ion-icon aria-hidden="true" :icon="square" />
<ion-label>Tab 3</ion-label>
</ion-tab-button>
</ion-tab-bar>
</ion-tabs>
</ion-page>
</template>

```tsx
<script setup lang="ts">
import { IonTabBar, IonTabButton, IonTabs, IonLabel, IonIcon, IonPage, IonRouterOutlet } from '@ionic/vue';
// CHANGE: Update import by removing `ellipse` and adding `images`
import { images, square, triangle } from 'ionicons/icons';
</script>
```

Within the tab bar (`<ion-tab-bar>`), change the label to "Photos" and the `ellipse` icon to `images` for the middle tab button:

```html
<ion-tab-button tab="tab2" href="/tabs/tab2">
<ion-icon :icon="images" />
<ion-label>Photos</ion-label>
</ion-tab-button>
```

That’s just the start of all the cool things we can do with Ionic. Up next, implementing camera taking functionality on the web, then building for iOS and Android.
That’s just the start of all the cool things we can do with Ionic. Up next, implement camera taking functionality on the web, then build it for iOS and Android.
Loading