or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

accessibility.mdanimation.mdcore-utilities.mdform-controls.mdhooks.mdindex.mdinteractive-components.mdlayout-components.mdlist-components.mdmedia-components.mdplatform-apis.mdstylesheet.mdsystem-integration.mdtext-input.md

list-components.mddocs/

0

# List Components

1

2

High-performance list and virtualization components for handling large datasets efficiently with comprehensive scroll management, pull-to-refresh, and advanced rendering optimizations.

3

4

## FlatList

5

6

A performant list component for rendering simple, flat lists with virtualization, cross-platform support, and extensive customization options.

7

8

```javascript { .api }

9

const FlatList: React.ComponentType<FlatListProps<ItemT>>;

10

```

11

12

**Required Props:**

13

- `data` - Array of items to render

14

- `renderItem` - Function to render each item: `({item, index, separators}) => React.Element`

15

16

**Core Props:**

17

- `keyExtractor` - Extract unique key for each item: `(item, index) => string`

18

- `extraData` - Additional data to trigger re-renders when changed

19

- `horizontal` - Render items horizontally instead of vertically

20

- `numColumns` - Number of columns for grid layout (vertical only)

21

- `initialNumToRender` - Items to render in initial batch

22

- `initialScrollIndex` - Start at specific index (requires `getItemLayout`)

23

- `inverted` - Reverse scroll direction

24

- `removeClippedSubviews` - Optimize performance by removing off-screen views

25

26

**Layout Optimization:**

27

- `getItemLayout` - Provide item dimensions for performance: `(data, index) => {length, offset, index}`

28

- `columnWrapperStyle` - Style for multi-column rows

29

- `ListHeaderComponent` - Component at the top of the list

30

- `ListFooterComponent` - Component at the bottom of the list

31

- `ListEmptyComponent` - Component when list is empty

32

- `ItemSeparatorComponent` - Component between items

33

34

**Scroll Props:**

35

- `onScroll` - Scroll event handler

36

- `onScrollToIndexFailed` - Called when scrollToIndex fails

37

- `scrollEventThrottle` - Scroll event throttling

38

- `showsHorizontalScrollIndicator` - Show horizontal scroll bar

39

- `showsVerticalScrollIndicator` - Show vertical scroll bar

40

41

**Viewability:**

42

- `onViewableItemsChanged` - Called when viewable items change

43

- `viewabilityConfig` - Configuration for viewability callbacks

44

- `viewabilityConfigCallbackPairs` - Multiple viewability configs

45

46

**Methods:**

47

- `scrollToEnd({animated?})` - Scroll to end of list

48

- `scrollToIndex({index, animated?, viewPosition?, viewOffset?})` - Scroll to specific index

49

- `scrollToItem({item, animated?, viewPosition?, viewOffset?})` - Scroll to specific item

50

- `scrollToOffset({offset, animated?})` - Scroll to pixel offset

51

- `recordInteraction()` - Trigger viewability calculations

52

- `flashScrollIndicators()` - Show scroll indicators briefly

53

54

**Usage:**

55

