Scrollbar
This component provides a unified scrollbar experience because native browser scrollbars often look inconsistent across browsers.
Basic Usage
Wrap content with b-scrollbar. The default slot is the content area, as shown below:
<template>
<div style="height: 300px">
<b-scrollbar ref="componentScrollBar" style="height: 100%">
<div class="scrollbar-demo-list">
<div v-for="i in 12" :key="i" class="scrollbar-demo-item">Scroll Demo Block {{ i }}</div>
</div>
</b-scrollbar>
</div>
</template>
<style scoped>
.scrollbar-demo-list {
padding: 4px;
}
.scrollbar-demo-item {
display: flex;
align-items: center;
justify-content: center;
height: 56px;
margin: 10px 0;
border-radius: 8px;
background: linear-gradient(135deg, #f8fbff 0%, #eef5ff 100%);
color: #3a4a66;
font-weight: 500;
}
</style>Note: If the content does not exceed the container height, no scrollbar is rendered.
Max Height
Use max-height to limit the maximum height of the scroll area. The scrollbar only appears when the content exceeds this height.
Item 1
Item 2
Item 3
Item 4
Item 5
<template>
<div>
<div style="margin-bottom: 12px">
<b-button size="small" @click="add">Add Item</b-button>
<b-button size="small" style="margin-left: 8px" @click="remove">Delete Item</b-button>
</div>
<b-scrollbar max-height="320px">
<p v-for="item in count" :key="item" class="scrollbar-demo-item">
Item {{ item }}
</p>
</b-scrollbar>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const count = ref(5)
function add() {
count.value++
}
function remove() {
if (count.value > 0) {
count.value--
}
}
</script>
<style scoped>
.scrollbar-demo-item {
display: flex;
align-items: center;
justify-content: center;
height: 48px;
margin: 10px 0;
border-radius: 6px;
background: #f5f7fa;
color: #606266;
}
</style>Manual Scroll
Use the exposed setScrollTop and setScrollLeft methods to control the scroll position manually.
Manual Scroll 1
Manual Scroll 2
Manual Scroll 3
Manual Scroll 4
Manual Scroll 5
Manual Scroll 6
Manual Scroll 7
Manual Scroll 8
Manual Scroll 9
Manual Scroll 10
Manual Scroll 11
Manual Scroll 12
Manual Scroll 13
Manual Scroll 14
Manual Scroll 15
Manual Scroll 16
Manual Scroll 17
Manual Scroll 18
Manual Scroll 19
Manual Scroll 20
<template>
<div>
<b-scrollbar ref="scrollbarRef" height="320px" always @scroll="handleScroll">
<div ref="innerRef">
<p v-for="item in 20" :key="item" class="scrollbar-demo-item">
Manual Scroll {{ item }}
</p>
</div>
</b-scrollbar>
<div style="margin-top: 16px">
<b-slider v-model="value" :max="max" :format-tooltip="formatTooltip"></b-slider>
</div>
</div>
</template>
<script setup lang="ts">
import { nextTick, onMounted, ref, watch } from 'vue'
const max = ref(0)
const value = ref(0)
const innerRef = ref<HTMLElement | null>(null)
const scrollbarRef = ref<{
setScrollTop: (scrollTop: number) => void
wrapRef?: {
value: HTMLElement | null
}
} | null>(null)
function handleScroll({ scrollTop }: { scrollTop: number }) {
value.value = scrollTop
}
function formatTooltip(currentValue: number) {
return `${currentValue}px`
}
function updateMaxScroll() {
const wrapElement = scrollbarRef.value?.wrapRef?.value
const contentHeight = innerRef.value?.clientHeight || 0
const viewportHeight = wrapElement?.clientHeight || 0
max.value = Math.max(contentHeight - viewportHeight, 0)
}
watch(value, currentValue => {
scrollbarRef.value?.setScrollTop(currentValue)
})
onMounted(async () => {
await nextTick()
updateMaxScroll()
})
</script>
<style scoped>
.scrollbar-demo-item {
display: flex;
align-items: center;
justify-content: center;
height: 48px;
margin: 10px 0;
border-radius: 6px;
background: #f5f7fa;
color: #606266;
}
</style>Always Show
Use always to keep the scrollbar visible instead of showing it only on hover.
<template>
<div style="height: 300px">
<b-scrollbar ref="componentScrollBar" always noresize>
<div class="scrollbar-demo-list">
<div v-for="i in 12" :key="i" class="scrollbar-demo-item">Always Visible Block {{ i }}</div>
</div>
</b-scrollbar>
</div>
</template>
<style scoped>
.scrollbar-demo-list {
padding: 4px;
}
.scrollbar-demo-item {
display: flex;
align-items: center;
justify-content: center;
height: 56px;
margin: 10px 0;
border-radius: 8px;
background: linear-gradient(135deg, #f8fbff 0%, #eef5ff 100%);
color: #3a4a66;
font-weight: 500;
}
</style>Custom Scrollbar Styles
You can customize the scrollbar with props or override its styles with CSS.
<template>
<div style="height: 300px">
<b-scrollbar
ref="componentScrollBar"
always
noresize
:bar-style="{ background: 'rgba(110, 23, 122, 0.3)' }"
:bar-wrap-style="{ background: 'rgba(0, 0, 0, 0.03)' }"
>
<div class="scrollbar-demo-list">
<div v-for="i in 12" :key="i" class="scrollbar-demo-item">Custom Styled Block {{ i }}</div>
</div>
</b-scrollbar>
</div>
</template>
<style scoped>
.scrollbar-demo-list {
padding: 4px;
}
.scrollbar-demo-item {
display: flex;
align-items: center;
justify-content: center;
height: 56px;
margin: 10px 0;
border-radius: 8px;
background: linear-gradient(135deg, #f7efff 0%, #efe4ff 100%);
color: #5c2a86;
font-weight: 500;
}
</style>Infinite Scroll
end-reached is triggered when the scrollbar reaches an edge. It supports top / bottom / left / right and is commonly used for infinite loading.
Infinite Scroll Item 1
Infinite Scroll Item 2
Infinite Scroll Item 3
Infinite Scroll Item 4
Infinite Scroll Item 5
Infinite Scroll Item 6
Infinite Scroll Item 7
Infinite Scroll Item 8
Infinite Scroll Item 9
Infinite Scroll Item 10
Infinite Scroll Item 11
Infinite Scroll Item 12
Infinite Scroll Item 13
Infinite Scroll Item 14
Infinite Scroll Item 15
Infinite Scroll Item 16
Infinite Scroll Item 17
Infinite Scroll Item 18
Infinite Scroll Item 19
Infinite Scroll Item 20
<template>
<b-scrollbar height="320px" :distance="16" @end-reached="loadMore">
<p v-for="item in count" :key="item" class="scrollbar-demo-item">
Infinite Scroll Item {{ item }}
</p>
</b-scrollbar>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const count = ref(20)
function loadMore(direction: 'top' | 'bottom' | 'left' | 'right') {
if (direction === 'bottom') {
count.value += 5
}
}
</script>
<style scoped>
.scrollbar-demo-item {
display: flex;
align-items: center;
justify-content: center;
height: 48px;
margin: 10px 0;
border-radius: 6px;
background: #f5f7fa;
color: #606266;
}
</style>Notes
- The parent container of
b-scrollbarshould have a fixed height b-scrollbaritself should usually be set toheight: 100%- If an unwanted horizontal scrollbar appears, add
.bin-scrollbar__wrap { overflow-x: hidden; }
Props
| Parameter | Description | Type | Options | Default |
|---|---|---|---|---|
| distance | Trigger distance for end-reached in pixels | Number | - | 0 |
| height | Height of the scroll area | String / Number | - | — |
| maxHeight | Maximum height of the scroll area | String / Number | - | — |
| native | Whether to use native scrolling | Boolean | true | false |
| always | Whether to always show the scrollbar instead of only on hover | Boolean | true | false |
| wrapStyle | Inline style for the wrap container | String / Object / Array | - | — |
| wrapClass | Class name for the wrap container | String / Array | - | — |
| viewClass | Class name for the view container | String / Array | - | — |
| viewStyle | Inline style for the view container | String / Object / Array | - | — |
| noresize | If the container size does not change, setting this to true can optimize performance | Boolean | true | false |
| tag | Element tag of the view container | String | - | div |
| minSize | Minimum scrollbar size | Number | - | 20 |
| tabindex | Tabindex of the wrap container | String / Number | - | — |
| barStyle | Scrollbar thumb style | Object | - | {} |
| barWrapStyle | Scrollbar bar container style | Object | - | {} |
Events
| Event Name | Description | Callback |
|---|---|---|
| scroll | Triggered when scrolling | { scrollTop, scrollLeft } |
| end-reached | Triggered when an edge is reached | direction: 'top' | 'bottom' | 'left' | 'right' |
Methods
| Method Name | Description | Parameters |
|---|---|---|
| handleScroll | Manually trigger scroll handling | — |
| scrollTo | Scroll to a specific position | (options) or (x, y) |
| setScrollTop | Set vertical scroll distance | (scrollTop: number) |
| setScrollLeft | Set horizontal scroll distance | (scrollLeft: number) |
| update | Manually update scrollbar state | — |
| wrapRef | Scroll container instance ref | — |