or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

collections.mddesign-tokens.mddom-aria.mddrag-drop.mdevents.mdindex.mdinput-handling.mdlabelable.mdrefs.mdselection.mdstyling.md

collections.mddocs/

0

# Collections and Data Structures

1

2

Generic collection interfaces supporting lists, grids, trees, and other data structures with keyboard navigation, sorting, expansion, loading states, and layout management.

3

4

## Capabilities

5

6

### Core Collection Interface

7

8

The fundamental collection interface that provides iteration and key-based access to items.

9

10

```typescript { .api }

11

/**

12

* A generic interface to access a readonly sequential collection of unique keyed items

13

* @template T The type of items in the collection

14

*/

15

interface Collection<T> extends Iterable<T> {

16

/** The number of items in the collection */

17

readonly size: number;

18

19

/** Iterate over all keys in the collection */

20

getKeys(): Iterable<Key>;

21

22

/** Get an item by its key */

23

getItem(key: Key): T | null;

24

25

/** Get an item by the index of its key */

26

at(idx: number): T | null;

27

28

/** Get the key that comes before the given key in the collection */

29

getKeyBefore(key: Key): Key | null;

30

31

/** Get the key that comes after the given key in the collection */

32

getKeyAfter(key: Key): Key | null;

33

34

/** Get the first key in the collection */

35

getFirstKey(): Key | null;

36

37

/** Get the last key in the collection */

38

getLastKey(): Key | null;

39

40

/** Iterate over the child items of the given key */

41

getChildren?(key: Key): Iterable<T>;

42

43

/** Returns a string representation of the item's contents */

44

getTextValue?(key: Key): string;

45

46

/** Filters the collection using the given function */

47

filter?(filterFn: (nodeValue: string, node: T) => boolean): Collection<T>;

48

}

49

```

50

51

### Collection Nodes

52

53

Nodes represent individual items within a collection with metadata and hierarchy support.

54

55

```typescript { .api }

56

/**

57

* Represents a node in a collection

58

* @template T The type of the node's value

59

*/

60

interface Node<T> {

61

/** The type of item this node represents */

62

type: string;

63

/** A unique key for the node */

64

key: Key;

65

/** The object value the node was created from */

66

value: T | null;

67

/** The level of depth this node is at in the hierarchy */

68

level: number;

69

/** Whether this item has children, even if not loaded yet */

70

hasChildNodes: boolean;

71

/**

72

* The loaded children of this node

73

* @deprecated Use collection.getChildren(node.key) instead

74

*/

75

childNodes: Iterable<Node<T>>;

76

/** The rendered contents of this node (e.g. JSX) */

77

rendered: ReactNode;

78

/** A string value for this node, used for features like typeahead */

79

textValue: string;

80

/** An accessibility label for this node */

81

"aria-label"?: string;

82

/** The index of this node within its parent */

83

index: number;

84

/** A function that should be called to wrap the rendered node */

85

wrapper?: (element: ReactElement) => ReactElement;

86

/** The key of the parent node */

87

parentKey?: Key | null;

88

/** The key of the node before this node */

89

prevKey?: Key | null;

90

/** The key of the node after this node */

91

nextKey?: Key | null;

92

/** Additional properties specific to a particular node type */

93

props?: any;

94

/** @private */

95

shouldInvalidate?: (context: any) => boolean;

96

/** A function that renders this node to a React Element in the DOM */

97

render?: (node: Node<any>) => ReactElement;

98

}

99

```

100

101

### Items and Sections

102

103

Building blocks for creating collection content with React elements.

104

105

