Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ const items = Array.from({ length: 1000 }).map((_, index) => {
:virtualize="{
gap: 16,
lanes: 3,
estimateSize: 480
estimateSize: 480,
dynamicSize: true
}"
class="w-full h-128 p-4"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ const items = Array.from({ length: 1000 }).map((_, index) => {
:virtualize="{
gap,
lanes,
estimateSize: 480
estimateSize: 480,
dynamicSize: true
}"
class="w-full h-128 p-4"
>
Expand Down
37 changes: 35 additions & 2 deletions docs/content/docs/2.components/scroll-area.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ Use the `virtualize` prop to render only the items currently in view, significan
When virtualization is **enabled**, customize spacing via the `virtualize` prop options like `gap`, `paddingStart`, and `paddingEnd`. Otherwise, use the `ui` prop to apply classes like `gap p-4` on the `viewport` slot.
::

::tip
For fixed-size items, set `estimateSize` to match your item height for best performance. The component will skip expensive per-item DOM measurements and use the estimated size directly.
::

::component-example
---
collapse: true
Expand All @@ -89,9 +93,38 @@ options:

## Examples

### As masonry layout
### With variable height items

For items with variable heights, you have two options:

1. **Auto-measurement with `dynamicSize: true`**: The component measures each item's DOM element automatically. Best for masonry layouts or when sizes can't be predicted.

2. **Manual measurement with `measure(size)`**: Use the `measure` function from slot props to provide pre-calculated sizes, avoiding expensive DOM measurements.



```vue
<template>
<!-- Option 1: Auto-measurement -->
<UScrollArea :items="items" :virtualize="{ dynamicSize: true }">
<template #default="{ item }">
<MasonryCard :item="item" />
</template>
</UScrollArea>

<!-- Option 2: Manual measurement with pre-calculated size -->
<UScrollArea :items="items" virtualize>
<template #default="{ item, measure }">
<div :ref="() => measure(item.height)">
<ContentCard :item="item" />
</div>
</template>
</UScrollArea>
</template>
```


Use the `virtualize` prop with `lanes`, `gap`, and `estimateSize` options to create Pinterest-style masonry layouts with variable height items.
Use the `lanes` and `gap` options to create Pinterest-style masonry layouts:

::component-example
---
Expand Down
4 changes: 2 additions & 2 deletions docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
"@nuxt/ui": "workspace:*",
"@nuxtjs/mcp-toolkit": "^0.5.2",
"@nuxtjs/plausible": "^2.0.1",
"@tiptap/extension-emoji": "3.13.0",
"@tiptap/extension-text-align": "3.13.0",
"@tiptap/extension-emoji": "^3.14.0",
"@tiptap/extension-text-align": "^3.14.0",
"@octokit/rest": "^22.0.1",
"@regle/core": "^1.14.3",
"@regle/rules": "^1.14.3",
Expand Down
29 changes: 16 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -133,19 +133,22 @@
"@tailwindcss/vite": "^4.1.18",
"@tanstack/vue-table": "^8.21.3",
"@tanstack/vue-virtual": "^3.13.13",
"@tiptap/core": "3.13.0",
"@tiptap/extension-bubble-menu": "3.13.0",
"@tiptap/extension-drag-handle-vue-3": "3.13.0",
"@tiptap/extension-floating-menu": "3.13.0",
"@tiptap/extension-horizontal-rule": "3.13.0",
"@tiptap/extension-image": "3.13.0",
"@tiptap/extension-mention": "3.13.0",
"@tiptap/extension-placeholder": "3.13.0",
"@tiptap/markdown": "3.13.0",
"@tiptap/pm": "3.13.0",
"@tiptap/starter-kit": "3.13.0",
"@tiptap/suggestion": "3.13.0",
"@tiptap/vue-3": "3.13.0",
"@tiptap/core": "^3.14.0",
"@tiptap/extension-bubble-menu": "^3.14.0",
"@tiptap/extension-collaboration": "^3.14.0",
"@tiptap/extension-drag-handle": "^3.14.0",
"@tiptap/extension-drag-handle-vue-3": "^3.14.0",
"@tiptap/extension-node-range": "^3.14.0",
"@tiptap/extension-floating-menu": "^3.14.0",
"@tiptap/extension-horizontal-rule": "^3.14.0",
"@tiptap/extension-image": "^3.14.0",
"@tiptap/extension-mention": "^3.14.0",
"@tiptap/extension-placeholder": "^3.14.0",
"@tiptap/markdown": "^3.14.0",
"@tiptap/pm": "^3.14.0",
"@tiptap/starter-kit": "^3.14.0",
"@tiptap/suggestion": "^3.14.0",
"@tiptap/vue-3": "^3.14.0",
"@unhead/vue": "^2.0.19",
"@vueuse/core": "^14.1.0",
"@vueuse/integrations": "^14.1.0",
Expand Down
3 changes: 2 additions & 1 deletion playgrounds/nuxt/app/pages/components/scroll-area.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ const virtualizeOptions = computed(() => {
return {
estimateSize: estimateSize.value,
gap: gap.value,
lanes: lanes.value
lanes: lanes.value,
dynamicSize: true
}
})
</script>
Expand Down
4 changes: 2 additions & 2 deletions playgrounds/nuxt/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
"@iconify-json/simple-icons": "^1.2.63",
"@internationalized/date": "^3.10.1",
"@nuxt/ui": "workspace:*",
"@tiptap/extension-emoji": "3.13.0",
"@tiptap/extension-text-align": "3.13.0",
"@tiptap/extension-emoji": "^3.14.0",
"@tiptap/extension-text-align": "^3.14.0",
"ai": "^5.0.114",
"nuxt": "^4.2.2",
"zod": "^4.2.1"
Expand Down
4 changes: 2 additions & 2 deletions playgrounds/vue/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
},
"dependencies": {
"@nuxt/ui": "workspace:*",
"@tiptap/extension-emoji": "3.13.0",
"@tiptap/extension-text-align": "3.13.0",
"@tiptap/extension-emoji": "^3.14.0",
"@tiptap/extension-text-align": "^3.14.0",
"vue": "^3.5.25",
"vue-router": "^4.6.3",
"zod": "^4.2.1"
Expand Down
Loading
Loading