Bootstrap Vue: Using Bootstrap 5 with Vue 3 and Nuxt
To use Bootstrap with Vue 3, the standard choice is BootstrapVueNext: Bootstrap 5’s components rebuilt as Vue components, such as <BButton>, <BModal>, <BNavbar>, and <BTable>, controlled with props and v-model instead of Bootstrap’s JavaScript. This guide explains which library to use (the original BootstrapVue doesn’t support Vue 3), how to install it with Vite or Nuxt, the components you’ll use most, and how to apply a custom theme.
BootstrapVue or BootstrapVueNext?
| BootstrapVue | BootstrapVueNext | |
|---|---|---|
| npm package | bootstrap-vue |
bootstrap-vue-next |
| Vue version | Vue 2 | Vue 3 |
| Bootstrap version | Bootstrap 4 | Bootstrap 5.3 |
| Latest version | 2.23.1, last updated April 2025 | 1.2.4 |
| Use for | Maintaining old Vue 2 apps | New projects |
Vue 2 reached end of life on December 31, 2023, and BootstrapVue never added Vue 3 or Bootstrap 5 support. It still gets about 230,000 weekly npm downloads from existing apps, but for anything new, use BootstrapVueNext, which reached its stable 1.x releases and gets about 76,000 weekly downloads in November 2026.
Install with Vite
npm create vue@latest my-app
cd my-app
npm install bootstrap bootstrap-vue-next
Import Bootstrap’s CSS and the library’s own CSS in src/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')
Then wrap your app in <BApp> in App.vue. It provides the services that modals, toasts, and popovers need:
<script setup lang="ts">
import { BApp } from 'bootstrap-vue-next'
</script>
<template>
<BApp>
<RouterView />
</BApp>
</template>
Older guides register a plugin with app.use(createBootstrap()) instead. It still works, but the docs now recommend <BApp>. Don’t load Bootstrap’s own JavaScript bundle: the Vue components replace it.
Import components automatically
Import each component where you use it (import { BButton } from 'bootstrap-vue-next'), or let a Vite plugin do it:
npm install -D unplugin-vue-components
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import Components from 'unplugin-vue-components/vite'
import { BootstrapVueNextResolver } from 'bootstrap-vue-next/resolvers'
export default defineConfig({
plugins: [vue(), Components({ resolvers: [BootstrapVueNextResolver()] })],
})
Every <B...> component in your templates is then imported for you, and only the ones you use end up in the bundle.
Install with Nuxt
npm install bootstrap bootstrap-vue-next @bootstrap-vue-next/nuxt
Add the module to nuxt.config.ts and Bootstrap’s CSS to the global styles:
export default defineNuxtConfig({
modules: ['@bootstrap-vue-next/nuxt'],
css: ['bootstrap/dist/css/bootstrap.min.css'],
})
The module registers the components automatically. Check the BootstrapVueNext Nuxt docs for its options.
Buttons and layout
<script setup lang="ts">
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<BContainer>
<BRow class="g-4">
<BCol md="8">
<BButton variant="primary" @click="count++">Clicked {{ count }} times</BButton>
</BCol>
<BCol md="4">Sidebar</BCol>
</BRow>
</BContainer>
</template>
variant takes Bootstrap’s color names (primary, outline-secondary, danger, and so on), and md="8" becomes col-md-8. Utility classes such as g-4, mt-3, or d-flex go in class as usual. The underlying classes are explained in the buttons guide and the columns guide.
A responsive navbar
<template>
<BNavbar toggleable="lg" variant="dark" data-bs-theme="dark">
<BNavbarBrand href="/">Acme</BNavbarBrand>
<BNavbarToggle target="main-nav" />
<BCollapse id="main-nav" is-nav>
<BNavbarNav class="ms-auto">
<BNavItem href="/pricing">Pricing</BNavItem>
<BNavItemDropdown text="Resources" placement="bottom-end">
<BDropdownItem href="/docs">Docs</BDropdownItem>
<BDropdownItem href="/blog">Blog</BDropdownItem>
</BNavItemDropdown>
</BNavbarNav>
</BCollapse>
</BNavbar>
</template>
toggleable="lg" collapses the links below the large breakpoint, and data-bs-theme="dark" makes the text light on the dark background. For links handled by Vue Router, use the to prop instead of href: <BNavItem to="/pricing">. The plain HTML version is in the Bootstrap navbar guide.
A modal with v-model
<script setup lang="ts">
import { ref } from 'vue'
const show = ref(false)
function deleteProject() { /* call your API */ }
</script>
<template>
<BButton variant="danger" @click="show = true">Delete project</BButton>
<BModal v-model="show" title="Delete this project?" ok-title="Delete" ok-variant="danger"
cancel-title="Cancel" @ok="deleteProject">
This can't be undone.
</BModal>
</template>
v-model opens and closes the modal, and @ok runs when the OK button is clicked. Props such as centered, size="lg", scrollable, and no-close-on-backdrop match the options in the Bootstrap modal guide.
Forms
<script setup lang="ts">
import { ref } from 'vue'
const email = ref('')
const plan = ref('Free')
const updates = ref(true)
function onSubmit() { /* send the form */ }
</script>
<template>
<BForm @submit.prevent="onSubmit">
<BFormGroup label="Email" label-for="email" description="We'll never share it.">
<BFormInput id="email" v-model="email" type="email" required />
</BFormGroup>
<BFormGroup label="Plan" label-for="plan">
<BFormSelect id="plan" v-model="plan" :options="['Free', 'Pro']" />
</BFormGroup>
<BFormCheckbox v-model="updates" switch>Email me product updates</BFormCheckbox>
<BButton type="submit" variant="primary" class="mt-3">Create account</BButton>
</BForm>
</template>
BFormGroup links the label to the input and adds help text, and switch turns a checkbox into a toggle switch. Validation messages go in the group’s invalid-feedback prop with :state="false". The classes underneath are covered in the Bootstrap forms guide.
Tables with sorting
<script setup lang="ts">
const items = [
{ name: 'Ana Lopez', role: 'Admin', projects: 12 },
{ name: 'Ben Carter', role: 'Editor', projects: 4 },
]
const fields = [
{ key: 'name', sortable: true },
'role',
{ key: 'projects', sortable: true },
]
</script>
<template>
<BTable striped hover responsive :items="items" :fields="fields" />
</template>
Unlike plain Bootstrap, BTable sorts columns marked sortable for you, and it also supports filtering, pagination with BPagination, and custom cell templates. The styling options are explained in the Bootstrap table guide.
Toasts and alerts from code
<script setup lang="ts">
import { useToast } from 'bootstrap-vue-next'
const toast = useToast()
function save() {
toast.create({ title: 'Saved', body: 'Your changes were saved.', variant: 'success' })
}
</script>
<template>
<BButton @click="save">Save</BButton>
<BAlert :model-value="true" variant="warning" dismissible>Your trial ends in 3 days.</BAlert>
</template>
useToast() works because <BApp> wraps the app. Alerts and toasts are explained in the alerts guide and the toast guide.
Custom themes
BootstrapVueNext uses Bootstrap’s normal classes, so a custom Bootstrap theme restyles every component. Replace the CSS import with your own Sass:
npm install -D sass
// src/styles/custom.scss
$primary: #2f55ff;
$border-radius: .75rem;
$font-family-sans-serif: "Inter", system-ui, sans-serif;
@import "bootstrap/scss/bootstrap";
Then import ./styles/custom.scss in main.ts instead of bootstrap/dist/css/bootstrap.css, keeping the bootstrap-vue-next.css import. How the variables work is in Bootstrap Sass variables explained, and you can design the theme visually in the bootstrap.build editor and export the Sass. Dark mode works through Bootstrap’s data-bs-theme attribute; see the dark mode guide.
Bootstrap in Vue without a component library
You can also use plain Bootstrap classes in Vue templates and call Bootstrap’s JavaScript yourself for interactive parts:
<script setup lang="ts">
import { onMounted, onBeforeUnmount, ref } from 'vue'
import { Tooltip } from 'bootstrap'
const el = ref<HTMLElement>()
let tooltip: Tooltip | undefined
onMounted(() => { tooltip = new Tooltip(el.value!) })
onBeforeUnmount(() => tooltip?.dispose())
</script>
<template>
<button ref="el" class="btn btn-secondary" data-bs-title="Save changes">Save</button>
</template>
That’s fine for a page or two, but every modal, dropdown, and tooltip needs this setup and cleanup, which BootstrapVueNext handles for you. If you use React instead, the equivalent library is React Bootstrap.
FAQ
Does BootstrapVue work with Vue 3?
No. BootstrapVue supports Vue 2 and Bootstrap 4 only. For Vue 3 and Bootstrap 5, use BootstrapVueNext (bootstrap-vue-next), which has a similar component API.
How do I install Bootstrap in Vue 3?
Run npm install bootstrap bootstrap-vue-next, import bootstrap/dist/css/bootstrap.css and bootstrap-vue-next/dist/bootstrap-vue-next.css in main.ts, and wrap your app in <BApp>. Then use components such as <BButton> and <BModal>.
How do I use Bootstrap with Nuxt?
Install bootstrap, bootstrap-vue-next, and @bootstrap-vue-next/nuxt, add '@bootstrap-vue-next/nuxt' to modules in nuxt.config.ts, and add Bootstrap’s CSS to the css array. The components are then available in every page.
Do I need Bootstrap’s JavaScript with BootstrapVueNext?
No. BootstrapVueNext reimplements modals, dropdowns, collapses, tooltips, and the other interactive parts in Vue. Load only Bootstrap’s CSS; loading its JavaScript as well can make components behave twice.
How do I customize the Bootstrap theme in a Vue app?
Install sass, create a SCSS file that sets variables such as $primary before @import "bootstrap/scss/bootstrap", and import that file in main.ts instead of Bootstrap’s CSS. All BootstrapVueNext components pick up the new theme.
Try it in the builder
Make these changes visually with a live preview, then export clean Bootstrap Sass or CSS.
Open the Builder