“Vue 3 + Vite JS Version” Documentation by “Sean Ngu” v6.0.0
Updated on: 25/August/2026
By: Sean Ngu
If you have any inquiries or require further assistance beyond what is covered in this help file,
please do not hesitate to send us a message
through Wrapbootstrap. We are more than happy to help.
Thank you very much!
Follow the following steps to install Vue 3 with Vite in your local development environment.
You may refer to their official documentation for how to setup the development environment.
Setup Guide
<!-- run the following command --> cd /your-path-url/template_vue3 npm install npm run dev <!-- browse the url --> http://localhost:8081/
Verify that you are running at least node 22.x.x or later and npm 11.x.x by running node -v and npm -v in a terminal/console window. Older versions produce errors, but newer versions are fine.
Copy over the required image from global assets folder
<!-- copy the following folder--> /admin/template/assets/img <!-- paste it into vue3 folder --> /admin/template/template_vue3/public/assets/img
File structure overview for Vue JS Version
template_vue3/
├── .eslintrc.cjs
├── .gitignore
├── .vscode/
├── cypress/
├── cypress.json
├── env.d.ts
├── index.html
├── package.json
├── public/
├── README.md
├── src/
│ ├── App.vue
│ ├── assets/
│ ├── components/
│ ├── composables/
│ ├── main.ts
│ ├── router/
│ ├── scss/
│ ├── stores/
│ └── views/
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig-vite-config.json
└── tsconfig.vitest.json
└── vite.config.ts
Below is the code from App.vue which include the header, sidebar, right sidebar, top menu, page content and footer. You may remove the component if you are not using it.
<template>
<div class="app" v-bind:class="[{
'app-header-menu-search-toggled': appOption.appHeaderSearchToggled,
'app-header-fixed': appOption.appHeaderFixed,
'app-sidebar-fixed': appOption.appSidebarFixed,
'app-sidebar-grid': appOption.appSidebarGrid,
'app-sidebar-toggled': appOption.appSidebarToggled,
'app-sidebar-collapsed': appOption.appSidebarCollapsed,
'app-sidebar-mobile-toggled': appOption.appSidebarMobileToggled,
'app-sidebar-mobile-closed': appOption.appSidebarMobileClosed,
'app-sidebar-end-toggled': appOption.appSidebarEndToggled,
'app-sidebar-end-mobile-toggled': appOption.appSidebarEndMobileToggled,
'app-content-full-height': appOption.appContentFullHeight,
'app-content-full-width': appOption.appSidebarHide,
'app-without-sidebar': appOption.appSidebarHide,
'app-with-end-sidebar': appOption.appSidebarEnd,
'app-with-wide-sidebar': appOption.appSidebarWide,
'app-with-hover-sidebar': appOption.appSidebarHover,
'app-with-top-menu': appOption.appTopMenu,
'app-with-two-sidebar': appOption.appSidebarTwo,
'pt-0': appOption.appHeaderHide,
'app-boxed-layout': appOption.appBoxedLayout,
'app-footer-fixed': appOption.appFooterFixed,
'app-sidebar-minified': appOption.appSidebarMinified,
'app-gradient-enabled': appOption.appGradientEnabled
}, appOption.appClass]"">
<vue3-progress-bar />
<app-header v-if="!appOption.appHeaderHide" />
<app-sidebar v-if="!appOption.appSidebarHide" />
<app-sidebar-right v-if="appOption.appSidebarTwo" />
<app-top-menu v-if="appOption.appTopMenu" />
<div class="app-content" v-bind:class="appOption.appContentClass">
<router-view></router-view>
</div>
<app-footer v-if="appOption.appFooter" />
<app-theme-panel />
</div>
</template>
List of components inside the components folder
/src/components/
├── app/
│ ├── AnimateNumber.vue
│ ├── Footer.vue
│ ├── Header.vue
│ ├── HeaderMegaMenu.vue
│ ├── NavScrollTo.vue
│ ├── Sidebar.vue
│ ├── SidebarNav.vue
│ ├── SidebarRight.vue
│ ├── ThemePanel.vue
│ ├── TopMenu.vue
│ └── TopMenuNav.vue
├── bootstrap/
│ ├── Panel.vue
│ ├── PanelBody.vue
│ ├── PanelFooter.vue
│ ├── PanelGroup.vue
│ ├── PanelHeader.vue
│ ├── PanelTitle.vue
│ └── PanelToolbar.vue
└── plugins/
├── Apexcharts.vue
├── Chartjs.vue
├── Datepicker.vue
├── Highlightjs.vue
├── QuillEditor.vue
├── TagsInput.vue
├── Typeahead.vue
├── VueSelect.vue
└── VueTable.vue
This template used mitt as event bus to emit events between component. Emitter files can be found via /composables/useEmitter.ts
import useEmitter from '@/composables/useEmitter';
const emitter = useEmitter();
// emit event
emitter.emit('my-event', true);
// event listener
this.emitter.on('my-event', (evt) => {
// do something
});
This template used pinia to create the store and share the states variable between the components. Store files can be found via /src/stores/
/src/stores/ ├─ app-option.ts // global app option states ├─ app-sidebar-menu.ts // global app sidebar menu list └─ app-variable.ts // global app variable (fetched from css / font variables)
You can use the global app option from /stores/app-option.ts
import { useAppOptionStore } from '@/stores/app-option';
const appOption = useAppOptionStore();
export default {
mounted() {
// available app option
appOption.appThemeClass: '',
appOption.appDarkMode: '',
appClass: '',
appOption.appHeaderHide: false,
appOption.appHeaderFixed: true,
appOption.appHeaderInverse: false,
appOption.appHeaderSearchToggled: false,
appOption.appHeaderLanguageBar: false,
appOption.appHeaderMegaMenu: false,
appOption.appSidebarTwo: false,
appOption.appSidebarHide: false,
appOption.appSidebarEnd: false,
appOption.appSidebarWide: false,
appOption.appSidebarLight: false,
appOption.appSidebarFixed: true,
appOption.appSidebarCollapsed: false,
appOption.appSidebarMobileToggled: false,
appOption.appSidebarMobileClosed: false,
appOption.appSidebarMinified: false,
appOption.appSidebarHover: false,
appOption.appSidebarSearch: false,
appOption.appSidebarEndToggled: false,
appOption.appSidebarEndMobileToggled: false,
appOption.appSidebarTransparent: false,
appOption.appTopMenu: false,
appOption.appContentFullHeight: false,
appOption.appContentClass: '',
appOption.appFooter: false,
appOption.appFooterFixed: false,
appOption.appThemePanelToggled: false
},
beforeUnmount() {
// set to default before leave the page
appOption.appTopMenu = false;
}
}
You can use the global app variables (css color / font family) from /stores/app-variable.ts
import { useAppVariableStore } from '@/stores/app-variable';
const appVariable = useAppVariableStore();
export default {
data() {
return {
variableName: appVariable.color.theme
// font variable
appVariable.font.family;
appVariable.font.size;
appVariable.font.weight;
// color variable
appVariable.color.componentColor;
appVariable.color.componentBg;
appVariable.color.theme;
appVariable.color.blue;
appVariable.color.green;
appVariable.color.orange
appVariable.color.red;
appVariable.color.cyan;
appVariable.color.purple;
appVariable.color.yellow;
appVariable.color.indigo;
appVariable.color.pink;
appVariable.color.black;
appVariable.color.white;
appVariable.color.gray;
appVariable.color.dark;
appVariable.color.gray100;
appVariable.color.gray200;
appVariable.color.gray300;
appVariable.color.gray400;
appVariable.color.gray500;
appVariable.color.gray600;
appVariable.color.gray700;
appVariable.color.gray800;
appVariable.color.gray900;
// color variable (rgba)
appVariable.color.componentColorRgb;
appVariable.color.componentBgRgb;
appVariable.color.themeRgb;
appVariable.color.blueRgb;
appVariable.color.greenRgb;
appVariable.color.orange
appVariable.color.redRgb;
appVariable.color.cyanRgb;
appVariable.color.purpleRgb;
appVariable.color.yellowRgb;
appVariable.color.indigoRgb;
appVariable.color.pinkRgb;
appVariable.color.blackRgb;
appVariable.color.whiteRgb;
appVariable.color.grayRgb;
appVariable.color.darkRgb;
appVariable.color.gray100Rgb;
appVariable.color.gray200Rgb;
appVariable.color.gray300Rgb;
appVariable.color.gray400Rgb;
appVariable.color.gray500Rgb;
appVariable.color.gray600Rgb;
appVariable.color.gray700Rgb;
appVariable.color.gray800Rgb;
appVariable.color.gray900Rgb;
}
}
}
Set the app sidebar menu list from from /stores/app-sidebar-menu.ts
// single level structure
{
'url': '/',
'icon': 'fa fa-sitemap',
'text': 'Dashboard'
},
// multi level structure
{
'icon': 'fa fa-envelope',
'text': 'Email',
'children': [{
'url': '/email/inbox',
'action': 'Inbox',
'text': 'Inbox'
}, {
'url': '/email/compose',
'action': 'Compose',
'text': 'Compose'
}, {
'url': '/email/detail',
'action': 'Detail',
'text': 'Detail'
}]
}
Enable the dark mode from template_vue3/stores/app-variable.ts
... appDarkMode: true ...
Add the dir="rtl" attribute to <html> for index.html in order to enable Right-To-Left (RTL) layout direction.
<html dir="rtl">
This will flip the layout direction of the entire page to support RTL languages like Arabic, Hebrew, or Persian.
Replace the existing @import 'default/styles'; line in template_vue3/src/scss/vue.scss with the selected theme import below, then restart the Vite development server.
template_vue3/src/scss/vue.scss.@import 'apple/styles';
<!-- No additional icon script is required. -->
<div class="menu-icon"> <iconify-icon icon="solar:pulse-bold-duotone"></iconify-icon> </div>
template_vue3/src/scss/vue.scss.@import 'facebook/styles';
template_vue3/stores/app-option.ts.... appHeaderInverse: true ...
template_vue3/src/scss/vue.scss.@import 'transparent/styles';
.app-cover next to the <body> tag in template_vue3/public/index.html.<body> <!-- BEGIN page-cover --> <div class="app-cover"></div> <!-- END page-cover --> ... </body>
template_vue3/src/scss/vue.scss.@import 'google/styles';
<div class="menu-icon"> <iconify-icon icon="solar:home-2-bold-duotone"></iconify-icon> </div>
template_vue3/stores/app-option.ts.... appSidebarWide: true, appSidebarLight: true, ...
.app-header in template_vue3/src/components/app/Header.vue.
<!-- BEGIN #appHeader -->
<div id="appHeader" class="app-header">
<!-- BEGIN brand -->
<div class="brand">
<button type="button" class="menu-toggler">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<button type="button" class="menu-toggler">
...
</button>
<a class="brand-logo">
Color Admin
</a>
</div>
<!-- END brand -->
...
</div>
template_vue3/src/scss/vue.scss.@import 'material/styles';
<div class="menu-icon"> <iconify-icon icon="solar:home-2-bold-duotone"></iconify-icon> </div>
template_vue3/stores/app-option.ts.... appSidebarWide: true, ...
.app-header in template_vue3/src/components/app/Header.vue.
<!-- BEGIN #appHeader -->
<div id="appHeader" class="app-header">
<!-- BEGIN brand -->
<div class="brand">
<button type="button" class="menu-toggler">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<button type="button" class="menu-toggler">
...
</button>
<a class="brand-logo">
Color Admin Material
</a>
</div>
<!-- END brand -->
...
</div>
template_vue3/src/components/app/Header.vue. Do not add a second search form.
<!-- BEGIN #appHeader -->
<div id="appHeader" class="app-header">
<!-- BEGIN header-nav -->
<div class="menu">
<div class="menu-item">
<a href="#" class="menu-link icon">
<i class="material-icons">search</i>
</a>
<!-- EXISTING SEARCH FORM -->
<div class="menu-item menu-item-form">
...
</div>
</div>
...
</div>
<!-- END header-nav -->
<div class="menu-item-form">
<button class="search-btn" type="submit"><i class="material-icons">search</i></button>
<input type="text" class="form-control" placeholder="Search Something..." />
<a href="#" class="close">
<i class="material-icons">close</i>
</a>
</div>
</div>
.app-loader in template_vue3/public/index.html.
<!-- BEGIN #loader -->
<div id="loader" class="app-loader">
<div class="material-loader">
<svg class="circular" viewBox="25 25 50 50">
<circle class="path" cx="50" cy="50" r="20" fill="none" stroke-width="2" stroke-miterlimit="10"></circle>
</svg>
<div class="message">Loading...</div>
</div>
</div>
<!-- END #loader -->
The Vue 3 version is fully configured with SCSS. You may switch the Color Admin theme by changing the file /template_vue3/src/scss/vue.scss.
@import 'default/styles'; <!-- other themes --> @import 'apple/styles'; @import 'facebook/styles'; @import 'google/styles'; @import 'material/styles'; @import 'transparent/styles';
Below is the list of package that has been installed in this project. You may use the following example to find the package from their official website.
https://www.npmjs.com/package/bootstrap-vue
{
"name": "color-admin",
"version": "6.0.0",
"scripts": {
"dev": "vite",
"build": "vue-tsc --noEmit && vite build",
"preview": "vite preview --port 5050",
"test:unit": "vitest --environment jsdom",
"test:e2e": "start-server-and-test preview http://127.0.0.1:5050/ 'cypress open'",
"test:e2e:ci": "start-server-and-test preview http://127.0.0.1:5050/ 'cypress run'",
"typecheck": "vue-tsc --noEmit -p tsconfig.vitest.json --composite false",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore"
},
"type": "module",
"dependencies": {
"@caohenghu/vue-colorpicker": "^1.2.4",
"@chenfengyuan/vue-countdown": "^2.1.3",
"@fortawesome/fontawesome-free": "^7.3.1",
"@fortawesome/fontawesome-svg-core": "^7.3.1",
"@fortawesome/free-solid-svg-icons": "^7.3.1",
"@fortawesome/vue-fontawesome": "^3.0.8",
"@fullcalendar/bootstrap": "^6.1.21",
"@fullcalendar/common": "^5.11.5",
"@fullcalendar/core": "^6.1.21",
"@fullcalendar/daygrid": "^6.1.21",
"@fullcalendar/interaction": "^6.1.21",
"@fullcalendar/list": "^6.1.21",
"@fullcalendar/timegrid": "^6.1.21",
"@fullcalendar/vue3": "^6.1.21",
"@highlightjs/vue-plugin": "github:highlightjs/vue-plugin",
"@marcoschulte/vue3-progress": "^0.0.9",
"@sipec/vue3-tags-input": "^3.0.4",
"@vuepic/vue-datepicker": "^11.0.2",
"@vueup/vue-quill": "^1.2.0",
"apexcharts": "^6.7.0",
"axios": "^1.10.0",
"bootstrap": "^5.3.8",
"bootstrap-icons": "^1.13.1",
"bootstrap-social": "^5.1.1",
"chart.js": "^4.5.0",
"date-fns": "^4.1.0",
"flag-icons": "^7.5.0",
"highlight.js": "^11.11.1",
"jsvectormap": "^1.7.0",
"lity": "^2.4.1",
"maska": "^3.2.0",
"masonry-layout": "^4.2.2",
"mitt": "^3.0.1",
"moment": "^2.30.1",
"photoswipe": "^5.4.4",
"pinia": "^3.0.3",
"simple-line-icons": "^2.5.5",
"v-calendar": "^3.0.0-alpha.8",
"vue": "^3.5.41",
"vue-axios": "^3.5.2",
"vue-router": "^4.5.1",
"vue-select": "^4.0.0-beta.3",
"vue3-apexcharts": "^1.8.0",
"vue3-datepicker": "^0.4.0",
"vue3-google-map": "^0.22.0",
"vue3-perfect-scrollbar": "^2.0.0",
"vue3-simple-typeahead": "^1.0.11",
"vue3-table-lite": "^1.4.3"
},
"devDependencies": {
"@iconify/vue": "^5.0.0",
"@rushstack/eslint-patch": "^1.12.0",
"@types/jsdom": "^21.1.7",
"@types/node": "^24.0.10",
"@vitejs/plugin-vue": "^6.0.0",
"@vitejs/plugin-vue-jsx": "^5.0.1",
"@vue/eslint-config-prettier": "^10.2.0",
"@vue/eslint-config-typescript": "^14.6.0",
"@vue/test-utils": "^2.4.6",
"@vue/tsconfig": "^0.7.0",
"cypress": "^14.5.1",
"eslint": "^9.30.1",
"eslint-plugin-cypress": "^5.1.0",
"eslint-plugin-vue": "^10.3.0",
"jsdom": "^26.1.0",
"prettier": "^3.6.2",
"sass": "1.77.7",
"sass-loader": "^16.0.5",
"start-server-and-test": "^2.0.12",
"typescript": "~5.8.3",
"vite": "^8.2.1",
"vitest": "^3.2.4",
"vue-tsc": "^3.0.1"
}
}