Vue NativeVue Native
Guide
Components
Composables
Navigation
Architecture
  • iOS
  • Android
  • macOS
GitHub
Guide
Components
Composables
Navigation
Architecture
  • iOS
  • Android
  • macOS
GitHub
  • Layout

    • VView
    • VScrollView
    • VSafeArea
    • VKeyboardAvoiding
  • Text & Input

    • VText
    • VInput
  • Interactive

    • VButton
    • VPressable
    • VSwitch
    • VSlider
    • VSegmentedControl
    • VCheckbox
    • VRadio
    • VDropdown
    • VRefreshControl
  • Media

    • VImage
    • VSVG
    • VWebView
    • VVideo
  • Lists

    • VList
    • VFlatList
    • VSectionList
  • Feedback

    • VActivityIndicator
    • VProgressBar
    • VAlertDialog
    • VActionSheet
    • VModal
    • VErrorBoundary
  • Transition & State

    • VTransition & VTransitionGroup
    • KeepAlive
    • VSuspense
  • Navigation

    • VNavigationBar
    • VTabBar
    • VDrawer
  • System

    • VStatusBar
    • VPicker
  • macOS

    • VToolbar
    • VSplitView
    • VOutlineView

VList

A virtualized scrollable list backed by UITableView on iOS and RecyclerView on Android. Efficient for large datasets -- only visible rows are rendered.

Usage

VList uses a :data prop and an #item slot to render each row. Do not use v-for inside VList -- the native virtualization engine manages which rows are rendered.

<script setup>
import { ref } from '@thelacanians/vue-native-runtime'

const items = ref([
  { id: 1, title: 'Item 1' },
  { id: 2, title: 'Item 2' },
  { id: 3, title: 'Item 3' },
])
</script>

<template>
  <VList
    :data="items"
    :keyExtractor="item => item.id"
    :style="{ flex: 1 }"
  >
    <template #item="{ item }">
      <VView :style="{ padding: 16, borderBottomWidth: 1, borderBottomColor: '#eee' }">
        <VText>{{ item.title }}</VText>
      </VView>
    </template>
  </VList>
</template>

Props

PropTypeDefaultDescription
dataArrayrequiredThe array of items to render
keyExtractor(item: T, index: number) => stringindex as stringFunction that returns a unique key for each item
styleStyleProp--Container styles
estimatedItemHeightnumber44Estimated extent per row along the scroll axis (height for vertical lists, width for horizontal), used to estimate which items fall inside the render window before layout runs
windowSizenumber10Number of extra items to mount above and below the visible window as a buffer. Higher values reduce blank flashes during fast scrolling but use more memory. Lists with length <= windowSize * 2 render every item without windowing.
showsScrollIndicatorbooleantrueShow/hide the scroll bar
bouncesbooleantrueBounce at top/bottom (iOS only)
horizontalbooleanfalseRender the list horizontally

Slots

SlotPropsDescription
#item{ item, index }Render each list item. Required.
#header--Content rendered above the list items
#footer--Content rendered below the list items
#empty--Content shown when data is an empty array

Events

EventPayloadDescription
@scroll{ x: number, y: number }Fires as the user scrolls
@endReached--Fires when scrolled near the bottom (20% threshold). Use this for infinite scroll / pagination

Platform Support

PlatformSupport
iOSFull (UITableView)
AndroidFull (RecyclerView)
macOSFull (NSTableView, single-column view-based)

Infinite scroll example

<script setup>
import { ref } from '@thelacanians/vue-native-runtime'

const items = ref(Array.from({ length: 20 }, (_, i) => ({ id: i + 1 })))
const loading = ref(false)

async function loadMore() {
  if (loading.value) return
  loading.value = true
  // fetch more items...
  loading.value = false
}
</script>

<template>
  <VList
    :data="items"
    :keyExtractor="item => item.id"
    :style="{ flex: 1 }"
    @endReached="loadMore"
  >
    <template #item="{ item }">
      <VView :style="{ padding: 16 }">
        <VText>Item {{ item.id }}</VText>
      </VView>
    </template>
    <template #footer>
      <VActivityIndicator v-if="loading" />
    </template>
  </VList>
</template>

Header, footer, and empty state

<template>
  <VList
    :data="items"
    :keyExtractor="item => item.id"
    :style="{ flex: 1 }"
  >
    <template #header>
      <VView :style="{ padding: 16 }">
        <VText :style="{ fontSize: 24, fontWeight: 'bold' }">My Items</VText>
      </VView>
    </template>

    <template #item="{ item }">
      <VView :style="{ padding: 16 }">
        <VText>{{ item.title }}</VText>
      </VView>
    </template>

    <template #empty>
      <VView :style="{ padding: 40, alignItems: 'center' }">
        <VText :style="{ color: '#999' }">No items yet</VText>
      </VView>
    </template>

    <template #footer>
      <VView :style="{ padding: 16, alignItems: 'center' }">
        <VText :style="{ color: '#999', fontSize: 12 }">End of list</VText>
      </VView>
    </template>
  </VList>
</template>

Performance

Set estimatedItemHeight close to your actual row height. This prevents layout jumps when the list first renders.

Edit this page
Last Updated: 8/12/26, 5:15 AM
Contributors: github-actions[bot], Abdul Hamid, Claude Fable 5
Next
VFlatList