# List List component with custom item rendering, headers, and reactive data binding. ## Tag `List` ## Props | Prop | Type | Default | Description | | :------- | :-------------------------- | :------------------- | :------------------------------------------ | | `items` | `Array \| Signal` | `[]` | Data array to display | | `header` | `string \| VNode \| Signal` | `-` | Optional header content | | `render` | `function(item, index)` | Required | Custom render function for each item | | `keyFn` | `function(item, index)` | `(item, idx) => idx` | Unique key function for items | | `class` | `string` | `''` | Additional CSS classes (DaisyUI + Tailwind) | ## Styling List supports all **daisyUI List classes**: | Category | Keywords | Description | | :--------- | :------------ | :------------------------- | | Base | `list` | Base list styling | | Variant | `list-row` | Row styling for list items | | Background | `bg-base-100` | Background color | > For further details, check the [daisyUI List Documentation](https://daisyui.com/components/list) โ€“ Full reference for CSS classes. ## Live Examples ### Basic List

Live Demo

```javascript const BasicDemo = () => { const items = ["Apple", "Banana", "Orange", "Grape", "Mango"]; return List({ items: items, render: (item) => Div({ class: "p-3 hover:bg-base-200 transition-colors" }, [ Span({ class: "font-medium" }, item), ]), }); }; Mount(BasicDemo, "#demo-basic"); ``` ### With Header

Live Demo

```javascript const HeaderDemo = () => { const users = [ { name: "John Doe", email: "john@example.com", status: "active" }, { name: "Jane Smith", email: "jane@example.com", status: "inactive" }, { name: "Bob Johnson", email: "bob@example.com", status: "active" }, ]; return List({ items: users, header: Div( { class: "p-3 bg-primary/10 font-bold border-b border-base-300" }, "Active Users", ), render: (user) => Div({ class: "p-3 border-b border-base-300 hover:bg-base-200" }, [ Div({ class: "font-medium" }, user.name), Div({ class: "text-sm opacity-70" }, user.email), Span( { class: `badge badge-sm ${user.status === "active" ? "badge-success" : "badge-ghost"} mt-1`, }, user.status, ), ]), }); }; Mount(HeaderDemo, "#demo-header"); ``` ### With Icons

Live Demo

```javascript const IconsDemo = () => { const settings = [ { icon: "๐Ÿ”Š", label: "Sound", description: "Adjust volume and notifications", }, { icon: "๐ŸŒ™", label: "Display", description: "Brightness and dark mode" }, { icon: "๐Ÿ”’", label: "Privacy", description: "Security settings" }, { icon: "๐ŸŒ", label: "Network", description: "WiFi and connections" }, ]; return List({ items: settings, render: (item) => Div( { class: "flex gap-3 p-3 hover:bg-base-200 transition-colors cursor-pointer", }, [ Div({ class: "text-2xl" }, item.icon), Div({ class: "flex-1" }, [ Div({ class: "font-medium" }, item.label), Div({ class: "text-sm opacity-60" }, item.description), ]), Span({ class: "opacity-40" }, "โ†’"), ], ), }); }; Mount(IconsDemo, "#demo-icons"); ``` ### With Badges

Live Demo

```javascript const BadgesDemo = () => { const notifications = [ { id: 1, message: "New comment on your post", time: "5 min ago", unread: true, }, { id: 2, message: "Your order has been shipped", time: "1 hour ago", unread: true, }, { id: 3, message: "Welcome to the platform!", time: "2 days ago", unread: false, }, { id: 4, message: "Weekly digest available", time: "3 days ago", unread: false, }, ]; return List({ items: notifications, render: (item) => Div( { class: `flex justify-between items-center p-3 border-b border-base-300 hover:bg-base-200 ${item.unread ? "bg-primary/5" : ""}`, }, [ Div({ class: "flex-1" }, [ Div({ class: "font-medium" }, item.message), Div({ class: "text-xs opacity-50" }, item.time), ]), item.unread ? Span({ class: "badge badge-primary badge-sm" }, "New") : null, ], ), }); }; Mount(BadgesDemo, "#demo-badges"); ``` ### Interactive List

Live Demo

