Skip to content

Conversation

mikenewbon
Copy link
Contributor

πŸ”— Linked issue

Resolves #5201

❓ Type of change

  • πŸ“– Documentation (updates to the documentation or readme)
  • 🐞 Bug fix (a non-breaking change that fixes an issue)
  • πŸ‘Œ Enhancement (improving an existing functionality)
  • ✨ New feature (a non-breaking change that adds functionality)
  • 🧹 Chore (updates to the build process or auxiliary tools and libraries)
  • ⚠️ Breaking change (fix or feature that would cause existing functionality to change)

πŸ“š Description

An implementation of a flexible, multi-column, vertical/horizontal scroll-area component using Tanstack virtual.

πŸ“ Checklist

  • I have linked an issue or discussion.
  • I have updated the documentation accordingly.

@mikenewbon
Copy link
Contributor Author

scroll-area
@benjamincanac
Got an initial version working, and managed to implement a working gap for multiple lanes. Would like to figure out a nice input of min/max lanes with target size to be responsive. Still lots to do but a cool demo!

Comment on lines +65 to +98

#component
:scroll-area-horizontal-example

#code
```vue
<script setup lang="ts">
const images = ref(
Array.from({ length: 20 }, (_, i) => ({
id: i + 1,
url: `https://picsum.photos/300/200?random=${i}`,
title: `Image ${i + 1}`
}))
)
</script>

<template>
<UScrollArea
:items="images"
orientation="horizontal"
class="w-full border border-default rounded-lg p-4"
>
<template #default="{ item }">
<div class="inline-block me-4">
<img
:src="item.url"
:alt="item.title"
class="w-[300px] h-[200px] rounded-lg object-cover"
>
<p class="mt-2 text-sm text-center">{{ item.title }}</p>
</div>
</template>
</UScrollArea>
</template>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need this it should be automatic 😊

* Enable virtualization for large lists.
* @defaultValue false
*/
virtualize?: boolean | {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use the type from @tanstack/vue-virtual: https://github.com/nuxt/ui/blob/v4/src/runtime/components/Table.vue#L100

lanes: 1
}))
const virtualizer = useVirtualizer({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be simpler to spread the options here like: https://github.com/nuxt/ui/blob/v4/src/runtime/components/Table.vue#L409-L415

</script>

<template>
<Primitive
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need a way to not have this root slot when using in a component that already has one: https://github.com/nuxt/ui/blob/v4/src/runtime/components/Table.vue#L639

</template>

<template v-else-if="items?.length">
<slot
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure defining a default slot multiple times works here πŸ€”

@mikenewbon
Copy link
Contributor Author

Ah sorry @benjamincanac - didnt mean for you to spend time reviewing yet, I was just excited about the demo πŸ˜…

Copy link
Member

Yeah don't worry I just took a quick look at it 😊 The demo is really cool!

@alliecatowo
Copy link

I'd love to see skeleton support for something like this!

I was implementing a scrollable component that UTable won't really work for with tan-virtual, and had the similar scroll behavior when jumping down a large list, where everything blanks out for a second. If that behaviors unavoidable, skeletons or some other placeholder prop could really help the visual flow. Infinite scroll is definitely a component Nuxt UI could use :)

Loving the demo by the way! πŸ’ͺ🏻

@mikenewbon
Copy link
Contributor Author

I'd love to see skeleton support for something like this!

I was implementing a scrollable component that UTable won't really work for with tan-virtual, and had the similar scroll behavior when jumping down a large list, where everything blanks out for a second. If that behaviors unavoidable, skeletons or some other placeholder prop could really help the visual flow. Infinite scroll is definitely a component Nuxt UI could use :)

A lot of the rendering time is taken up by the height calculation, if you have a consistent row height - using the correct estimate size improves the scrolling empty state a lot. I dont see support for a loading/skeleton state in tanstack virtual. There is a check for is scrolling, I will try to expose this and you could could show some kind of skeleton, otherwise if you're dynamically calling data on render, you would need to implement a loading state inside your row.

@alliecatowo If you find any helpful references please link them, I would love to solve this also.

Copy link

pkg-pr-new bot commented Oct 18, 2025

npm i https://pkg.pr.new/@nuxt/ui@5245

commit: abc0e88

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

v4 #4488

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add 'ScrollArea' component with tanstack virtualization

3 participants