#Scroll Area
Augments native scroll functionality for custom, cross-browser styling and supports virtual scrolling for large lists.
#Component Features
- Custom scrollbar styling across all browsers.
- Supports vertical, horizontal, or both directions.
- Smooth scrolling support.
- Scroll position and edge detection events.
- Virtual Scrolling support for rendering massive lists efficiently.
#Both Directions
<script setup lang="ts">
import { BrScrollArea } from '@breezeui/vue'
const artworks = [
{
artist: 'Ornella Binni',
art: 'https://images.unsplash.com/photo-1465869185982-5a1a7522cbcb?auto=format&fit=crop&w=300&q=80',
},
{
artist: 'Tom Byrom',
art: 'https://images.unsplash.com/photo-1548516173-3cabfa4607e9?auto=format&fit=crop&w=300&q=80',
},
{
artist: 'Vladimir Malyavko',
art: 'https://images.unsplash.com/photo-1494337480532-3725c85fd2ab?auto=format&fit=crop&w=300&q=80',
},
]
</script>
<template>
<BrScrollArea class="h-[200px] w-full max-w-[350px] whitespace-nowrap rounded-md border" direction="both" type="always">
<div class="flex w-max space-x-4 p-4">
<figure v-for="artwork in artworks" :key="artwork.artist" class="shrink-0">
<div class="overflow-hidden rounded-md">
<img
:src="artwork.art"
:alt="artwork.artist"
class="aspect-[3/4] h-fit w-fit object-cover"
width="150"
height="200"
>
</div>
<figcaption class="pt-2 text-xs text-muted-foreground">
Photo by <span class="font-semibold text-foreground">{{ artwork.artist }}</span>
</figcaption>
</figure>
</div>
</BrScrollArea>
</template>#Smooth Scroll & Events
<script setup lang="ts">
import { BrScrollArea, BrButton } from '@breezeui/vue'
const scrollTo = (id: string) => {
const el = document.getElementById(id)
if (el) {
el.scrollIntoView({ behavior: 'smooth', block: 'start' })
}
}
const handleScrollTop = () => { console.log('Scrolled to top') }
const handleScrollBottom = () => { console.log('Scrolled to bottom') }
const handleScrollPosition = (pos: { x: number; y: number }) => {
// console.log('Position:', pos)
}
</script>
<template>
<div>
<div class="flex gap-2 mb-4">
<BrButton size="sm" @click="scrollTo('section-1')">Section 1</BrButton>
<BrButton size="sm" @click="scrollTo('section-2')">Section 2</BrButton>
<BrButton size="sm" @click="scrollTo('section-3')">Section 3</BrButton>
</div>
<BrScrollArea
smooth
class="h-[250px] w-full max-w-[400px] rounded-md border p-4"
@scroll-top="handleScrollTop"
@scroll-bottom="handleScrollBottom"
@scroll-position="handleScrollPosition"
>
<div class="space-y-8">
<div id="section-1" class="h-[200px] rounded bg-primary/10 p-4 flex items-center justify-center">Section 1</div>
<div id="section-2" class="h-[200px] rounded bg-secondary/10 p-4 flex items-center justify-center">Section 2</div>
<div id="section-3" class="h-[200px] rounded bg-destructive/10 p-4 flex items-center justify-center">Section 3</div>
</div>
</BrScrollArea>
</div>
</template>#With Table
<script setup lang="ts">
import { BrScrollArea, BrCard, BrCardHeader, BrCardTitle, BrCardContent, BrTable } from '@breezeui/vue'
const tableColumns = [
{ key: 'invoice', title: 'Invoice', width: 100 },
{ key: 'status', title: 'Status' },
{ key: 'method', title: 'Method' },
{ key: 'amount', title: 'Amount', align: 'right' },
]
const tableData = Array.from({ length: 15 }).map((_, i) => ({
invoice: `INV00${i + 1}`,
status: 'Paid',
method: 'Credit Card',
amount: `$${(Math.random() * 1000).toFixed(2)}`,
}))
</script>
<template>
<BrCard class="w-full max-w-[800px]">
<BrCardHeader>
<BrCardTitle>Recent Orders</BrCardTitle>
</BrCardHeader>
<BrCardContent>
<BrScrollArea class="h-[300px] w-full rounded-md border" direction="both">
<div class="min-w-[800px]">
<BrTable :columns="tableColumns" :data="tableData" />
</div>
</BrScrollArea>
</BrCardContent>
</BrCard>
</template>#Infinite Scroll
<script setup lang="ts">
import { ref } from 'vue'
import { BrScrollArea } from '@breezeui/vue'
const infiniteList = ref(Array.from({ length: 20 }).map((_, i) => `Item ${i + 1}`))
const isLoadingMore = ref(false)
const handleInfiniteScroll = () => {
if (isLoadingMore.value) return
isLoadingMore.value = true
// Simulate network request
setTimeout(() => {
const currentLength = infiniteList.value.length
const moreItems = Array.from({ length: 10 }).map((_, i) => `Item ${currentLength + i + 1}`)
infiniteList.value.push(...moreItems)
isLoadingMore.value = false
}, 1000)
}
</script>
<template>
<BrScrollArea
class="h-[300px] w-full max-w-[400px] rounded-md border p-4"
:scroll-threshold="50"
@scroll-bottom="handleInfiniteScroll"
>
<div class="space-y-4">
<div
v-for="item in infiniteList"
:key="item"
class="rounded bg-primary/5 p-4 flex items-center justify-between"
>
<span>{{ item }}</span>
</div>
<div v-if="isLoadingMore" class="py-4 flex justify-center items-center text-sm text-muted-foreground">
<span class="animate-pulse">Loading more...</span>
</div>
</div>
</BrScrollArea>
</template>#Virtual Scrolling
You can enable virtual scrolling to render lists with thousands of items without performance issues.
<script setup lang="ts">
import { BrScrollArea } from '@breezeui/vue'
const virtualItems = Array.from({ length: 10000 }).map((_, i) => ({
id: i,
text: `Virtual Item ${i + 1}`,
}))
</script>
<template>
<BrScrollArea
class="h-[300px] w-full max-w-[400px] rounded-md border bg-card"
virtual-scroll
:items="virtualItems"
:item-height="40"
>
<template #item="{ item, index }">
<div class="flex items-center px-4 h-[40px] text-sm border-b border-border/50 last:border-b-0 hover:bg-muted/50 transition-colors">
<span class="text-muted-foreground/70 w-12 text-xs">{{ index + 1 }}</span>
<span class="font-normal text-foreground">{{ item.text }}</span>
</div>
</template>
</BrScrollArea>
</template>#API
#Props
| Name | Type | Default | Description |
|---|---|---|---|
type | 'auto' | 'always' | 'scroll' | 'hover' | 'hover' | Describes the nature of scrollbar visibility. |
direction | 'vertical' | 'horizontal' | 'both' | 'vertical' | The direction of the scroll area. |
smooth | boolean | false | Enables smooth scrolling behavior. |
scrollThreshold | number | 0 | Distance in pixels from the edge to trigger infinite scroll events. |
virtualScroll | boolean | false | Enables virtual scrolling mode. |
items | any[] | [] | Array of items to render when virtual scrolling is enabled. |
itemHeight | number | 40 | Fixed height of each item in pixels for virtual scrolling. |
#Events
| Name | Parameters | Description |
|---|---|---|
scroll-position | (position: { x: number; y: number }) | Emitted when scrolling occurs, providing current coordinates. |
scroll-top | - | Emitted when scrolled to the top edge (considering threshold). |
scroll-bottom | - | Emitted when scrolled to the bottom edge (considering threshold). |
scroll-left | - | Emitted when scrolled to the left edge (considering threshold). |
scroll-right | - | Emitted when scrolled to the right edge (considering threshold). |
#Slots
| Name | Scope | Description |
|---|---|---|
default | - | The main content to be scrolled. |
item | { item: any, index: number } | Custom template for each item in virtual scroll mode. |