legend-list
A 100% JavaScript, drop-in replacement for FlatList and FlashList with better performance on dynamically sized items and no native dependencies.
Repository Health
Technical Analysis
Legend List is a high-performance list component for React Native and React, written purely in TypeScript with no native modules to link. It targets the same use case as FlatList and FlashList but is built from the ground up to handle items with varying, dynamically computed heights without the jank or scroll jumps those alternatives run into.
Beyond raw performance, it adds features aimed at real product needs: bidirectional infinite scrolling without flashes, chat-style layouts that pin to the bottom without inverting the list, optional item recycling for maximum throughput, and separate entrypoints for React DOM and React Native so the same component works across web and native.
What You Get
- A
LegendListcomponent API-compatible withFlatList/FlashList(data,renderItem,keyExtractor,ListHeaderComponent, and more) - Optional item recycling, bidirectional infinite scroll, and chat-style bottom-alignment without list inversion
- Dedicated subpath entrypoints for React DOM, React Native, Reanimated, keyboard-aware scrolling, and section lists
- An imperative ref API (
scrollToIndex,scrollToOffset,scrollToEnd) for programmatic control - Zero native dependencies — 100% JavaScript/TypeScript, so there’s no native linking or pod install step
Common Use Cases
- Chat and messaging interfaces that need bottom-pinned, non-inverted scrolling
- Social or content feeds with variable-height cards (text, images, video)
- Migrating away from FlatList’s performance ceiling or FlashList’s native dependency
- Cross-platform apps that share one virtualized list implementation across web and native
Under The Hood
Architecture
The public LegendList component (src/components/LegendList.tsx) wraps a StateProvider and delegates virtualization, scroll, and layout orchestration to a large set of single-purpose modules under src/core (calculateItemsInView, updateScroll, scrollToIndex, viewability, bootstrapInitialScroll, doMaintainScrollAtEnd) that all operate on a shared ctx object rather than component props or React state. That shared state lives in src/state/state.tsx, a small Legend State-inspired store built on useSyncExternalStore with peek$/set$/listen$ primitives, letting scroll position, container sizes, and viewability update without forcing a full React re-render of the list. Rendering and recycling are handled separately in src/components/Container*.tsx and src/utils/containerPool.ts, which pool and reuse mounted item containers when recycleItems is enabled. Platform divergence (React DOM vs React Native, old vs new architecture) is resolved through .native.ts/.web.ts file-suffix overrides rather than runtime Platform.OS branching in the hot path, so the core orchestration logic in src/core and src/utils stays platform-agnostic; changing the shared ctx/state contract would ripple through nearly every file in components and core since both layers read and write it directly.
Tech Stack
Legend List ships as pure TypeScript with a single runtime dependency (use-sync-external-store) and a peer dependency on react; React Native, Reanimated, and react-native-keyboard-controller integrations are optional peer dependencies activated only through their own subpath entrypoints. The build pipeline uses tsup (configured in tsup.config.ts) with custom prebuild.ts/postbuild.ts scripts to produce separate react, react-native, section-list, animated, reanimated, and keyboard bundles as distinct package exports, and Bun is the primary task runner for installs, builds, and tests. Example consumers are maintained directly in the repo — an Expo app (example/, plus an old-architecture variant) and a Vite-based web playground (example-web/) — giving contributors a way to exercise both native and web code paths against the same source.
Code Quality
The repo carries an extensive Jest/React Native Testing Library suite under __tests__ that mirrors the src layout (components, core, hooks, integrations, platform, section-list, state, utils), with contributor guidance in AGENTS.md explicitly requiring regression tests for any change touching scroll adjustment, bootstrapping, or measurement logic. Biome enforces formatting and linting across src, tests, and the example apps, and the codebase is written in strict TypeScript with dedicated typed-wrapper helpers (typedForwardRef, typedMemo in types.internal.ts) to keep generic list-item types sound through forwardRef/memo. The one gap is automation: there is no GitHub Actions workflow in .github/workflows (only a FUNDING.yml), so lint/test/build verification currently relies on contributor discipline rather than an enforced CI gate.
API Design
The public API is deliberately shaped to be a near drop-in swap for FlatList/FlashList — same data, renderItem, keyExtractor, header/footer, and viewability props — so migrating an existing list usually means changing an import and opting into a couple of new props. Performance-sensitive behaviors are explicit and opt-in rather than implicit: recycleItems triggers a dev-mode warning when left unset precisely because it changes component lifecycle semantics, and higher-level conveniences like maintainScrollAtEnd, maintainVisibleContentPosition, and alignItemsAtEnd accept both a boolean shorthand and a detailed options object for finer control. An imperative ref (createImperativeHandle) exposes scrollToIndex/scrollToOffset/scrollToEnd, and generics on LegendListRenderItemProps<T> keep item types checked end-to-end, while the linked documentation site (legendapp.com/open-source/list) covers the fuller prop surface beyond the README.
Used by 2 apps in this directory
Notesnook
Note Taking · File Storage · Security
End-to-end encrypted, open-source note-taking where your data stays yours — even from the server.
superset
AI Code Assistants · AI Development
Orchestrate an army of AI coding agents—Claude Code, Codex, Gemini CLI, and more—running simultaneously in isolated git worktrees from a single Electron desktop app.