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) }