```javascript const InteractiveDemo = () => { const selected = $(null); const items = [ { id: 1, name: "Project Alpha", status: "In Progress" }, { id: 2, name: "Project Beta", status: "Planning" }, { id: 3, name: "Project Gamma", status: "Completed" }, { id: 4, name: "Project Delta", status: "Review" }, ]; const statusColors = { "In Progress": "badge-warning", Planning: "badge-info", Completed: "badge-success", Review: "badge-accent", }; return Div({ class: "flex flex-col gap-4" }, [ List({ items: items, render: (item) => Div( { class: `p-3 cursor-pointer transition-all hover:bg-base-200 ${selected() === item.id ? "bg-primary/10 border-l-4 border-primary" : "border-l-4 border-transparent"}`, onclick: () => selected(item.id), }, [ Div({ class: "flex justify-between items-center" }, [ Div({ class: "font-medium" }, item.name), Span( { class: `badge ${statusColors[item.status]}` }, item.status, ), ]), ], ), }), () => selected() ? Div( { class: "alert alert-info" }, `Selected: ${items.find((i) => i.id === selected()).name}`, ) : Div({ class: "alert alert-soft" }, "Select a project to see details"), ]); }; Mount(InteractiveDemo, "#demo-interactive"); ``` ### Reactive List (Todo App)

Live Demo

```javascript const ReactiveDemo = () => { const todos = $([ { id: 1, text: 'Complete documentation', done: false }, { id: 2, text: 'Review pull requests', done: false }, { id: 3, text: 'Deploy to production', done: false } ]); const newTodo = $(''); const addTodo = () => { if (newTodo().trim()) { const newId = Math.max(...todos().map(t => t.id), 0) + 1; todos([...todos(), { id: newId, text: newTodo(), done: false }]); newTodo(''); } }; const toggleTodo = (id) => { todos(todos().map(t => t.id === id ? { ...t, done: !t.done } : t)); }; const deleteTodo = (id) => { todos(todos().filter(t => t.id !== id)); }; const pendingCount = () => todos().filter(t => !t.done).length; Watch(()=> console.log(pendingCount())); return Div({ class: 'flex flex-col gap-4' }, [ Div({ class: 'flex gap-2' }, [ Input({ placeholder: 'Add new task...', value: newTodo, oninput: (e) => newTodo(e.target.value), onkeypress: (e) => e.key === 'Enter' && addTodo() }), Button({ class: 'btn btn-primary', onclick: addTodo }, 'Add') ]), List({ items: todos, render: (item) => { // Esta funciรณn busca siempre el estado actual del item dentro del signal const it = () => todos().find(t => t.id === item.id) || item; return Div({ class: () => `flex items-center gap-3 p-2 border-b border-base-300 ${it().done ? 'opacity-60' : ''}` }, [ Checkbox({ value: () => it().done, onclick: () => toggleTodo(item.id) }), Span({ class: () => `flex-1 ${it().done ? 'line-through' : ''}`, onclick: () => toggleTodo(item.id) }, () => it().text), Button({ class: 'btn btn-ghost btn-xs btn-circle', onclick: () => deleteTodo(item.id) }, 'โœ•') ]); } }), Div({ class: 'text-sm opacity-70 mt-2' }, () => `${pendingCount()} tasks remaining`) ]); }; Mount(ReactiveDemo, '#demo-reactive'); ``` ### Avatar List

Live Demo

```javascript const AvatarDemo = () => { const contacts = [ { name: "Alice Johnson", role: "Developer", avatar: "A", online: true }, { name: "Bob Smith", role: "Designer", avatar: "B", online: false }, { name: "Charlie Brown", role: "Manager", avatar: "C", online: true }, { name: "Diana Prince", role: "QA Engineer", avatar: "D", online: false }, ]; return List({ items: contacts, render: (contact) => Div({ class: "flex gap-3 p-3 hover:bg-base-200 transition-colors" }, [ Div( { class: `avatar ${contact.online ? "online" : "offline"}`, style: "width: 48px", }, [ Div( { class: "rounded-full bg-primary text-primary-content flex items-center justify-center w-12 h-12 font-bold", }, contact.avatar, ), ], ), Div({ class: "flex-1" }, [ Div({ class: "font-medium" }, contact.name), Div({ class: "text-sm opacity-60" }, contact.role), ]), Div( { class: `badge badge-sm ${contact.online ? "badge-success" : "badge-ghost"}`, }, contact.online ? "Online" : "Offline", ), ]), }); }; Mount(AvatarDemo, "#demo-avatar"); ``` ### All Variants

Live Demo

```javascript const VariantsDemo = () => { const items = ["Item 1", "Item 2", "Item 3"]; return Div({ class: "flex flex-col gap-6" }, [ Div({ class: "text-sm font-bold" }, "Default List"), List({ items: items, render: (item) => Div({ class: "p-2" }, item), }), Div({ class: "text-sm font-bold mt-2" }, "With Shadow"), List({ items: items, render: (item) => Div({ class: "p-2" }, item), class: "shadow-lg", }), Div({ class: "text-sm font-bold mt-2" }, "Rounded Corners"), List({ items: items, render: (item) => Div({ class: "p-2" }, item), class: "rounded-box overflow-hidden", }), ]); }; Mount(VariantsDemo, "#demo-variants"); ```