Skip to content

ListView

Unified virtualized list component. Renders only visible items plus overscan for smooth scrolling. Supports passive (parent-controlled scroll) and navigable (built-in keyboard/mouse) modes.

Import

tsx
import { ListView } from "silvery"

Usage

tsx
// Passive — parent controls scroll position
<ListView
  items={logs}
  height={20}
  renderItem={(item, index) => <Text>{item.message}</Text>}
/>

// Navigable — built-in j/k, arrows, PgUp/PgDn, Home/End, G, mouse wheel
<ListView
  items={items}
  height={20}
  navigable
  renderItem={(item, i, meta) => (
    <Text inverse={meta.isCursor}>{item.name}</Text>
  )}
  onSelect={(index) => openItem(items[index])}
/>

Props

Core

PropTypeDefaultDescription
itemsT[]requiredArray of items to render
heightnumberrequiredViewport height in rows
renderItem(item: T, index: number, meta: ListItemMeta) => ReactNoderequiredRender function for each item
estimateHeightnumber | (index: number) => number1Estimated height per item in rows
getKey(item: T, index: number) => string | numberindexKey extractor
widthnumberViewport width (uses parent width if omitted)

Scrolling

PropTypeDefaultDescription
scrollTonumberIndex to scroll to (ignored when navigable)
overscannumber5Extra items rendered beyond viewport
maxRenderednumber100Maximum items rendered at once
scrollPaddingnumber2Padding from edge before scrolling (in items)
overflowIndicatorbooleanfalseShow overflow indicators
gapnumber0Gap between items in rows
renderSeparator() => ReactNodeCustom separator between items
listFooterReactNodeContent after all items in scroll container
virtualized(item: T, index: number) => booleanPredicate for already-virtualized prefix items
PropTypeDefaultDescription
navigablebooleanEnable built-in keyboard and mouse navigation
cursorIndexnumberControlled cursor position
onCursorIndexChange(index: number) => voidCalled when cursor moves
onSelect(index: number) => voidCalled when Enter is pressed
activebooleantrueWhether keyboard input is captured

Infinite Scroll

PropTypeDefaultDescription
onEndReached() => voidCalled when near the end of the list
onEndReachedThresholdnumber5Items from end to trigger onEndReached

ListItemMeta

ts
interface ListItemMeta {
  /** Whether this item is at the cursor position (navigable mode only) */
  isCursor: boolean
}

Ref Handle (ListViewHandle)

MethodTypeDescription
scrollToItem(index)(index: number) => voidImperatively scroll to an item

Keyboard Shortcuts (navigable mode)

KeyAction
j / DownMove cursor down
k / UpMove cursor up
G / EndJump to last item
HomeJump to first item
PgDn / Ctrl+DPage down (half viewport)
PgUp / Ctrl+UPage up (half viewport)
EnterSelect item at cursor

Examples

Variable Height Items

tsx
<ListView
  items={messages}
  height={20}
  estimateHeight={(index) => messages[index].lines}
  renderItem={(msg) => <Text>{msg.content}</Text>}
  scrollTo={messages.length - 1}
/>

With Custom Separators

tsx
<ListView
  items={sections}
  height={15}
  navigable
  renderItem={(item, i, meta) => <Text inverse={meta.isCursor}>{item.title}</Text>}
  renderSeparator={() => <Text color="$border">{"─".repeat(40)}</Text>}
/>

Infinite Scroll

tsx
<ListView
  items={feed}
  height={20}
  navigable
  renderItem={(item) => <Text>{item.title}</Text>}
  onEndReached={loadMore}
  onEndReachedThreshold={10}
/>

Released under the MIT License.