Skip to content

Rendering Lists

manolo edge edited this page Jul 6, 2025 · 1 revision

Cardboard provides a powerful utility called each for rendering lists of items. It works with both plain arrays and reactive observables, making it easy to build dynamic, performant UIs.


Basic Usage

The each function takes a list (array or observable) and a builder function that returns a tag for each item.

import { init, allTags, each } from '@nkeff/cardboard-js';
const { ul, li } = allTags;

const items = ['Apple', 'Banana', 'Cherry'];

init().append(
  ul(
    each(items, (item) => li(item))
  )
);

Using with State (Reactive Lists)

If you use an observable (like state or listState), the list will update automatically when the data changes.

import { init, allTags, state, each } from '@nkeff/cardboard-js';
const { ul, li, button } = allTags;

const fruits = state(['Apple', 'Banana']);

init().append(
  button('Add Orange').clicked(() => fruits.value = [...fruits.value, 'Orange']),
  ul(
    each(fruits, (item) => li(item))
  )
);

See: each


Custom Keys for List Items

By default, Cardboard uses the item value as the key. For objects or non-unique values, you can provide a custom key function:

const users = [
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' }
];

ul(
  each(users, (user) => li(user.name), user => user.id)
);

Removing and Updating Items

When using observables, changes to the list (add, remove, reorder) are reflected in the DOM efficiently:

import { state, each, allTags } from '@nkeff/cardboard-js';
const { ul, li, button } = allTags;

const items = state(['A', 'B', 'C']);

ul(
  each(items, (item) =>
    li(
      item,
      button('Remove').clicked(() => {
        items.value = items.value.filter(i => i !== item);
      })
    )
  )
);

Performance

  • Cardboard's each uses a diffing algorithm to minimize DOM updates.
  • Only changed, added, or removed items are updated in the DOM.

Example: Todo List

import { init, allTags, state, each } from '@nkeff/cardboard-js';
const { ul, li, input, button } = allTags;

const todos = state(['Learn Cardboard', 'Build something']);

const addTodo = (value) => {
  if (value) todos.value = [...todos.value, value];
};

let inputRef;
init().append(
  input().on('input', (self) => (inputRef = self.value)),
  button('Add').clicked(() => addTodo(inputRef)),
  ul(
    each(todos, (todo) => li(todo))
  )
);

API

each(
  list: T[] | IObservable<T[]>,
  builder: (item: T) => CTag,
  key?: (item: T) => any
): Node
  • list: Array or observable of items.
  • builder: Function that returns a tag for each item.
  • key (optional): Function to provide a unique key for each item.

See: each

Clone this wiki locally