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
| Prop | Type | Description |
|---|---|---|
each | T[] | (() => T[]) | The array to iterate over |
key | (item: T) => string | number | Optional key function for keyed diffing |
children | (item: T, index: () => number) => Node | Render 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
| Prop | Type | Description |
|---|---|---|
when | boolean | (() => boolean) | Condition controlling visibility |
children | Node | Node[] | (() => Node | Node[]) | Content shown when when is true |
fallback | Node | (() => 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>