```javascript

56

import { FlatList, Text, View, TouchableOpacity } from "react-native-web";

57

58

// Basic list

59

function BasicList() {

60

const data = [

61

{ id: '1', title: 'First Item' },

62

{ id: '2', title: 'Second Item' },

63

{ id: '3', title: 'Third Item' },

64

];

65

66

const renderItem = ({ item, index }) => (

67

<View style={{

68

padding: 16,

69

borderBottomWidth: 1,

70

borderBottomColor: '#eee'

71

}}>

72

<Text>{item.title}</Text>

73

</View>

74

);

75

76

return (

77

<FlatList

78

data={data}

79

renderItem={renderItem}

80

keyExtractor={item => item.id}

81

/>

82

);

83

}

84

85

// Advanced list with optimizations

86

function OptimizedList() {

87

const [data, setData] = useState(generateLargeDataset(1000));

88

const [refreshing, setRefreshing] = useState(false);

89

90

const getItemLayout = (data, index) => ({

91

length: 80, // Item height

92

offset: 80 * index,

93

index,

94

});

95

96

const renderItem = ({ item, index }) => (

97

<TouchableOpacity

98

style={styles.item}

99

onPress={() => handleItemPress(item)}

100

>

101

<Text style={styles.title}>{item.title}</Text>

102

<Text style={styles.subtitle}>{item.subtitle}</Text>

103

</TouchableOpacity>

104

);

105

106

const renderSeparator = () => (

107

<View style={{ height: 1, backgroundColor: '#e0e0e0' }} />

108

);

109

110

const renderHeader = () => (

111

<View style={styles.header}>

112

<Text style={styles.headerText}>My List</Text>

113

</View>

114

);

115

116

const renderFooter = () => (

117

<View style={styles.footer}>

118

<Text>End of list</Text>

119

</View>

120

);

121

122

const renderEmpty = () => (

123

<View style={styles.empty}>

124

<Text>No items found</Text>

125

</View>

126

);

127

128

const onRefresh = async () => {

129

setRefreshing(true);

130

const newData = await fetchFreshData();

131

setData(newData);

132

setRefreshing(false);

133

};

134

135

return (

136

<FlatList

137

data={data}

138

renderItem={renderItem}

139

keyExtractor={item => item.id}

140

getItemLayout={getItemLayout}

141

ItemSeparatorComponent={renderSeparator}

142

ListHeaderComponent={renderHeader}

143

ListFooterComponent={renderFooter}

144

ListEmptyComponent={renderEmpty}

145

initialNumToRender={10}

146

maxToRenderPerBatch={5}

147

windowSize={10}

148

removeClippedSubviews={true}

149

refreshControl={

150

<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />

151

}

152

onViewableItemsChanged={({ viewableItems }) => {

153

console.log('Visible items:', viewableItems.map(v => v.key));

154

}}

155

viewabilityConfig={{

156

itemVisiblePercentThreshold: 50

157

}}

158

/>

159

);

160

}

161

162

// Grid layout

163

function GridList() {

164

const data = Array.from({ length: 100 }, (_, i) => ({

165

id: i.toString(),

166

title: `Item ${i + 1}`,

167

color: colors[i % colors.length]

168

}));

169

170

const renderGridItem = ({ item }) => (

171

<View style={[styles.gridItem, { backgroundColor: item.color }]}>

172

<Text style={styles.gridText}>{item.title}</Text>

173

</View>

174

);

175

176

return (

177

<FlatList

178

data={data}

179

renderItem={renderGridItem}

180

keyExtractor={item => item.id}

181

numColumns={2}

182

columnWrapperStyle={styles.gridRow}

183

contentContainerStyle={styles.gridContainer}

184

/>

185

);

186

}

187

188

// Horizontal list

189

function HorizontalList() {

190

const categories = [

191

{ id: '1', name: 'Electronics', image: 'electronics.jpg' },

192

{ id: '2', name: 'Clothing', image: 'clothing.jpg' },

193

{ id: '3', name: 'Books', image: 'books.jpg' },

194

];

195

196

const renderCategory = ({ item }) => (

197

<TouchableOpacity style={styles.categoryCard}>

198

<Image source={{ uri: item.image }} style={styles.categoryImage} />

199

<Text style={styles.categoryName}>{item.name}</Text>

200

</TouchableOpacity>

201

);

202

203

return (

204

<FlatList

205

data={categories}

206

renderItem={renderCategory}

207

keyExtractor={item => item.id}

208

horizontal={true}

209

showsHorizontalScrollIndicator={false}

210

contentContainerStyle={styles.horizontalList}

211

/>

212

);

213

}

214

```

215

216

## SectionList

217

218

A high-performance list component for rendering sectioned data with headers, similar to iOS's UITableView.

219

220

```javascript { .api }

221

const SectionList: React.ComponentType<SectionListProps<ItemT>>;

222

```

223

224

**Required Props:**

225

- `sections` - Array of section objects with `data` property

226

- `renderItem` - Function to render each item

227

- `renderSectionHeader` - Function to render section headers

228

229

**Section Object:**

230

```javascript

231

{

232

title: string,

233

data: Array<ItemT>,

234

key?: string, // Optional, will use index if not provided

235

// Any additional custom properties

236

}

237

```

