Skip to content
Permalink
Browse files
feat(b-sidebar): add optional backdrop support (#5182)
* feat(b-sidebar): add backdrop support

* Update sidebar.js

* Update sidebar.js

* Update _sidebar.scss

* Update sidebar.spec.js

* Update sidebar.spec.js

* Update _sidebar.scss

* Update _sidebar.scss

* Update styles.scss

* Update _sidebar.scss

* Update sidebar.js

* Update sidebar.js

* Update sidebar.js

* lint

* Update sidebar.js

* Update package.json

* Update sidebar.spec.js

* Update sidebar.js

* Update sidebar.spec.js

* Update sidebar.spec.js

* Update sidebar.spec.js

* Update sidebar.spec.js

* Update sidebar.spec.js

* Update sidebar.spec.js

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update dom.js

* Update sidebar.js

* Update dom.js

* Update modal.js

* Update modal.js

* Update modal.js

* Update dom.js

* Update modal.js

* lint

* Update sidebar.js

* Update sidebar.js

* Update sidebar.js

* Update sidebar.js

* lint

* Update sidebar.js

* Update README.md

* Update README.md

* Update sidebar.js

* Update sidebar.js

* Update sidebar.spec.js

* Update sidebar.spec.js

* Update sidebar.spec.js

* Update sidebar.spec.js

* Update sidebar.spec.js

* Update sidebar.spec.js

* Update sidebar.spec.js

* Update sidebar.js

* Update sidebar.js

* Update sidebar.js

* Update package.json

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update sidebar.js

* Update _sidebar.scss

* Update README.md

* Update _sidebar.scss

* Update dom.js

Co-authored-by: Jacob Müller <jacob.mueller.elz@gmail.com>
  • Loading branch information
tmorehouse and jacobmllr95 committed Apr 19, 2020
1 parent 83180f1 commit c6375e5513cb0ec33a9bc9fc894a123d74cf7768
Showing 8 changed files with 324 additions and 78 deletions.
@@ -271,7 +271,8 @@ table#table-transition-example {
}

