Skip to content

IDs and Keys

GPUI-RSX generates stable IDs when GPUI APIs require an element identity.

Most layout and styling calls do not need an ID. The macro only injects one when a stateful GPUI method is used.

For static RSX outside loops, the macro can generate IDs from the call site. This keeps common markup concise:

rsx! {
<button onClick={handler}>
{"Click"}
</button>
}

Static stateful scroll classes also trigger auto IDs:

rsx! {
<div class="overflow-y-scroll">
{"Scrollable content"}
</div>
}

The generated ID is deterministic for the macro expansion site.

Common ID-triggering attributes include onClick, onHover, onDrag, onAuxClick, onA11yAction, active, activeClass, groupActive, tooltip, tooltipShowDelay, focusable, role, ariaLabel, overflowScroll, overflowXScroll, overflowYScroll, trackScroll, scrollbarWidth, and static overflow-scroll class variants.

Attributes such as hover, hoverClass, focus, focusClass, group, groupHover, onMouseDown, and captureKeyDown do not by themselves require a stateful ID in the current GPUI target.

When rendering repeated stateful elements, provide key={...}:

rsx! {
<div>
{for task in &self.tasks {
<button key={task.id} onClick={handler} class="flex items-center gap-2">
{task.title.clone()}
</button>
}}
</div>
}

Loops that need stateful IDs produce a compile error if the key is missing. This prevents repeated rows from accidentally sharing the same generated ID.

key is a macro-only attribute. It never becomes a .key(...) method call.

Literal keys can be expanded with concat!:

rsx! {
<button key="toolbar" onClick={handler} />
}

Dynamic keys use formatting so each row or stateful instance gets a unique identity. The expression must implement Display:

rsx! {
<button key={task.id} onClick={handler} />
}

If an element does not need an ID, key is ignored:

rsx! {
<div key={task.id} class="flex items-center">
{task.title.as_str()}
</div>
}

The example above stays a plain element because no stateful method is present.

An explicit id always wins:

rsx! {
<button id="save-button" key={task.id} onClick={handler}>
{"Save"}
</button>
}

Use explicit IDs when identity must remain stable across source-line movement or refactors.

Add a key when:

  • the element appears inside {for ...},
  • the class or attribute uses a GPUI stateful behavior,
  • the identity must remain stable across reorder or update operations.

Keep simple, non-repeated elements keyless and let the macro generate IDs where needed.