238

239

**Props:**

240

- `keyExtractor` - Extract key for items

241

- `renderSectionFooter` - Render section footers

242

- `SectionSeparatorComponent` - Component between sections

243

- `ItemSeparatorComponent` - Component between items

244

- `stickySectionHeadersEnabled` - Make headers stick to top

245

- `onScrollToIndexFailed` - Handle scroll failures

246

247

**Usage:**

248

```javascript

249

import { SectionList, Text, View } from "react-native-web";

250

251

function ContactsList() {

252

const sections = [

253

{

254

title: 'A',

255

data: ['Alice', 'Andrew', 'Anna'],

256

},

257

{

258

title: 'B',

259

data: ['Bob', 'Betty', 'Brian'],

260

},

261

{

262

title: 'C',

263

data: ['Charlie', 'Catherine', 'Chris'],

264

},

265

];

266

267

const renderItem = ({ item, section, index }) => (

268

<TouchableOpacity style={styles.contactItem}>

269

<Text style={styles.contactName}>{item}</Text>

270

<Text style={styles.contactSection}>Section: {section.title}</Text>

271

</TouchableOpacity>

272

);

273

274

const renderSectionHeader = ({ section: { title } }) => (

275

<View style={styles.sectionHeader}>

276

<Text style={styles.sectionHeaderText}>{title}</Text>

277

</View>

278

);

279

280

const renderSectionFooter = ({ section }) => (

281

<View style={styles.sectionFooter}>

282

<Text>{section.data.length} contacts</Text>

283

</View>

284

);

285

286

return (

287

<SectionList

288

sections={sections}

289

renderItem={renderItem}

290

renderSectionHeader={renderSectionHeader}

291

renderSectionFooter={renderSectionFooter}

292

keyExtractor={(item, index) => item + index}

293

stickySectionHeadersEnabled={true}

294

ItemSeparatorComponent={() => (

295

<View style={{ height: 1, backgroundColor: '#ccc' }} />

296

)}

297

SectionSeparatorComponent={() => (

298

<View style={{ height: 10, backgroundColor: '#f0f0f0' }} />

299

)}

300

/>

301

);

302

}

303

304

// Advanced sectioned list

305

function GroupedDataList() {

306

const [sections, setSections] = useState([]);

307

308

const groupedSections = useMemo(() => {

309

return data.reduce((acc, item) => {

310

const category = item.category;

311

const existingSection = acc.find(section => section.title === category);

312

313

if (existingSection) {

314

existingSection.data.push(item);

315

} else {

316

acc.push({

317

title: category,

318

data: [item],

319

key: category.toLowerCase()

320

});

321

}

322

323

return acc;

324

}, []);

325

}, [data]);

326

327

const renderItem = ({ item, index, section }) => (

328

<View style={styles.listItem}>

329

<Text style={styles.itemTitle}>{item.title}</Text>

330

<Text style={styles.itemPrice}>${item.price}</Text>

331

</View>

332

);

333

334

const renderSectionHeader = ({ section }) => (

335

<View style={[

336

styles.sectionHeader,

337

{ backgroundColor: section.color || '#f5f5f5' }

338

]}>

339

<Text style={styles.sectionTitle}>{section.title}</Text>

340

<Text style={styles.sectionCount}>

341

{section.data.length} items

342

</Text>

343

</View>

344

);

345

346

return (

347

<SectionList

348

sections={groupedSections}

349

renderItem={renderItem}

350

renderSectionHeader={renderSectionHeader}

351

keyExtractor={(item) => item.id}

352

stickySectionHeadersEnabled={true}

353

/>

354

);

355

}

356

```

357

358

## VirtualizedList

359

360

The base component that FlatList and SectionList are built on, providing maximum flexibility for custom list implementations.

361

362

```javascript { .api }

363

const VirtualizedList: React.ComponentType<VirtualizedListProps>;

364

```

365

366

**Required Props:**

367

- `data` - Data source (can be any type)

368

- `getItem` - Function to get item by index: `(data, index) => ItemT`

369

