Run npm install bootstrap in your Vue 3 project, then import bootstrap/dist/css/bootstrap.min.css in main.js. That’s the whole install. Grid, utility and button classes work in your single-file components right away, and Vue needs no registration for any of them.
The stylesheet is the easy part. Bootstrap’s 5.3 documentation says its CSS works with any framework, but its JavaScript is not fully compatible with Vue, because both can change the same DOM element. Most of the trouble in this setup comes from that one gap.
How do you add Bootstrap to a Vue 3 project?
The project itself comes from create-vue, the official scaffolding tool. It sets up Vite and needs Node.js ^22.18.0 || >=24.12.0, per the Vue quick start guide as of October 2026. Already have a project? Jump to step 3.
- Scaffold the app with
npm create vue@latest. Pick Vue Router if the navbar will link to real routes. - Move into the folder and run
npm install. - Add the framework with
npm install bootstrap. - Open
src/main.jsand import the Bootstrap stylesheet above your own CSS, so your overrides win the cascade. - Add
import 'bootstrap/dist/js/bootstrap.bundle.min.js'only if a component needs Bootstrap JavaScript. The bundle already carries Popper. - Start the dev server with
npm run devand put a few Bootstrap classes intoApp.vue.
import { createApp } from 'vue'
import App from './App.vue'
import 'bootstrap/dist/css/bootstrap.min.css'
import './assets/main.css'
createApp(App).mount('#app')To check it worked, drop a container with a row, two col children and a btn btn-primary button into the template. Bootstrap’s grid system picks those class names up straight from the markup.
What older tutorials still tell you to install
Plenty of older guides start from vue create and end with npm run serve. The current quick start uses npm create vue@latest and npm run dev instead.
Some also tell you to add jQuery and popper.js. Bootstrap 5 does not need jQuery (its own documentation says so), and the bundle ships Popper anyway.
Which Bootstrap and Vue versions work together?
Bootstrap 5.3 works with Vue 3 through a plain npm import. Versions only get messy once a wrapper library enters the picture.
BootstrapVue was built for Vue 2 and Bootstrap 4, and Bootstrap’s JavaScript documentation still lists it that way. BootstrapVueNext is the one for Vue 3 with Bootstrap 5, though the same page labels it alpha (Bootstrap documentation, October 2026).
Vue 2 reached end of life on December 31, 2023, with 2.7.16 as the final release (Vue team, 2023). Vue 3 has been the default version since February 7, 2022 (Vue team, 2023).
New projects start on Vue 3. That rules out BootstrapVue before any other comparison begins.
Where tutorials contradict each other
The C# Corner tutorial installs bootstrap-vue and imports its stylesheet in a Vue 3 createApp file, then builds the demo from plain Bootstrap classes. The extra package does no work at all.
The vue3-bootstrap-vue demo repo on GitHub does register BootstrapVue on Vue 3, but it only runs after aliasing vue to @vue/compat in the Webpack config. That alias is a migration build for old code, and a poor foundation for a fresh project.
Alpha also means churn. BootstrapVueNext’s getting-started page recommends a newer BApp component setup and keeps the older createBootstrap plugin as legacy, so the install steps have already changed once.
Should you use npm, a CDN or a wrapper library?
npm covers most projects. The CDN suits prototypes and pages with no build step, and a wrapper library starts to pay off once modals and dropdowns (toasts too) are driven from Vue state.
| Route | Setup | Sass customization | Bootstrap JavaScript |
|---|---|---|---|
| npm with Vite | One package, one import | Full, through Sass | Plugins act on Vue-rendered DOM |
| CDN link | Two tags in index.html | None, compiled files only | Global bootstrap object |
| BootstrapVueNext | Two packages, BApp, two CSS files | Full, if you import Bootstrap Sass yourself | Replaced by Vue components |
npm with Vite
This is the default for a reason. You pin the version in package.json and compile your own Sass, which also lets you import just the parts you use. Nothing gets requested from a third-party host at runtime, and it runs on the same build as the rest of the app.
The downside is that customization needs the sass package, and Bootstrap’s JavaScript still touches DOM that Vue owns.
CDN link
It works for prototypes and for static pages with a sprinkle of Vue. It falls short the moment you want Sass customization or partial imports for a smaller bundle, and it’s a non-starter anywhere a third-party host is off limits.
Wrapper library
BootstrapVueNext’s docs put the legacy createBootstrap plugin at about 20 kb gzipped, while the recommended BApp setup bundles only the components you use.
A wrapper turns Bootstrap components into Vue components that take props and emit events. Bootstrap’s own JavaScript documentation points Vue users to a framework-specific package, because both Bootstrap and Vue can mutate the same DOM element and cause bugs such as dropdowns stuck open.
Props and events replace data attributes, and links are router-aware. The DOM tug of war goes away too.
The price is one more dependency and that alpha label in Bootstrap’s docs. Skip the BApp or plugin step and components misbehave.
My rule of thumb: if you mostly use the grid, utilities and static components, stay with plain npm. If modal or offcanvas state (dropdowns too) is driven from Vue, go with a wrapper.
How do you add Bootstrap to Vue with a CDN link?
Put the Bootstrap stylesheet in the head of index.html and the bundle script above the Vue entry script. Bootstrap’s documentation recommends jsDelivr for the files.
<head>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div id="app"></div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>
<script type="module" src="/src/main.js"></script>
</body>The classic script runs before the deferred module, so the global bootstrap object exists by the time components mount. Version 5.3.8 is what the JavaScript documentation’s own examples use as of October 2026, and the exact number belongs in the URL.
Bootstrap ships every CDN tag with an integrity hash on its download page. Copy those hashes into your tags so the browser verifies each file.
Prefer Popper separately? Load @popperjs/core 2.11.8 before bootstrap.min.js, as the docs describe.
The trade-offs are the ones you’d expect. The CDN serves compiled files only, so Sass variables and partial imports are off the table. If jsDelivr is blocked on your network, Bootstrap’s docs name cdnjs and unpkg as alternatives.
Load Vue from a CDN too and the page needs no build step at all. The Vue quick start notes that single-file component syntax is not available in that setup.
How do you install BootstrapVueNext in a Vue 3 app?
Install bootstrap and bootstrap-vue-next with npm, import both stylesheets in the entry file, and wrap the app in the BApp component. After that, BButton, BModal and the rest work in any template.
npm i bootstrap bootstrap-vue-nextBoth stylesheets go in the entry file, Bootstrap first.
// main.ts
import { createApp } from 'vue'
import App from './App.vue'
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue-next/dist/bootstrap-vue-next.css'
createApp(App).mount('#app')<!-- App.vue -->
<template>
<BApp>
<RouterView />
</BApp>
</template>
<script setup lang="ts">
import { BApp } from 'bootstrap-vue-next'
</script>A modal then needs one ref and a v-model on BModal, plus a BButton that flips the value.
Skip the bootstrap.bundle import here. BootstrapVueNext renders modals through Vue’s Teleport and runs its own focus trap, per its modal documentation.
Details to know for a first install
Keep BApp at least one component level above any call to useToast(), useModal() or usePopover(), because Vue’s inject only reaches child components.
Auto-registration is optional. It runs through unplugin-vue-components and the BootstrapVueNext resolver in the Vite config, and it also tree-shakes the JavaScript.
The TypeScript peers (@floating-ui/vue, @vueuse/core and vue-router) are optional as well. They add type definitions without growing the final bundle. None of these extras belong in a first install.
How does Bootstrap JavaScript work inside Vue components?
Import only the plugins the interface uses. Create each instance in onMounted from a template ref and dispose it before the component unmounts. Data attributes still work for static markup, but anything driven by Vue state is cleaner with instances.
Bundle or individual plugins
The bundle is the lazy option, and it’s fine while you’re still prototyping. Individual imports keep the build smaller.
import Modal from 'bootstrap/js/dist/modal'
import Collapse from 'bootstrap/js/dist/collapse'The bundle loads every plugin, used or not. Individual files use default exports, one import per plugin. Dropdowns, tooltips and popovers need Popper listed in package.json when you import them one by one.
All of that comes from Bootstrap’s optimize guide. A project that toggles a navbar and opens one modal needs two imports, not the whole bundle.
Data attributes versus component-controlled instances
Data attributes are Bootstrap’s preferred route, switched on through HTML alone. They’re fine for a navbar toggler or an accordion that Vue never touches.
Instances are created in code, driven from Vue handlers and disposed on unmount. That fits better when component state decides when a Bootstrap modal opens.
<template>
<button class="btn btn-primary" @click="openModal">Open</button>
<div ref="modalEl" class="modal fade" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body">Hello</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'
import Modal from 'bootstrap/js/dist/modal'
const modalEl = ref(null)
let modal = null
onMounted(() => {
modal = Modal.getOrCreateInstance(modalEl.value)
})
onBeforeUnmount(() => {
modal?.dispose()
})
function openModal() {
modal?.show()
}
</script>Vue’s lifecycle documentation says onMounted runs after the initial render has created the DOM nodes. That is the earliest point where an instance has an element to attach to.
One caveat from Bootstrap’s JavaScript docs: calling dispose straight after hide() gives incorrect results, because hiding is asynchronous. If the modal can be open at unmount time, wait for the hidden.bs.modal event first.
Navbar links with Vue Router
RouterLink takes activeClass and exactActiveClass props, according to the Vue Router API reference. Passing active-class="active" hands Bootstrap’s own active style to the current link.
<RouterLink class="nav-link" active-class="active" to="/about">About</RouterLink>The Bootstrap navbar markup stays as it is, and only the link component changes. Use exact-active-class when a parent link with nested routes must lose its highlight on child pages.
The mobile toggler still depends on the collapse plugin, so import it from the individual files.
How do you customize and slim down Bootstrap with Sass?
Variable overrides go between two imports, and that placement is the whole trick. Every Bootstrap variable carries the !default flag, so a value assigned before Bootstrap’s own definitions wins (Bootstrap Sass documentation).
Override variables before the import
- Install the compiler with
npm i -D sass. The Vite documentation says no Vite plugin is needed, and listssass-embeddedas the faster alternative. - Create
src/scss/styles.scssand importbootstrap/scss/functionsfirst. - Add overrides such as
$primary: #0074d9;right after it. - Import variables, maps and mixins, then the layout and component partials you use.
- Replace the CSS import in
main.jswithimport './scss/styles.scss', so Bootstrap does not load twice.
// src/scss/styles.scss
@import "bootstrap/scss/functions";
$primary: #0074d9;
@import "bootstrap/scss/variables";
@import "bootstrap/scss/variables-dark";
@import "bootstrap/scss/maps";
@import "bootstrap/scss/mixins";
@import "bootstrap/scss/utilities";
@import "bootstrap/scss/root";
@import "bootstrap/scss/reboot";
@import "bootstrap/scss/type";
@import "bootstrap/scss/containers";
@import "bootstrap/scss/grid";
@import "bootstrap/scss/buttons";
@import "bootstrap/scss/helpers";
@import "bootstrap/scss/utilities/api";Import only the partials and plugins you use
Unused components are where the biggest savings sit, according to Bootstrap’s optimize guide, which points at the layout and components block of its Sass file. Drop the carousel import if there’s no carousel, and the modal plugin if there’s no modal.
Be careful, though. Partials depend on each other, so removing one can break compilation, and so can removing the primary, success or danger keys from $theme-colors.
Vite adds one trap. Its additionalData option prepends code to every style block, and the Vite documentation warns that real styles, not just variables, get duplicated in the final bundle. Inject variables and mixins only, never the full Bootstrap import.
Sass variables or CSS variables
Sass variables change the compiled output, so they need the Sass pipeline. CSS variables with the --bs- prefix change values in the browser without recompiling, and Bootstrap navbars have used them since v5.2.0, per the CSS variables documentation.
Breakpoints are the exception, because CSS variables do not work inside media queries. That is by design in the CSS specification, the same page notes.
On the CDN route, CSS variables are the only lever. Bootstrap assigns them at the base component level, such as .navbar, which makes those selectors the cleanest targets when overriding Bootstrap’s default CSS without a build step.
What breaks when you add Bootstrap to Vue?
Most broken setups trace back to missing styles, Sass deprecation noise, a missing Popper, over-trimmed partials or a misplaced BApp.
| Symptom | Cause | Fix |
|---|---|---|
| No Bootstrap styling | Stylesheet not loaded | Look for --bs- variables on :root in devtools, then add the import |
| Sass warnings in the terminal | Bootstrap source uses @import | Ignore them or silence the import deprecation |
| Dropdown or tooltip does nothing | Popper missing | List @popperjs/core or load the bundle |
| Compile error after trimming | Cross-file dependency or removed map key | Restore the partial or the key |
useToast() or useModal() fails | Called beside BApp | Move BApp one component up |
Why the Sass warnings appear and how long they last
Bootstrap’s Sass documentation says the deprecation warnings do not block compilation and can be ignored while a long-term fix is in progress. Sass deprecated @import as of Dart Sass 1.80.0 and plans removal in Dart Sass 3.0.0, no sooner than two years after 1.80.0 (Sass documentation).
Both statements hold up. The build passes today, and the removal plan is a good reason to pin the sass version in package.json so a major upgrade never lands unnoticed.
Sass prints each deprecation type five times by default, then goes quiet. To hide the warnings entirely, pass both import and global-builtin to silenceDeprecations, which Vite forwards through css.preprocessorOptions.
export default defineConfig({
css: {
preprocessorOptions: {
scss: {
silenceDeprecations: ['import', 'global-builtin'],
},
},
},
})When Bootstrap does not fit
It’s a poor pick when a Vue-native component library already styles the whole interface, or when the design system is utility-first. Bootstrap’s reboot stylesheet restyles base elements globally, so a second component library in the same app competes for them.
If the real question is utility-first styling, how Tailwind stacks up against Bootstrap is a separate decision.
FAQ About Adding Bootstrap to Vue
Can I add Bootstrap to a Vue CLI project?
Yes, with the same install and import. Run npm install bootstrap, then import the stylesheet in main.js.
Sass customization adds packages. Bootstrap’s Webpack guide lists sass, sass-loader, css-loader, style-loader, postcss-loader and autoprefixer for the pipeline.
How do I add Bootstrap Icons to a Vue project?
Install the icon package with npm i bootstrap-icons, then import bootstrap-icons/font/bootstrap-icons.css in your entry file.
Icons render through bi classes on an i element, so no component registration is involved.
Does a TypeScript project need a different Bootstrap setup?
No. create-vue generates main.ts when you pick TypeScript, and the CSS and Sass imports are identical to main.js.
Only the JavaScript plugins differ, because Bootstrap ships without type definitions. Add @types/bootstrap to get them.
Can I use Bootstrap with Nuxt?
Yes. BootstrapVueNext ships a Nuxt module, installed with bootstrap, bootstrap-vue-next and @bootstrap-vue-next/nuxt.
For plain Bootstrap CSS, list the stylesheet in the css array of nuxt.config.
Which is the better choice for Vue, Bootstrap or Tailwind?
Bootstrap suits teams that want modals, navbars and grids ready-made. Tailwind is the pick if you’d rather compose your own components from utility classes.
Neither depends on Vue, so the decision follows the design system, not the framework.
What to Re-Check When Bootstrap, Sass or Vue Updates
Upgrades go smoother in a fixed order, because each step isolates one layer and a failure points at a single cause. Bump Sass alone and rebuild. Then re-test every component that creates a Bootstrap plugin instance, and upgrade the wrapper library last.
Sass goes first because its failures surface at compile time, before any browser test. The wrapper library goes last because BootstrapVueNext commits to breaking changes whenever Bootstrap deprecates something, per its migration guide.
The cost is that pinned versions delay bug fixes until the next scheduled upgrade.
This order holds as of October 2026, while Bootstrap 5.3’s Sass still relies on @import. Once its source moves to the Sass module system, the first check shrinks to a version bump.
- How to Insert Image in Figma With Ease - November 3, 2026
- How to Download Figma Files Fast and Free - October 30, 2026
- Figma Keyboard Shortcuts That Will 10x Your Speed - October 25, 2026


