Control Flow

<For> and <Show> are reactive control flow components for use in client islands. Import them from davaux/client. They update the DOM surgically when signals change — no VDOM diffing, no full re-renders.

<For>

Renders a list from an array or a signal returning an array. Each item's DOM node is created by the render function you provide.

import { createSignal, For } from 'davaux/client'

const [items, setItems] = createSignal([
  { id: 1, name: 'Apples' },
  { id: 2, name: 'Bananas' },
])

<ul>
  <For each={() => items()}>
    {(item) => <li>{item.name}</li>}
  </For>
</ul>

The each prop accepts either a plain array or a signal getter function. When each is a signal getter, the list re-renders reactively whenever the signal changes.

Keyed diffing

By default, <For> does a full re-render of all items whenever the array changes. For lists that update frequently, pass a key function to enable keyed diffing — each item's DOM node is created once and reused, moved, or removed based on the key.

<For each={() => items()} key={(item) => item.id}>
  {(item, index) => (
    <li>{() => index() + 1}. {item.name}</li>
  )}
</For>

The second argument to the render function is a reactive index signal. With keyed diffing, the index stays correct as items are inserted, removed, or reordered — without recreating the DOM node.

When to use keyed diffing:

  • Items have stable unique identifiers
  • The list is sorted or filtered interactively
  • Items contain their own reactive state you want to preserve

Props

PropTypeDescription
eachT[] | (() => T[])The array to iterate over
key(item: T) => string | numberOptional key function for keyed diffing
children(item: T, index: () => number) => NodeRender function called once per item

<Show>

Conditionally renders content based on a boolean or a signal returning a boolean. The children are created once eagerly at mount time and then attached or detached from the DOM as the condition changes — they are not destroyed and recreated.

import { createSignal, Show } from 'davaux/client'

const [isLoggedIn, setIsLoggedIn] = createSignal(false)

<Show when={() => isLoggedIn()}>
  <UserMenu />
</Show>

Fallback

Use the fallback prop to render something when the condition is false:

<Show
  when={() => isLoggedIn()}
  fallback={<a href="/login">Log in</a>}
>
  <UserMenu />
</Show>

Lazy children

By default <Show> constructs its children immediately at mount time, even when when starts as false. If the hidden branch contains expensive effects or data fetching, wrap the children in a function so they are only constructed the first time the condition becomes true:

<Show when={() => isLoggedIn()}>
  {() => <Dashboard />}
</Show>

The function is called once and the result is cached — subsequent hide/show cycles just attach and detach the same nodes. The fallback prop accepts a function for the same reason:

<Show
  when={() => data() !== null}
  fallback={() => <HeavySkeleton />}
>
  {() => <DataView data={data()} />}
</Show>

Static condition

when can also be a plain boolean for one-time conditional rendering:

<Show when={user.isAdmin}>
  <AdminPanel />
</Show>

Props

PropTypeDescription
whenboolean | (() => boolean)Condition controlling visibility
childrenNode | Node[] | (() => Node | Node[])Content shown when when is true
fallbackNode | (() => Node)Optional content shown when when is false

<ErrorBoundary>

Catches errors thrown during the initial construction of its children — including errors in the first run of any createEffect inside them — and renders a fallback instead.

import { ErrorBoundary } from 'davaux/client'

<ErrorBoundary fallback={<p>Something went wrong.</p>}>
  {() => <RiskyComponent />}
</ErrorBoundary>

The fallback prop accepts a function that receives the caught error, which lets you display the message or log it:

<ErrorBoundary fallback={(err) => <p>Error: {err.message}</p>}>
  {() => <DataView data={parse(rawJson)} />}
</ErrorBoundary>

Children must be a function so their construction is deferred into the error boundary's try/catch. A plain <Node> child would be evaluated by JSX before ErrorBoundary runs.

Limitation: errors thrown by reactive updates after the initial render are not caught. If an effect can throw on subsequent runs, add a try/catch inside the effect itself.

Combining <For> and <Show>

A common pattern is to show a loading state while data is being fetched, then render the list:

import { createResource, For, Show } from 'davaux/client'

const [posts] = createResource(() => fetch('/api/posts').then(r => r.json()))

<Show when={() => !posts.loading} fallback={<p>Loading…</p>}>
  <For each={posts} key={(post) => post.id}>
    {(post) => <article><h2>{post.title}</h2></article>}
  </For>
</Show>