- `getItemCount` - Function to get total count: `(data) => number`

370

- `renderItem` - Render function for items

371

372

**Advanced Props:**

373

- `CellRendererComponent` - Custom cell renderer

374

- `ListHeaderComponent` - Header component

375

- `ListFooterComponent` - Footer component

376

- `debug` - Enable debug mode

377

- `disableVirtualization` - Disable virtualization for debugging

378

379

**Usage:**

380

```javascript

381

// Custom data source example

382

function CustomVirtualizedList() {

383

// Custom data structure (not an array)

384

const customData = {

385

items: new Map([

386

['key1', { title: 'Item 1', value: 100 }],

387

['key2', { title: 'Item 2', value: 200 }],

388

['key3', { title: 'Item 3', value: 300 }],

389

]),

390

order: ['key1', 'key2', 'key3']

391

};

392

393

const getItem = (data, index) => {

394

const key = data.order[index];

395

return data.items.get(key);

396

};

397

398

const getItemCount = (data) => data.order.length;

399

400

const renderItem = ({ item, index }) => (

401

<View style={styles.customItem}>

402

<Text>{item.title}: {item.value}</Text>

403

</View>

404

);

405

406

return (

407

<VirtualizedList

408

data={customData}

409

initialNumToRender={4}

410

renderItem={renderItem}

411

keyExtractor={(item, index) => customData.order[index]}

412

getItemCount={getItemCount}

413

getItem={getItem}

414

/>

415

);

416

}

417

```

418

419

## RefreshControl

420

421

A component for adding pull-to-refresh functionality to scrollable components.

422

423

```javascript { .api }

424

const RefreshControl: React.ComponentType<RefreshControlProps>;

425

```

426

427

**Props:**

428

- `refreshing` - Whether refresh is in progress (required)

429

- `onRefresh` - Callback when refresh is triggered

430

- `colors` - Array of colors for refresh indicator (Android)

431

- `tintColor` - Color of refresh indicator (iOS)

432

- `title` - Title text during refresh (iOS)

433

- `titleColor` - Title text color (iOS)

434

- `progressBackgroundColor` - Progress background color (Android)

435

- `progressViewOffset` - Progress view offset (Android)

436

- `size` - Size of refresh indicator (Android)

437

- `enabled` - Whether refresh is enabled

438

439

**Usage:**

440

```javascript

441

import { ScrollView, RefreshControl, FlatList } from "react-native-web";

442

443

// With ScrollView

444

function RefreshableScrollView() {

445

const [refreshing, setRefreshing] = useState(false);

446

447

const onRefresh = React.useCallback(async () => {

448

setRefreshing(true);

449

try {

450

await fetchNewData();

451

} finally {

452

setRefreshing(false);

453

}

454

}, []);

455

456

return (

457

<ScrollView

458

refreshControl={

459

<RefreshControl

460

refreshing={refreshing}

461

onRefresh={onRefresh}

462

tintColor="#007AFF"

463

title="Pull to refresh"

464

titleColor="#007AFF"

465

colors={['#007AFF', '#4CD964']}

466

/>

467

}

468

>

469

{/* Content */}

470

</ScrollView>

471

);

472

}

473

474

// With FlatList

475

function RefreshableList() {

476

const [data, setData] = useState([]);

477

const [refreshing, setRefreshing] = useState(false);

478

479

const loadData = async () => {

480

const newData = await api.fetchItems();

481

setData(newData);

482

};

483

484

const onRefresh = async () => {

485

setRefreshing(true);

486

await loadData();

487

setRefreshing(false);

488

};

489

490

return (

491

<FlatList

492

data={data}

493

renderItem={renderItem}

494

keyExtractor={item => item.id}

495

refreshControl={

496

<RefreshControl

497

refreshing={refreshing}

498

onRefresh={onRefresh}

499

colors={['#ff0000', '#00ff00', '#0000ff']}

500

progressBackgroundColor="#ffffff"

501

/>

502

}

503

/>

504

);

505

}

506

```

507

508

## Performance Optimization Tips

509

510

