Skip to content

Scrollbar

WxScrollbar is a box that scrolls with a bar that matches the rest of the admin panel — a log, a list of comments, a tall filter panel, a table too wide for its column.

A panel that scrolls on its own

queue.worker job #1000 finished in 20ms

queue.worker job #1001 finished in 27ms

queue.worker job #1002 finished in 34ms

queue.worker job #1003 finished in 41ms

queue.worker job #1004 finished in 48ms

queue.worker job #1005 finished in 55ms

queue.worker job #1006 finished in 62ms

queue.worker job #1007 finished in 69ms

queue.worker job #1008 finished in 76ms

queue.worker job #1009 finished in 83ms

queue.worker job #1010 finished in 90ms

queue.worker job #1011 finished in 97ms

queue.worker job #1012 finished in 104ms

queue.worker job #1013 finished in 21ms

queue.worker job #1014 finished in 28ms

queue.worker job #1015 finished in 35ms

queue.worker job #1016 finished in 42ms

queue.worker job #1017 finished in 49ms

queue.worker job #1018 finished in 56ms

queue.worker job #1019 finished in 63ms

queue.worker job #1020 finished in 70ms

queue.worker job #1021 finished in 77ms

queue.worker job #1022 finished in 84ms

queue.worker job #1023 finished in 91ms

queue.worker job #1024 finished in 98ms

queue.worker job #1025 finished in 105ms

queue.worker job #1026 finished in 22ms

queue.worker job #1027 finished in 29ms

queue.worker job #1028 finished in 36ms

queue.worker job #1029 finished in 43ms

queue.worker job #1030 finished in 50ms

queue.worker job #1031 finished in 57ms

queue.worker job #1032 finished in 64ms

queue.worker job #1033 finished in 71ms

queue.worker job #1034 finished in 78ms

queue.worker job #1035 finished in 85ms

queue.worker job #1036 finished in 92ms

queue.worker job #1037 finished in 99ms

queue.worker job #1038 finished in 106ms

queue.worker job #1039 finished in 23ms

Sideways, with the bar always visible
Column 1Column 2Column 3Column 4Column 5Column 6Column 7Column 8Column 9Column 10Column 11Column 12

Usage

vue
<template>
  <wx-scrollbar :height="240">
    <p v-for="line in log" :key="line.id">{{ line.text }}</p>
  </wx-scrollbar>
</template>

max-height instead of height lets the box grow with its content and only start scrolling once it would get too tall:

vue
<template>
  <wx-scrollbar max-height="50vh">…</wx-scrollbar>
</template>

Scrolling from code

The component exposes the scrolling element itself along with three helpers, so a log that follows new lines needs no wrapper of its own:

vue
<script setup lang="ts">
import { ref, nextTick } from 'vue'
import { WxScrollbar } from '@webx-ui/core'

const log = ref<InstanceType<typeof WxScrollbar> | null>(null)

async function append(line: string) {
  lines.value.push(line)
  await nextTick()
  log.value?.scrollToBottom('smooth')
}
</script>

<template>
  <wx-scrollbar ref="log" :height="240" @scroll="onScroll">…</wx-scrollbar>
</template>
ExposedSignatureDescription
elHTMLElement | nullThe scrolling element
scrollTo(options: ScrollTarget) => voidNative scrollTo
scrollToTop(behavior?: ScrollMotion) => voidBack to the start
scrollToBottom(behavior?: ScrollMotion) => voidTo the end — a log following output

Sideways

vue
<template>
  <wx-scrollbar axis="x" always>
    <div class="wide-row">…</div>
  </wx-scrollbar>
</template>

Scroll chaining

A scroll that reaches the end of the box stops there rather than carrying on to the page behind it — what you want for a panel inside a dialog. chain-scroll restores the browser default.

Props

PropTypeDefaultDescription
heightnumber | stringFixed height
maxHeightnumber | stringHeight it grows to before scrolling
axis'y' | 'x' | 'both''y'Which way the content scrolls
size'sm' | 'md''md'Thickness of the bar
alwaysbooleanfalseKeeps the bar visible instead of on hover
chainScrollbooleanfalseLets a scroll carry on to the page behind it

Events: scroll (Event).

Slots: default — the content.

What it is not

This is native scrolling, themed — not a pair of <div>s moved about in JavaScript. Keyboard scrolling, momentum, the trackpad's own overlay bar and every accessibility setting the browser has all keep working, and the component adds the colour and the thickness on top: scrollbar-width and scrollbar-color where they are honoured, ::-webkit-scrollbar where they are not. The trade-off is that a browser which supports neither shows its own bar, which is a far better failure than a panel that cannot be scrolled.

Both colours are variables, so a panel on a dark surface can correct them:

vue
<template>
  <wx-scrollbar style="--wx-scrollbar-thumb: var(--wx-border-strong)">…</wx-scrollbar>
</template>

Released under the MIT License.