# Slot(item) — let the caller decide what each row looks like

> `Slot(item)` renders the caller's template once for that item. It is how a component owns the list — the layout, the scrolling, the selection — while the app that uses it owns what a single row looks like.

<!-- id: ui-slot-template · area: ui · stability: preview · html: https://osysharp.com/reference/ui/slot-template/ -->

## Summary        {#summary}
A plain `Slot` places the caller's content once. `Slot(item)` renders it **once per item**, with a different value
each time — so one component can serve a list of anything.

## Signature      {#signature}
```osy syntax
// in the component — pass the item
Slot(<value>);

// at the call site — receive it
SomeComponent(items: xs) { x => … }
```

## Description    {#description}
Some components are about a *collection*: a picker, a list, a table. The component knows how to lay the collection
out; only the app knows what one row should say. `Slot(item)` is what connects those.

**The component passes the item:**

```osy title="inside the component — Slot hands each item out" syntax
[Composable] component Picker<T>(T[] options) {
  render {
    Stack {
      foreach (var o in options) { Slot(o); }
    }
  }
}
```

**The caller supplies a template**, naming the value it receives:

```osy title="at the call site — name the value the template receives" syntax
Picker(options: customers) { c =>
  Row { Text(c.Name); Hint(c.Region); }
}
```

That block is a **template**, not content: it runs once per `Slot(o)`, and `c` is a different customer each time.

**The template still sees everything around it.** Only the named value comes from the component; the rest of the
expression resolves where you wrote it, so a page's own state and the item can appear together:

```osy title="the template also sees the page around it" syntax
string search = "";

Picker(options: customers) { c =>
  Text(c.Name, bold: c.Name == search);     // `c` from Picker, `search` from the page
}
```

**A plain `Slot` is unchanged.** A component that just wraps its caller's content — a card, a panel, a dialog —
writes `Slot;` exactly as before. You only need the argument when the same content has to render more than once with
different values.

**A component may use both.** `Slot(current)` for the closed state of a dropdown and `Slot(o)` inside its list both
render the same template, with different values — which is usually what you want, since the selected row should look
like the rows it was chosen from.

### A repeated slot needs a template, and the compiler says so   {#repeated}

A fill is **placed, not copied**. The caller builds its content once and the component moves it to wherever the
`Slot` is — so a `Slot` reached once per row can only ever end up holding it in the **last** row, and every earlier
row renders empty. Both halves of that mismatch are compile errors rather than a blank page:

```osy title="refused — plain content for a slot inside a foreach" syntax
[Composable] component Rows<T>(T[] rows) {
  render { foreach (var r in rows) { Stack { Slot("cell"); } } }
}

Rows(rows: xs) { slot cell { Text("hi"); } }
// ✗ 'Rows' renders `Slot("cell")` inside a `foreach`, so this fill would be placed once per row …
```

**The fix is two-sided**, and so is the message: the caller writes a template, and the component gives that template
a datum to render with. A template is only ever invoked by `Slot(<name>, <datum>)`, so adding `r =>` alone swaps a
last-row-only page for an empty one — which is refused too, naming the component's half.

```osy title="the pair that works" syntax
[Composable] component Rows<T>(T[] rows) {
  render { foreach (var r in rows) { Stack { Slot("cell", r); } } }   // ← hand each invocation its row
}

Rows(rows: xs) { slot cell { r => Text(r.Name); } }                   // ← receive it
```

**Two mutually exclusive `if` arms are not repetition.** A component that writes the same `Slot` in a wide arm and a
narrow one renders one of them at a time, so plain content is correct there and is accepted.

**If a caller passes plain content to a component that expects a template**, nothing renders at that slot — the same
as any unfilled slot. Slots are optional by design.

## Examples       {#examples}

A picker that owns the list and lets its caller own the row:

```osy title="the control owns the LIST; the caller owns what a row looks like" test app=slot-template-picker
entity Customer { [MaxLength(100)] string Name; }

[Composable] component Picker<T>(T[] options) {
  render {
    Stack {
      foreach (var o in options) { Slot(o); }
    }
  }
}

component Home() {
  live var rows = Customer.ToList();
  render {
    Picker(options: rows) { c =>
      Text(c.Name);
    }
  }
}
```

A named per-row cell — the shape the refusals above steer to:

```osy title="one NAMED cell of a table — the shape the refusals above steer to" test app=slot-template-named-cell
entity Customer { [MaxLength(100)] string Name; }

[Composable] component Rows<T>(T[] rows) {
  render {
    Stack {
      foreach (var r in rows) { Row { Slot("cell", r); } }
    }
  }
}

component Home() {
  live var cs = Customer.ToList();
  render {
    Rows(rows: cs) { slot cell { c => Text(c.Name); } }
  }
}
```

## See also       {#see-also}
- [component](https://osysharp.com/reference/ui/component/) — declaring a component and its parameters
- [[Composable] — presentational components in public pages](https://osysharp.com/reference/ui/composable/) — marking a presentational component so any page can render it