```typescript { .api }

106

/**

107

* Properties for collection items

108

* @template T The type of the item data

109

*/

110

interface ItemProps<T> extends LinkDOMProps {

111

/** Rendered contents of the item or child items */

112

children: ReactNode;

113

/** Rendered contents of the item if children contains child items */

114

title?: ReactNode;

115

/** A string representation of the item's contents, used for features like typeahead */

116

textValue?: string;

117

/** An accessibility label for this item */

118

"aria-label"?: string;

119

/** A list of child item objects. Used for dynamic collections */

120

childItems?: Iterable<T>;

121

/** Whether this item has children, even if not loaded yet */

122

hasChildItems?: boolean;

123

}

124

125

/**

126

* Properties for collection sections

127

* @template T The type of the item data

128

*/

129

interface SectionProps<T> {

130

/** Rendered contents of the section, e.g. a header */

131

title?: ReactNode;

132

/** An accessibility label for the section */

133

"aria-label"?: string;

134

/** Static child items or a function to render children */

135

children: ItemElement<T> | ItemElement<T>[] | ItemRenderer<T>;

136

/** Item objects in the section */

137

items?: Iterable<T>;

138

}

139

140

/** React element representing an item */

141

type ItemElement<T> = ReactElement<ItemProps<T>> | null;

142

143

/** Function that renders an item */

144

type ItemRenderer<T> = (item: T) => ItemElement<T>;

145

146

/** React element representing a section */

147

type SectionElement<T> = ReactElement<SectionProps<T>> | null;

148

149

/** Union of collection elements */

150

type CollectionElement<T> = SectionElement<T> | ItemElement<T>;

151

152

/** Children content for collections */

153

type CollectionChildren<T> = CollectionElement<T> | CollectionElement<T>[] | ((item: T) => CollectionElement<T>);

154

```

155

156

### Collection Base Properties

157

158

Base properties for collections with static and dynamic content support.

159

160

```typescript { .api }

161

/**

162

* Base properties for collections

163

* @template T The type of items in the collection

164

*/

165

interface CollectionBase<T> {

166

/** The contents of the collection */

167

children: CollectionChildren<T>;

168

/** Item objects in the collection */

169

items?: Iterable<T>;

170

/** The item keys that are disabled. These items cannot be selected, focused, or otherwise interacted with */

171

disabledKeys?: Iterable<Key>;

172

}

173

174

/**

175

* Base properties for collection state

176

* @template T The type of items in the collection

177

* @template C The type of the collection

178

*/

179

interface CollectionStateBase<T, C extends Collection<Node<T>> = Collection<Node<T>>> extends Partial<CollectionBase<T>> {

180

/** A pre-constructed collection to use instead of building one from items and children */

181

collection?: C;

182

}

183

```

184

185

### Loading States

186

187

Support for asynchronous collections with loading indicators.

188

189

```typescript { .api }

190

/** Loading states for collections */

191

type LoadingState = "loading" | "sorting" | "loadingMore" | "error" | "idle" | "filtering";

192

193

/**

194

* Properties for collections that support async loading

195

*/

196

interface AsyncLoadable {

197

/** Whether the items are currently loading */

198

isLoading?: boolean;

199

/** Handler that is called when more items should be loaded, e.g. while scrolling near the bottom */

200

onLoadMore?: () => any;

201

}

202

```

203

204

### Expandable Collections

205

206

Support for hierarchical collections with expand/collapse functionality.

207

208

```typescript { .api }

209

/**

210

* Properties for expandable collections (trees)

211

*/

212

interface Expandable {

213

/** The currently expanded keys in the collection (controlled) */

214

expandedKeys?: Iterable<Key>;

215

/** The initial expanded keys in the collection (uncontrolled) */

216

defaultExpandedKeys?: Iterable<Key>;

217

/** Handler that is called when items are expanded or collapsed */

218

onExpandedChange?: (keys: Set<Key>) => any;

219

}

220

```

221

222

### Sortable Collections

223

224

Support for collections with sorting functionality.

225

226

```typescript { .api }

227

/** Sort direction options */

228

type SortDirection = "ascending" | "descending";

229

230

/**

231

* Sort descriptor defining how to sort a collection

232

*/

233

interface SortDescriptor {

234

/** The key of the column to sort by */

235

column: Key;

236

/** The direction to sort by */

237

direction: SortDirection;

238

}

239

240

/**

241

* Properties for sortable collections

242

*/

243

interface Sortable {

244

/** The current sorted column and direction */

245

sortDescriptor?: SortDescriptor;

246

/** Handler that is called when the sorted column or direction changes */

247

onSortChange?: (descriptor: SortDescriptor) => any;

248

}

249

```

250

251

### Keyboard Navigation

252

253

Interfaces for custom keyboard navigation within collections.

254

255