```javascript

511

// 1. Use getItemLayout for fixed-size items

512

const getItemLayout = (data, index) => ({

513

length: ITEM_HEIGHT,

514

offset: ITEM_HEIGHT * index,

515

index,

516

});

517

518

// 2. Optimize renderItem with React.memo

519

const ListItem = React.memo(({ item, onPress }) => (

520

<TouchableOpacity onPress={() => onPress(item.id)}>

521

<Text>{item.title}</Text>

522

</TouchableOpacity>

523

));

524

525

// 3. Use keyExtractor effectively

526

const keyExtractor = (item) => item.id.toString();

527

528

// 4. Configure window size and batch rendering

529

<FlatList

530

windowSize={10} // Items to keep in memory

531

initialNumToRender={10} // Items in initial batch

532

maxToRenderPerBatch={5} // Items per batch

533

removeClippedSubviews={true} // Remove off-screen views

534

/>

535

536

// 5. Avoid inline functions and objects

537

const styles = StyleSheet.create({ /* ... */ });

538

const renderItem = useCallback(({ item }) => (

539

<ListItem item={item} style={styles.item} />

540

), []);

541

```

542

543

## Types

544

545

```javascript { .api }

546

interface FlatListProps<ItemT> extends VirtualizedListProps {

547

data: ItemT[] | null | undefined;

548

renderItem: (info: {item: ItemT, index: number, separators: Separators}) => React.ReactElement | null;

549

keyExtractor?: (item: ItemT, index: number) => string;

550

551

// Layout

552

horizontal?: boolean;

553

numColumns?: number;

554

columnWrapperStyle?: ViewStyle;

555

getItemLayout?: (data: ItemT[] | null | undefined, index: number) => {length: number, offset: number, index: number};

556

557

// Performance

558

initialNumToRender?: number;

559

maxToRenderPerBatch?: number;

560

windowSize?: number;

561

removeClippedSubviews?: boolean;

562

563

// Components

564

ListHeaderComponent?: React.ComponentType | React.ReactElement;

565

ListFooterComponent?: React.ComponentType | React.ReactElement;

566

ListEmptyComponent?: React.ComponentType | React.ReactElement;

567

ItemSeparatorComponent?: React.ComponentType;

568

569

// Viewability

570

onViewableItemsChanged?: (info: {viewableItems: ViewToken[], changed: ViewToken[]}) => void;

571

viewabilityConfig?: ViewabilityConfig;

572

573

// Other

574

extraData?: any;

575

inverted?: boolean;

576

refreshControl?: React.ReactElement;

577

}

578

579

interface SectionListProps<ItemT> extends VirtualizedListProps {

580

sections: SectionListData<ItemT>[];

581

renderItem: (info: {item: ItemT, index: number, section: SectionListData<ItemT>, separators: Separators}) => React.ReactElement | null;

582

renderSectionHeader?: (info: {section: SectionListData<ItemT>}) => React.ReactElement | null;

583

renderSectionFooter?: (info: {section: SectionListData<ItemT>}) => React.ReactElement | null;

584

keyExtractor?: (item: ItemT, index: number) => string;

585

stickySectionHeadersEnabled?: boolean;

586

SectionSeparatorComponent?: React.ComponentType;

587

}

588

589

interface SectionListData<ItemT> {

590

data: ItemT[];

591

key?: string;

592

title?: string;

593

[key: string]: any;

594

}

595

596

interface RefreshControlProps extends ViewProps {

597

refreshing: boolean;

598

onRefresh?: () => void;

599

colors?: string[];

600

enabled?: boolean;

601

progressBackgroundColor?: ColorValue;

602

progressViewOffset?: number;

603

size?: 0 | 1;

604

tintColor?: ColorValue;

605

title?: string;

606

titleColor?: ColorValue;

607

}

608

609

interface ViewToken {

610

item: any;

611

key: string;

612

index: number | null;

613

isViewable: boolean;

614

section?: any;

615

}

616

617

interface ViewabilityConfig {

618

minimumViewTime?: number;

619

viewAreaCoveragePercentThreshold?: number;

620

itemVisiblePercentThreshold?: number;

621

waitForInteraction?: boolean;

622

}

623

```