// `<b-sidebar>` overrides for docs
.b-sidebar {
.b-sidebar-outer,
.b-sidebar{
z-index: 1071;
}

@@ -5,7 +5,7 @@ import identity from '../../utils/identity'
import observeDom from '../../utils/observe-dom'
import { arrayIncludes, concat } from '../../utils/array'
import { getComponentConfig } from '../../utils/config'
import { closest, contains, isVisible, requestAF, select, selectAll } from '../../utils/dom'
import { closest, contains, getTabables, isVisible, requestAF, select } from '../../utils/dom'
import { isBrowser } from '../../utils/env'
import { EVENT_OPTIONS_NO_CAPTURE, eventOn, eventOff } from '../../utils/events'
import { stripTags } from '../../utils/html'
@@ -37,20 +37,6 @@ const OBSERVER_CONFIG = {
attributeFilter: ['style', 'class']
}

// Query selector to find all tabbable elements
// (includes tabindex="-1", which we filter out after)
const TABABLE_SELECTOR = [
'button',
'[href]:not(.disabled)',
'input',
'select',
'textarea',
'[tabindex]',
'[contenteditable]'
]
.map(s => `${s}:not(:disabled):not([disabled])`)
.join(', ')

// --- Utility methods ---

// Attempt to focus an element, and return true if successful
@@ -564,14 +550,6 @@ export const BModal = /*#__PURE__*/ Vue.extend({
}
return null
},
// Private method to get a list of all tabable elements within modal content
getTabables() {
// Find all tabable elements in the modal content
// Assumes users have not used tabindex > 0 on elements!
return selectAll(TABABLE_SELECTOR, this.$refs.content)
.filter(isVisible)
.filter(i => i.tabIndex > -1 && !i.disabled)
},
// Private method to finish showing modal
doShow() {
/* istanbul ignore next: commenting out for now until we can test stacking */
@@ -727,7 +705,7 @@ export const BModal = /*#__PURE__*/ Vue.extend({
) {
return
}
const tabables = this.getTabables()
const tabables = getTabables(this.$refs.content)
const { bottomTrap, topTrap } = this.$refs
if (bottomTrap && target === bottomTrap) {
// If user pressed TAB out of modal into our bottom trab trap element
@@ -2,7 +2,8 @@

> Otherwise known as off-canvas or a side drawer, BootstrapVue's custom `<b-sidebar>` component is a
> fixed-position toggleable slide out box, which can be used for navigation, menus, details, etc. It
> can be positioned on either the left (default) or right of the viewport.
> can be positioned on either the left (default) or right of the viewport, with optional backdrop
> support.
## Overview

@@ -118,8 +119,28 @@ for no shadow.
### Borders

By default, `<b-sidebar>` has no borders. Use
[border utility classes](/docs/reference/utility-classes) to add border(s) to `<b-sidebar>`, or use
CSS style overrides.
[border utility classes](/docs/reference/utility-classes) to add border(s) to `<b-sidebar>` (via the
`sidebar-class` prop <span class="badge badge-secondary">2.12.0+</span>), or use CSS style
overrides.

```html
<template>
<div>
<b-button v-b-toggle.sidebar-border>Toggle Sidebar</b-button>
<b-sidebar id="sidebar-border" sidebar-class="border-right border-danger">
<div class="px-3 py-2">
<p>
Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis
in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
</p>
<b-img src="https://picsum.photos/500/500/?image=54" fluid thumbnail></b-img>
</div>
</b-sidebar>
</div>
</template>

<!-- b-sidebar-border.vue -->
```

### Width

@@ -142,6 +163,9 @@ slide transition via the `no-slide` prop.
[reduced motion section of our accessibility documentation](/docs/reference/accessibility) for
additional details.

When disabling the slid transition, the fade transition of the [optional backdrop](#backdrop) will
also be disabled.

### Z-index

The sidebar has a default `z-index` defined in SCSS/CSS. In some situations you may need to use a
@@ -237,6 +261,43 @@ In some instances, you may not want the content rendered when the sidebar is not
the `lazy` prop on `<b-sidebar>`. When `lazy` is `true`, the body and optional footer will _not_ be
rendered (removed from DOM) whenever the sidebar is closed.

### Backdrop

<span class="badge badge-info small">2.12.0+</span>

Add a basic backdrop when the side bar is open via the `backdrop` prop. When set to `true`, the
sidebar will show an opaque backdrop. Clicking on the backdrop will close the sidebar, unless the
`no-close-on-backdrop` prop is set to `true`.

```html
<template>
<div>
<b-button v-b-toggle.sidebar-backdrop>Toggle Sidebar</b-button>
<b-sidebar
id="sidebar-backdrop"
title="Sidebar with backdrop"
backdrop
shadow
>
<div class="px-3 py-2">
<p>
Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis
in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
</p>
<b-img src="https://picsum.photos/500/500/?image=54" fluid thumbnail></b-img>
</div>
</b-sidebar>
</div>
</template>

<!-- b-sidebar-backdrop.vue -->
```

Note that when the sidebar is open, it may still be possible to scroll the body (unlike the
behaviour of modals). When the backdrop in enabled, focus constraint will attempt to keep focus
within the sidebar. Note that in rare circumstances it might be possible for users to move focus to
elements outside of the sidebar.

## Visibility control

### `v-b-toggle` directive
@@ -285,7 +346,11 @@ reader and keyboard-only users. When the sidebar is closed, the element that pre
before the sidebar was opened will be re-focused.

When the sidebar is open, users can press <kbd>Esc</kbd> to close the sidebar. To disable this
feature, set the `no-close-on-esc` prop to `true`.
feature, set the `no-close-on-esc` prop to `true`. with the backdrop enabled, you can use the prop
`no-close-on-backdrop` to disable the close on backdrop click feature.

When the `backdrop` prop is `true`, the sidebar will attempt to constrain focus within the sidebar,
and the sidebar will have the attribute `aria-modal="true"` set.

When you have hidden the header, or do not have a title for the sidebar, set either `aria-label` to
a string that describes the sidebar, or set `aria-labelledby` to an ID of an element that contains
@@ -1,16 +1,36 @@
.b-sidebar-outer {
position: fixed !important;
top: 0;
left: 0;
right: 0;
height: 0;
overflow: visible;
z-index: $b-sidebar-zindex;
}

.b-sidebar-backdrop {
position: fixed !important;
top: 0;
left: 0;
z-index: -1;
width: 100vw;
height: 100vh;
background-color: #000;
opacity: 0.5;
}

.b-sidebar {
display: flex;
flex-direction: column;
position: fixed !important;
top: 0;
bottom: 0;
height: 100vh;
width: $b-sidebar-width;
max-width: 100% !important;
height: 100vh !important;
margin: 0 !important;
outline: 0;
transform: translateX(0);
z-index: $b-sidebar-zindex;

&.slide {
transition: transform $b-sidebar-transition-duration ease-in-out;
@@ -54,6 +54,11 @@
"prop": "closeLabel",
"description": "`aria-label` to apply to the built-in close button. Defaults to 'Close'"
},
{
"prop": "sidebarClass",
"version": "2.12.0",
"description": "Class, or classes, to apply to the sidebar content wrapper"
},
{
"prop": "headerClass",
"description": "Class, or classes, to apply to the built in header. Has no effect if prop `no-header` is set"
@@ -66,6 +71,11 @@
"prop": "footerClass",
"description": "Class, or classes, to apply to the optional `footer` slot"
},
{
"prop": "backdrop",
"version": "2.12.0",
"description": "When `true`, shows a backdrop when the sidebar is open"
},
{
"prop": "lazy",
"description": "When set to `true`, the content of the sidebar will only be rendered while the sidebar is open"
@@ -82,6 +92,11 @@
"prop": "noCloseOnEsc",
"description": "When set to `true`, disables closing the sidebar when the user presses ESC"
},
{
"prop": "noCloseOnBackdrop",
"version": "2.12.0",
"description": "When set to `true`, disables closing the sidebar when the user clicks on the backdrop. Requires that the prop `backdrop` be set"
},
{
"prop": "noCloseOnRouteChange",
"description": "When set to `true`, disables closing of the sidebar on route change"

0 comments on commit c6375e5

Please sign in to comment.