Skip to content

Offcanvas

Sliding side panel component based on Bootstrap 5, with optional extension panel support.

Description

Offcanvas is a wrapper around Bootstrap 5’s Offcanvas component for showing side panels (by default from the right edge). It provides slots for title, body, header, and footer, and optionally an extension panel that can be shown or hidden for detail or list/detail views.

Location: @/components/interface/Bootstrap/Offcanvas.vue

Props

PropTypeRequiredDefaultDescription
extensionBoolean❌ NofalseEnables the extension panel (half-screen)
fotterBoolean❌ NotrueShows the footer area (note: prop name has typo "fotter")
extensionFotterBoolean❌ NotrueShows footer in the extension panel when active
extendedBoolean❌ NofalseInitial state of the extension panel (open/closed)
alignString❌ No'end'Side from which the panel opens: 'start' or 'end'
keyboardBoolean❌ NotrueAllows closing with Escape key (via data-bs-keyboard)
classString❌ No''Additional CSS classes for the offcanvas
menuClassString❌ No''Additional CSS classes for the menu
optionsObject❌ No{}Options passed to the Bootstrap Offcanvas constructor
onCloseFunction❌ No() => {}Callback when the offcanvas closes
closeOnEscapeBoolean❌ NotrueCloses the offcanvas when Escape is pressed (manual listener)

Slots

title

Main panel title.

vue
<template #title>
  {{ t('offcanvas.details') }}
</template>

subtitle

Subtitle below the title.

vue
<template #subtitle>
  <span class="badge bg-primary">ID: {{ id }}</span>
</template>

Extra content in the header (to the right of the title, before the close button).

vue
<template #header>
  <button class="btn btn-sm btn-outline-primary">Action</button>
</template>

body

Main panel content.

vue
<template #body>
  <div class="details">...</div>
</template>

fotter

Footer actions (slot name has typo "fotter" as in the component).

vue
<template #fotter>
  <button class="btn btn-primary" @click="save">{{ t('actions.save') }}</button>
</template>

Extension panel slots (when extension is true)

  • extension-title: Extension panel title.
  • extension-header: Extension panel header content.
  • extension: Extension panel body (e.g. list).
  • extension-footer: Extension panel footer.

Exposed Methods

The component exposes the following methods via ref:

show()

Opens the offcanvas.

javascript
const offcanvas = ref(null);

offcanvas.value.show();

hide()

Closes the offcanvas.

javascript
offcanvas.value.hide();

extension.show()

Opens the extension panel (when extension is true).

javascript
offcanvas.value.extension.show();

extension.hide()

Closes the extension panel.

javascript
offcanvas.value.extension.hide();

el

Reference to the Bootstrap Offcanvas instance (for advanced use).

Events

EventPayloadDescription
update:extendedbooleanEmitted when the extension panel state changes
closeeventEmitted when the offcanvas closes (hidden.bs.offcanvas)

Extension panel behavior

When extension is true:

  • The offcanvas can be shown in two widths: normal (w-33) or extended (w-66), except on mobile where it is always w-100.
  • extension.show() and extension.hide() switch between normal view and the view with the extension panel visible.
  • The extension panel has its own title, body, and footer via the extension-title, extension, extension-footer slots, etc.
  • The extended prop and update:extended event allow binding the state with the parent (v-model:extended).

Usage Examples

Basic Example

vue
<template>
  <button class="btn btn-primary" @click="offcanvas.show()">Open</button>

  <Offcanvas ref="offcanvas">
    <template #title>{{ t('offcanvas.info') }}</template>
    <template #body>
      <p>Panel content.</p>
    </template>
    <template #fotter>
      <button class="btn btn-primary" @click="offcanvas.hide()">
        {{ t('actions.close') }}
      </button>
    </template>
  </Offcanvas>
</template>

<script setup>
import { ref } from 'vue';
import Offcanvas from '@/components/interface/Bootstrap/Offcanvas.vue';

const offcanvas = ref(null);
</script>

Example with Extension Panel

vue
<template>
  <Offcanvas
    ref="offcanvas"
    :extension="true"
    v-model:extended="isExtended"
  >
    <template #title>Detail</template>
    <template #body>
      <div>Main content (e.g. item detail).</div>
      <button class="btn btn-link" @click="offcanvas.extension.show()">
        View list
      </button>
    </template>
    <template #extension-title>List</template>
    <template #extension>
      <ul>
        <li v-for="item in items" :key="item.id">{{ item.name }}</li>
      </ul>
    </template>
    <template #fotter>
      <button class="btn btn-primary">Save</button>
    </template>
  </Offcanvas>
</template>

<script setup>
import { ref } from 'vue';
import Offcanvas from '@/components/interface/Bootstrap/Offcanvas.vue';

const offcanvas = ref(null);
const isExtended = ref(false);
const items = ref([]);
</script>

Important Notes

  1. Footer slot name: The footer actions slot is named fotter (intentional typo in the component). Use <template #fotter>.

  2. Widths: On desktop, without extension it uses w-33, with extension w-66. On mobile it is always w-100.

  3. Close on Escape: If closeOnEscape is true, a global keydown listener is added to close on Escape; the offcanvas also closes via Bootstrap’s native behavior when keyboard is true.

  4. Bootstrap: Depends on Bootstrap 5 (bs.Offcanvas). It must be loaded in the project.

  5. Responsive: The component uses the useBreakPoints() composable to detect isMobile and adjust width.

Envia Admin