BToggle
A light-weight directive for toggling visibility state for collapses, offcanvas, and modals by ID. It automatically sets the aria-controls attribute and registers the trigger with the target component, which then manages aria-expanded and visual state
The
v-b-toggledirective provides a simple, declarative way to toggle visibility of components likeBCollapse,BOffcanvas, andBModal. The directive automatically handles accessibility and can target multiple components at once.
<div>
<BButton
v-b-toggle.collapse-overview
variant="primary"
>Toggle Collapse</BButton
>
<BCollapse
id="collapse-overview"
class="mt-3"
>
<BCard>
<p class="card-text">This content can be toggled visible or hidden.</p>
</BCard>
</BCollapse>
</div>Overview
Things to know when using the toggle directive:
- The directive works with
BCollapse,BOffcanvas, andBModalcomponents - Target components are specified by their
idattribute - Multiple targets can be toggled simultaneously
- The directive automatically manages ARIA accessibility attributes
- The trigger element receives
collapsedandnot-collapsedCSS classes based on target state - Disabled buttons will not trigger toggle events
Target Specification
The v-b-toggle directive offers flexible ways to specify target components:
Using Modifiers
The most common approach is using modifiers, where each modifier represents a target ID:
<BButton
v-b-toggle.collapse-modifier
variant="primary"
>
Toggle with Modifier
</BButton>
<BCollapse
id="collapse-modifier"
class="mt-3"
>
<BCard>
<p class="card-text">Toggled using <code>v-b-toggle.collapse-modifier</code></p>
</BCard>
</BCollapse>Using Directive Argument
You can specify the target as a directive argument (supports Vue's dynamic arguments):
<div>
<BButton
v-b-toggle:collapse-argument
variant="primary"
>Toggle with Argument</BButton
>
<BCollapse
id="collapse-argument"
class="mt-3"
>
<BCard>
<p class="card-text">Toggled using <code>v-b-toggle:collapse-argument</code></p>
</BCard>
</BCollapse>
</div>Using Directive Value
The directive value can be a string ID or an array of IDs:
<div>
<BButton
v-b-toggle="'collapse-value'"
variant="primary"
>Toggle with Value</BButton
>
<BCollapse
id="collapse-value"
class="mt-3"
>
<BCard>
<p class="card-text">Toggled using <code>v-b-toggle="'collapse-value'"</code></p>
</BCard>
</BCollapse>
</div>All Methods
Here are all the ways to specify targets:
<!-- Using modifiers (multiple targets allowed) -->
<BButton v-b-toggle.target-id>Toggle</BButton>
<BButton v-b-toggle.target-1.target-2>Toggle Multiple</BButton><!-- Using directive argument (supports Vue dynamic arguments) -->
<BButton v-b-toggle:target-id>Toggle</BButton>
<BButton v-b-toggle:[dynamicTarget]>Toggle</BButton><!-- Using directive value (string or array) -->
<BButton v-b-toggle="'target-id'">Toggle</BButton>
<BButton v-b-toggle="'target-1 target-2'">Toggle Multiple (space-separated)</BButton>
<BButton v-b-toggle="['target-1', 'target-2']">Toggle Multiple (array)</BButton><!-- Using href attribute on links -->
<BLink
v-b-toggle
href="#target-id"
@click.prevent
>Toggle</BLink
>
<a
v-b-toggle
href="#target-id"
@click.prevent
>Toggle</a
><!-- Combining multiple methods (all targets will be toggled) -->
<BButton v-b-toggle.target-1:target-2="['target-3', 'target-4']">Toggle 4 Targets</BButton>Multiple Targets
Toggle multiple components simultaneously using any of these methods:
Using Modifiers
Using Space-Separated String
Using Array
<template>
<!-- #region template -->
<div>
<h5>Using Modifiers</h5>
<BButton
v-b-toggle.collapse-a.collapse-b
variant="primary"
class="mb-2"
>
Toggle Both Collapses
</BButton>
<h5>Using Space-Separated String</h5>
<BButton
v-b-toggle="'collapse-a collapse-b'"
variant="success"
class="mb-2"
>
Toggle Both Collapses
</BButton>
<h5>Using Array</h5>
<BButton
v-b-toggle="['collapse-a', 'collapse-b']"
variant="info"
class="mb-3"
>
Toggle Both Collapses
</BButton>
<BCollapse
id="collapse-a"
class="mb-2"
>
<BCard
header="Collapse A"
border-variant="primary"
>
<p class="card-text">This is collapse A</p>
</BCard>
</BCollapse>
<BCollapse id="collapse-b">
<BCard
header="Collapse B"
border-variant="success"
>
<p class="card-text">This is collapse B</p>
</BCard>
</BCollapse>
</div>
<!-- #endregion template -->
</template>Using on Links
When the directive is applied to an <a> tag or BLink, the target can be specified via the href attribute:
<div>
<p>
<BLink
v-b-toggle
href="#collapse-href"
@click.prevent
>
Toggle with BLink (prevents navigation)
</BLink>
</p>
<p>
<a
v-b-toggle
href="#collapse-href"
@click.prevent
>
Toggle with anchor tag (prevents navigation)
</a>
</p>
<p>
<a
v-b-toggle
href="#collapse-href"
>
Toggle with anchor tag (allows navigation - URL will change)
</a>
</p>
<BCollapse
id="collapse-href"
class="mt-3"
>
<BCard>
<p class="card-text">Toggled using <code>href="#collapse-href"</code></p>
</BCard>
</BCollapse>
</div>URL Navigation
Without @click.prevent, clicking the link will change the browser URL and may scroll the page. Add @click.prevent to prevent this behavior.
Conditional CSS Classes
The directive automatically adds CSS classes to the trigger element based on the target's visibility state:
collapsed- Added when the target is hiddennot-collapsed- Added when the target is visible
You can use these classes to conditionally show/hide content:
<template>
<div>
<BButton
v-b-toggle.collapse-css
variant="primary"
>
<span class="when-open">Hide</span>
<span class="when-closed">Show</span>
Content
</BButton>
<BCollapse
id="collapse-css"
class="mt-3"
>
<BCard>
<p class="card-text">
The button text changes based on the collapse state using CSS classes.
</p>
</BCard>
</BCollapse>
</div>
</template>
<style scoped>
/* Hide "Hide" text when collapsed, show "Show" text */
.collapsed > .when-open {
display: none;
}
/* Hide "Show" text when not collapsed, show "Hide" text */
.not-collapsed > .when-closed {
display: none;
}
</style>The CSS pattern for conditional display:
.collapsed > .when-open, .not-collapsed > .when-closed { display: none; }Preventing Toggle
Set the disabled attribute on the trigger element to prevent it from toggling the target:
<template>
<div>
<BButton
v-b-toggle.collapse-disabled
:disabled="isDisabled"
variant="primary"
class="mb-2"
>
Toggle (Currently {{ isDisabled ? 'Disabled' : 'Enabled' }})
</BButton>
<BButton
variant="secondary"
class="mb-2 ms-2"
@click="isDisabled = !isDisabled"
>
{{ isDisabled ? 'Enable' : 'Disable' }} Toggle Button
</BButton>
<BCollapse
id="collapse-disabled"
class="mt-2"
>
<BCard>
<p class="card-text">
When the toggle button is disabled, clicking it will not affect this collapse.
</p>
</BCard>
</BCollapse>
</div>
</template>
<script setup lang="ts">
import {ref} from 'vue'
const isDisabled = ref(false)
</script>This works with <button>, BButton, BLink, and any element that supports the disabled attribute.
Compatible Components
The v-b-toggle directive works with these components:
BCollapse
Toggle collapsible content. See the modifier example above for a demonstration.
For more details, see the BCollapse documentation.
BOffcanvas
Toggle off-canvas sidebars:
<template>
<!-- #region template -->
<div>
<BButton
v-b-toggle.offcanvas-demo
variant="primary"
>Toggle Offcanvas</BButton
>
<BOffcanvas
id="offcanvas-demo"
title="Offcanvas Title"
>
<p>This offcanvas is controlled by the v-b-toggle directive.</p>
<p>Click the close button or outside the offcanvas to hide it.</p>
</BOffcanvas>
</div>
<!-- #endregion template -->
</template>See the BOffcanvas documentation for more details.
BModal
The v-b-toggle directive also works with modals. However, for modals, the dedicated v-b-modal directive is recommended as it's an alias specifically designed for modal use cases.
See the BModal documentation for more details.
Comparison with Programmatic Control
The v-b-toggle directive is ideal for simple, declarative toggling. For programmatic control, use the useToggle composable or v-model:
Using v-b-toggle Directive
Using useToggle Composable
Using v-model
<template>
<div>
<h5>Using v-b-toggle Directive</h5>
<BButton
v-b-toggle.collapse-directive
variant="primary"
class="mb-3"
>
Toggle with Directive
</BButton>
<BCollapse
id="collapse-directive"
class="mb-4"
>
<BCard>
<p class="card-text">Simple, declarative approach for basic toggle functionality.</p>
</BCard>
</BCollapse>
<h5>Using useToggle Composable</h5>
<BButton
variant="success"
class="mb-3"
@click="() => toggleComposable()"
>
Toggle with Composable
</BButton>
<BCollapse
id="collapse-composable"
class="mb-4"
>
<BCard>
<p class="card-text">Programmatic control with full access to visibility state.</p>
<p class="mb-0">Current state: {{ composableValue ? 'Visible' : 'Hidden' }}</p>
</BCard>
</BCollapse>
<h5>Using v-model</h5>
<BButton
variant="info"
class="mb-3"
@click="isManual = !isManual"
>
Toggle with v-model
</BButton>
<BCollapse
id="collapse-manual"
v-model="isManual"
>
<BCard>
<p class="card-text">Direct control via reactive state binding.</p>
<p class="mb-0">Current state: {{ isManual ? 'Visible' : 'Hidden' }}</p>
</BCard>
</BCollapse>
</div>
</template>
<script setup lang="ts">
import {ref} from 'vue'
import {useToggle} from 'bootstrap-vue-next/composables/useToggle'
// Using useToggle composable
const {toggle: toggleComposable, value: composableValue} = useToggle('collapse-composable')
// Using v-model
const isManual = ref(false)
</script>| Approach | Use When | Pros | Cons |
|---|---|---|---|
v-b-toggle | Simple click-to-toggle | Declarative, minimal code | Click-only, no state access |
useToggle | Need programmatic control + state access | Full API, reactive state | More code |
v-model | Direct reactive binding | Simple, two-way binding | Manual event handling required |
Accessibility
The directive automatically handles accessibility by setting and managing ARIA attributes:
What the Directive Manages
The v-b-toggle directive sets:
aria-controls- Lists the IDs of all target components (static, set once)
What the Target Component Manages
The target component (BCollapse, BOffcanvas, etc.) manages:
aria-expanded- Reflects current visibility state ('true'or'false')
The directive itself handles the CSS classes (collapsed/not-collapsed) and click event handlers on the trigger element.
This separation of responsibilities ensures consistent accessibility across all show/hide components. For detailed information, see the ARIA Visibility Architecture documentation.
Best Practices
- Only use the directive on keyboard-focusable elements (buttons, links, form controls)
- Avoid applying to decorative elements like
<div>or<span>unless you also add appropriate ARIA attributes and keyboard handling yourself - For elements that don't have a native role of
buttonorlink, manually add an appropriaterole(for example,role="button") and atabindex(such astabindex="0") so they are keyboard-focusable
Multiple Target Caveats
When toggling multiple targets, the aria-expanded attribute on the trigger reflects the state based on the first target component. If individual targets have independent visibility controls (via v-model, other toggle buttons, or programmatic control), the aria-expanded value may not accurately reflect all targets' states.
For better accessibility with multiple independent targets, use separate toggle buttons for each target.
See Also
- BCollapse component - Collapsible content with accordion support
- BOffcanvas component - Off-canvas sidebars
- BModal component - Modal dialogs
- useToggle composable - Programmatic visibility control
- ARIA Visibility Architecture - Technical details on accessibility implementation