VirtualList
Frames long scrollable collections for virtualization adapters.
See it in context
Preview
Copy a working example
Usage
Astro examples assume UIPrimitives is mounted once in your root layout. Do not add the runtime next to each component instance.
---
import { VirtualList } from '@santi020k/lumen-astro'
const rows = Array.from({ length: 200 }, (_, index) => `Deployment #${200 - index}`)
---
{/* 200 rows, but only the visible slice is rendered while scrolling. */}
<VirtualList aria-label="Deployments" data-ui-item-size="44" style="--ui-list-height: 12rem">
{rows.map(row => <div>{row}</div>)}
</VirtualList>---
import { VirtualList } from '@santi020k/lumen-astro'
const rows = Array.from({ length: 200 }, (_, index) => `Deployment #${200 - index}`)
---
{/* 200 rows, but only the visible slice is rendered while scrolling. */}
<VirtualList aria-label="Deployments" data-ui-item-size="44" style="--ui-list-height: 12rem">
{rows.map(row => <div>{row}</div>)}
</VirtualList>import { VirtualList } from '@santi020k/lumen-react'
export const Example = () => (
<>
{/* 200 rows, but only the visible slice is rendered while scrolling. */}
<VirtualList aria-label="Deployments" data-ui-item-size="44" style={{ -UiListHeight: '12rem' }}>
{rows.map(row => <div>{row}</div>)}
</VirtualList>
</>
)import { VirtualList } from '@santi020k/lumen-react'
export const Example = () => (
<>
{/* 200 rows, but only the visible slice is rendered while scrolling. */}
<VirtualList aria-label="Deployments" data-ui-item-size="44" style={{ -UiListHeight: '12rem' }}>
{rows.map(row => <div>{row}</div>)}
</VirtualList>
</>
)<script type="module">
import { defineLumenElements } from '@santi020k/lumen-elements/define'
defineLumenElements()
</script>
{/* 200 rows, but only the visible slice is rendered while scrolling. */}
<lumen-virtual-list aria-label="Deployments" data-ui-item-size="44" style="--ui-list-height: 12rem">
{rows.map(row => <div>{row}</div>)}
</lumen-virtual-list><script type="module">
import { defineLumenElements } from '@santi020k/lumen-elements/define'
defineLumenElements()
</script>
{/* 200 rows, but only the visible slice is rendered while scrolling. */}
<lumen-virtual-list aria-label="Deployments" data-ui-item-size="44" style="--ui-list-height: 12rem">
{rows.map(row => <div>{row}</div>)}
</lumen-virtual-list>Choose your target
Add this component
Choose the package for your runtime. All adapters share the Lumen stylesheet. Use the matching registry command when you want a local wrapper for that framework.
pnpm add @santi020k/lumen-astropnpm add @santi020k/lumen-astrolumen add VirtualListlumen add VirtualListpnpm add @santi020k/lumen-reactpnpm add @santi020k/lumen-reactlumen add VirtualList --target reactlumen add VirtualList --target reactpnpm add @santi020k/lumen-elementspnpm add @santi020k/lumen-elementslumen add VirtualList --target elementslumen add VirtualList --target elementsGlass
Add the glass prop to apply the shared blur, saturation, border, and highlight tokens. Glass reads best over vivid content, so place the surface above imagery or color.
---
import { VirtualList } from '@santi020k/lumen-astro'
---
<div class="docs-glass-demo">
<VirtualList glass style="--ui-list-height: 12rem;">
<div>Frosted row 1</div>
<div>Frosted row 2</div>
<div>Frosted row 3</div>
<div>Frosted row 4</div>
</VirtualList>
</div>---
import { VirtualList } from '@santi020k/lumen-astro'
---
<div class="docs-glass-demo">
<VirtualList glass style="--ui-list-height: 12rem;">
<div>Frosted row 1</div>
<div>Frosted row 2</div>
<div>Frosted row 3</div>
<div>Frosted row 4</div>
</VirtualList>
</div>import { VirtualList } from '@santi020k/lumen-react'
export const Example = () => (
<>
<div className="docs-glass-demo">
<VirtualList glass style={{ -UiListHeight: '12rem' }}>
<div>Frosted row 1</div>
<div>Frosted row 2</div>
<div>Frosted row 3</div>
<div>Frosted row 4</div>
</VirtualList>
</div>
</>
)import { VirtualList } from '@santi020k/lumen-react'
export const Example = () => (
<>
<div className="docs-glass-demo">
<VirtualList glass style={{ -UiListHeight: '12rem' }}>
<div>Frosted row 1</div>
<div>Frosted row 2</div>
<div>Frosted row 3</div>
<div>Frosted row 4</div>
</VirtualList>
</div>
</>
)<script type="module">
import { defineLumenElements } from '@santi020k/lumen-elements/define'
defineLumenElements()
</script>
<div class="docs-glass-demo">
<lumen-virtual-list glass style="--ui-list-height: 12rem;">
<div>Frosted row 1</div>
<div>Frosted row 2</div>
<div>Frosted row 3</div>
<div>Frosted row 4</div>
</lumen-virtual-list>
</div><script type="module">
import { defineLumenElements } from '@santi020k/lumen-elements/define'
defineLumenElements()
</script>
<div class="docs-glass-demo">
<lumen-virtual-list glass style="--ui-list-height: 12rem;">
<div>Frosted row 1</div>
<div>Frosted row 2</div>
<div>Frosted row 3</div>
<div>Frosted row 4</div>
</lumen-virtual-list>
</div>API reference
Lumen-specific props and runtime attributes for the Astro primitive. React props follow the same names; Elements use equivalent kebab-case attributes where custom elements expose them.
| Attribute | Values | Default | Description |
|---|---|---|---|
| glass | boolean | "subtle" | "strong" | false | Applies the tokenized liquid-glass surface treatment with backdrop-filter fallbacks; "subtle" and "strong" adjust the fill intensity. |
| itemSize | number | string | - | Fixed size for items if all are uniform height/width. Used for virtual scroll calculation. |
| overscan | number | string | - | Number of items to render outside the viewport. |
| class, className | string | "" | Merges custom classes with the generated ui-* root classes. |
| ...native attributes | HTML attributes | - | Forwards standard attributes to the root element unless the component consumes them. |
Runtime events
CustomEvents dispatched by the Astro UIPrimitives runtime for this component.
| Event | Target | Detail | When |
|---|---|---|---|
| ui:virtual-list-range | VirtualList root ([data-ui-virtual-list]) | { startIndex: number, endIndex: number } | Fires when the virtual list calculates its visible range on initialization or scroll. |