# Rokkit LazyTree Component > Tree with on-demand lazy-loaded children and optional root-level pagination. LazyTree extends Tree with async child loading. Nodes with `children: true` (a boolean sentinel) fetch their children via `onlazyload` when expanded. A loading spinner appears during fetch. Set `hasMore` to show a "Load More" button for root-level pagination. ## Quick Start ```svelte ``` ## How it Works 1. Set `children: true` on nodes that should load children on demand 2. Provide `onlazyload` — an async function that receives the node's raw item and returns child items 3. When the user expands the node, a loading spinner appears while children are fetched 4. Returned children can themselves have `children: true` for progressive lazy loading 5. Once loaded, children are cached — subsequent expand/collapse uses the cached data ## Root-Level Pagination (Load More) Set `hasMore={true}` to show a "Load More" button at the bottom of the tree. When clicked, `onlazyload()` is called with no arguments. The callback should return the next batch of root items. Set `hasMore={false}` when all items are loaded. ```svelte ``` ## Props | Prop | Type | Default | Description | |------|------|---------|-------------| | `items` | `unknown[]` | `[]` | Hierarchical data array | | `fields` | `Record` | `{}` | Field mapping | | `value` | `unknown` | — | Selected value | | `size` | `'sm'\|'md'\|'lg'` | `'md'` | Size variant | | `lineStyle` | `'none'\|'solid'\|'dashed'\|'dotted'` | `'solid'` | Tree line connector style | | `icons` | `{ opened?: string; closed?: string }` | defaults | Override expand/collapse icons | | `onselect` | `(value, proxy) => void` | — | Selection callback | | `onlazyload` | `(item?) => Promise` | — | Async callback to fetch children (with item) or next root batch (without args) | | `hasMore` | `boolean` | `false` | Show "Load More" button for root pagination | | `class` | `string` | `''` | Additional CSS classes | ## Sentinel Pattern ```javascript // children: true → lazy (will call onlazyload on expand) // children: [...] → pre-loaded children // no children key → leaf node const items = [ { label: 'Lazy folder', value: 'lazy', children: true }, { label: 'Pre-loaded', value: 'pre', children: [{ label: 'Child', value: 'c1' }] }, { label: 'Leaf file', value: 'leaf' } ] ``` ## Loading States During async fetch: - Node gets `data-tree-loading` attribute - Node gets `aria-busy="true"` - Toggle button shows a spinner (`data-tree-spinner`) instead of the expand icon ## Keyboard Navigation Same as Tree: | Key | Action | |-----|--------| | `ArrowUp/Down` | Move between visible nodes | | `ArrowRight` | Expand node (triggers lazy load if needed) | | `ArrowLeft` | Collapse node / go to parent | | `Home/End` | First/last visible node | | `Enter/Space` | Select focused node | ## Data Attributes | Attribute | Description | |-----------|-------------| | `data-tree` | Root element | | `data-tree-node` | Tree node | | `data-tree-loading` | Node currently loading children | | `data-tree-spinner` | Loading spinner element | | `data-tree-toggle-btn` | Expand/collapse button | | `data-tree-item-content` | Clickable item content | | `data-tree-load-more` | "Load More" button | | `data-active` | Active/current node | ## Import ```javascript import { LazyTree } from '@rokkit/ui' ``` ## TypeScript Types ```typescript interface LazyTreeProps { items?: unknown[] fields?: Record value?: unknown size?: 'sm' | 'md' | 'lg' lineStyle?: 'none' | 'solid' | 'dashed' | 'dotted' icons?: { opened?: string; closed?: string } onselect?: (value: unknown, proxy: ProxyItem) => void onlazyload?: (item?: unknown) => Promise hasMore?: boolean class?: string } ``` ## Related Components - [Tree](/llms/components/tree.txt) — tree without lazy loading - [List](/llms/components/list.txt) — flat list with collapsible groups