Skip to content
ZOLO / TE708 Type · warning

island list without `key`

Compiler diagnostic TE708: island list without `key`.

Why this fires

This is a warning, not a hard error — it does not fail the build. A for loop produces a list of rows, and the row that carries an @island component has no key.

key is how the client-side morph matches an old row to its replacement across a re-render. Without it, a list that gains, loses, or reorders an item is rewritten node by node instead of patched in place — and every island in the list loses its hydrated DOM node along with it: signals reset, focus and scroll are lost, an input the user was typing into re-mounts empty.

@island
fn ItemTarefa(id: int = 0, descricao: str = "") -> View {
    var<signal> concluida = false
    <li>{descricao}</li>
}

fn Lista(tarefas: [Tarefa]) -> View {
    <ul>
        {for tarefa in tarefas {
            <ItemTarefa id={tarefa.id} descricao={tarefa.descricao}/>
        }}
    </ul>
    // warning[TE708]: island list without `key` — reordering or replacing
    // rows will silently mismatch island state (`ItemTarefa` is `@island`)
}

The same warning fires for the "wrapper" idiom, where a plain element wraps the island — the key still belongs on the outer tag, because that is the node the morph actually reconciles:

for tarefa in tarefas {
    <li><ItemTarefa id={tarefa.id}/></li>
}
// warning[TE708]: ... (an `@island` component is nested inside this row)

v1 scope

This check is deliberately narrow: it only fires when the row calls a function decorated @island — as the root of the loop body, or nested inside the root's subtree. A list of plain elements with no client-side state (<li>{x}</li>) never warns, because there is nothing to lose on reorder. A component that cannot be proven to be a local @island (imported, or otherwise unresolved) also stays silent — this diagnostic never guesses.

Fix it

Add key to the row that carries the island (or wraps one), using a value that stays stable for the same logical item across renders — a database id, not the array index:

for tarefa in tarefas {
    <ItemTarefa key={tarefa.id} id={tarefa.id} descricao={tarefa.descricao}/>
}

Or, for the wrapper idiom, on the outer element:

for tarefa in tarefas {
    <li key={tarefa.id}><ItemTarefa id={tarefa.id}/></li>
}

The builder spelling accepts key the same way, for any element that declares it (e.g. li, tr):

li(key: tarefa.id) { ItemTarefa(id: tarefa.id) }

See also

  • TE719 — a handler inside an @island that cannot be compiled to JavaScript.
  • TE720 — assigning to a derived cell (let<signal>).

Global index

Find your way through Zolo

Try an idea

Start here

9 results

9 results

en