```typescript { .api }

256

/**

257

* Keyboard navigation delegate for custom key handling

258

*/

259

interface KeyboardDelegate {

260

/** Returns the key visually below the given one, or null for none */

261

getKeyBelow?(key: Key): Key | null;

262

263

/** Returns the key visually above the given one, or null for none */

264

getKeyAbove?(key: Key): Key | null;

265

266

/** Returns the key visually to the left of the given one, or null for none */

267

getKeyLeftOf?(key: Key): Key | null;

268

269

/** Returns the key visually to the right of the given one, or null for none */

270

getKeyRightOf?(key: Key): Key | null;

271

272

/** Returns the key visually one page below the given one, or null for none */

273

getKeyPageBelow?(key: Key): Key | null;

274

275

/** Returns the key visually one page above the given one, or null for none */

276

getKeyPageAbove?(key: Key): Key | null;

277

278

/** Returns the first key, or null for none */

279

getFirstKey?(key?: Key | null, global?: boolean): Key | null;

280

281

/** Returns the last key, or null for none */

282

getLastKey?(key?: Key | null, global?: boolean): Key | null;

283

284

/** Returns the next key after fromKey that matches the given search string, or null for none */

285

getKeyForSearch?(search: string, fromKey?: Key | null): Key | null;

286

}

287

```

288

289

### Layout Management

290

291

Interfaces for managing collection layout and virtualization.

292

293

```typescript { .api }

294

/**

295

* Rectangle type for layout calculations

296

*/

297

interface Rect {

298

x: number;

299

y: number;

300

width: number;

301

height: number;

302

}

303

304

/**

305

* Size type for dimensions

306

*/

307

interface Size {

308

width: number;

309

height: number;

310

}

311

312

/**

313

* Layout delegate provides layout information for collection items

314

*/

315

interface LayoutDelegate {

316

/** Returns a rectangle for the item with the given key */

317

getItemRect(key: Key): Rect | null;

318

/** Returns the visible rectangle of the collection */

319

getVisibleRect(): Rect;

320

/** Returns the size of the scrollable content in the collection */

321

getContentSize(): Size;

322

/** Returns a list of keys between from and to */

323

getKeyRange?(from: Key, to: Key): Key[];

324

}

325

```

326

327

**Usage Examples:**

328

329

```typescript

330

import {

331

Collection,

332

Node,

333

CollectionBase,

334

ItemProps,

335

SectionProps,

336

Expandable,

337

Sortable,

338

AsyncLoadable,

339

SortDescriptor,

340

Key

341

} from "@react-types/shared";

342

343

// Basic list component with collection support

344

interface ListProps<T> extends CollectionBase<T>, AsyncLoadable {

345

onAction?: (key: Key) => void;

346

}

347

348

function List<T>({

349

children,

350

items,

351

disabledKeys,

352

isLoading,

353

onLoadMore,

354

onAction

355

}: ListProps<T>) {

356

// In a real implementation, you'd build a collection from children/items

357

// This is a simplified example showing the interface usage

358

359

return (

360

<div role="list">

361

{isLoading && <div>Loading...</div>}

362

{/* Render collection items */}

363

<div>Collection items would be rendered here</div>

364

{onLoadMore && (

365

<button onClick={onLoadMore}>Load More</button>

366

)}

367

</div>

368

);

369

}

370

371

// Tree component with expansion support

372

interface TreeProps<T> extends CollectionBase<T>, Expandable {

373

onAction?: (key: Key) => void;

374

}

375

376

function Tree<T>({

377

children,

378

items,

379

disabledKeys,

380

expandedKeys,

381

defaultExpandedKeys,

382

onExpandedChange,

383

onAction

384

}: TreeProps<T>) {

385

const [expanded, setExpanded] = useState<Set<Key>>(

386

new Set(defaultExpandedKeys || [])

387

);

388

389

const handleToggleExpanded = (key: Key) => {

390

const newExpanded = new Set(expandedKeys || expanded);

391

if (newExpanded.has(key)) {

392

newExpanded.delete(key);

393

} else {

394

newExpanded.add(key);

395

}

396

setExpanded(newExpanded);

397

onExpandedChange?.(newExpanded);

398

};

399

400

return (

401

<div role="tree">

402

{/* Tree implementation would render nodes with expand/collapse controls */}

403

<div>Tree nodes would be rendered here</div>

404

</div>

405

);

406

}

407

408

// Table component with sorting support

409

interface TableProps<T> extends CollectionBase<T>, Sortable {

410

columns: Array<{

411

key: Key;

412

name: string;

413

allowsSorting?: boolean;

414

}>;

415

}

416

417

function Table<T>({

418

children,

419

items,

420

columns,

421

sortDescriptor,

422

onSortChange

423

}: TableProps<T>) {

424

const handleSort = (column: Key) => {

425

const newDescriptor: SortDescriptor = {

426

column,

427

direction:

428

sortDescriptor?.column === column && sortDescriptor.direction === "ascending"

429

? "descending"

430

: "ascending"

431

};

432

onSortChange?.(newDescriptor);

433

};

434

435

return (

436

<table>

437

<thead>

438

<tr>

439

{columns.map(column => (

440

<th

441

key={column.key}

442

onClick={() => column.allowsSorting && handleSort(column.key)}

443

style={{

444

cursor: column.allowsSorting ? "pointer" : "default"

445

}}

446

>

447

{column.name}

448

{sortDescriptor?.column === column.key && (

449

<span>{sortDescriptor.direction === "ascending" ? " ↑" : " ↓"}</span>

450

)}

451

</th>

452

))}

453

</tr>

454

</thead>

455

<tbody>

456

{/* Table rows would be rendered here */}

457

</tbody>

458

</table>

459

);

460

}

461

462

// Usage with static content

463

function StaticListExample() {

464

return (

465

<List>

466

<Item key="1">First item</Item>

467

<Item key="2">Second item</Item>

468

<Section title="Group A">

469

<Item key="3">Third item</Item>

470

<Item key="4">Fourth item</Item>

471

</Section>

472

</List>

473

);

474

}

475

476

// Usage with dynamic content

477

function DynamicListExample() {

478

const items = [

479

{ id: 1, name: "Apple", category: "Fruit" },

480

{ id: 2, name: "Carrot", category: "Vegetable" },

481

{ id: 3, name: "Banana", category: "Fruit" }

482

];

483

484

return (

485

<List items={items} disabledKeys={[2]}>

486

{(item) => (

487

<Item key={item.id} textValue={item.name}>

488

{item.name} ({item.category})

489

</Item>

490

)}

491

</List>

492

);

493

}

494

495

// Tree with expansion

496

function TreeExample() {

497

const treeData = [

498

{

499

id: 1,

500

name: "Documents",

501

children: [

502

{ id: 2, name: "Resume.pdf" },

503

{ id: 3, name: "Cover Letter.doc" }

504

]

505

},

506

{

507

id: 4,

508

name: "Images",

509

children: [

510

{ id: 5, name: "Photo1.jpg" },

511

{ id: 6, name: "Photo2.png" }

512

]

513

}

514

];

515

516

return (

517

<Tree

518

items={treeData}

519

defaultExpandedKeys={[1]}

520

onExpandedChange={(keys) => console.log("Expanded keys:", keys)}

521

>

522

{(item) => (

523

<Item

524

key={item.id}

525

hasChildItems={!!item.children?.length}

526

childItems={item.children}

527

>

528

{item.name}

529

</Item>

530

)}

531

</Tree>

532

);

533

}

534

535

// Sortable table

536

function SortableTableExample() {

537

const data = [

538

{ id: 1, name: "Alice", age: 30, department: "Engineering" },

539

{ id: 2, name: "Bob", age: 25, department: "Design" },

540

{ id: 3, name: "Carol", age: 35, department: "Marketing" }

541

];

542

543

const columns = [

544

{ key: "name", name: "Name", allowsSorting: true },

545

{ key: "age", name: "Age", allowsSorting: true },

546

{ key: "department", name: "Department", allowsSorting: false }

547

];

548

549

const [sortDescriptor, setSortDescriptor] = useState<SortDescriptor>({

550

column: "name",

551

direction: "ascending"

552

});

553

554

return (

555

<Table

556

items={data}

557

columns={columns}

558

sortDescriptor={sortDescriptor}

559

onSortChange={setSortDescriptor}

560

>

561

{(item) => (

562

<Row key={item.id}>

563

<Cell>{item.name}</Cell>

564

<Cell>{item.age}</Cell>

565

<Cell>{item.department}</Cell>

566

</Row>

567

)}

568

</Table>

569

);

570

}

571

```