# Page snapshot ```yaml - main [ref=e4]: - generic [ref=e6]: - complementary - generic [ref=e7]: - generic [ref=e8]: - generic [ref=e11]: - link "()" [ref=e12] [cursor=pointer]: - /url: /sx/ - generic [ref=e14]: () - paragraph [ref=e15]: The framework-free reactive hypermedium - paragraph [ref=e17]: © Giles Bradshaw 2026· /sx/(geography.(reactive.(examples.reactive-list))) - generic [ref=e18]: - link "← Etc" [ref=e19] [cursor=pointer]: - /url: /sx/(etc) - link "Geography" [ref=e20] [cursor=pointer]: - /url: /sx/(geography) - link "Language →" [ref=e21] [cursor=pointer]: - /url: /sx/(language) - generic [ref=e22]: - link "← Reactive Runtime" [ref=e23] [cursor=pointer]: - /url: /sx/(geography.(reactive-runtime)) - link "Reactive Islands" [ref=e24] [cursor=pointer]: - /url: /sx/(geography.(reactive)) - link "Hypermedia Lakes →" [ref=e25] [cursor=pointer]: - /url: /sx/(geography.(hypermedia)) - generic [ref=e26]: - link "← Examples" [ref=e27] [cursor=pointer]: - /url: /sx/(geography.(reactive.(examples))) - link "Examples" [ref=e28] [cursor=pointer]: - /url: /sx/(geography.(reactive.(examples))) - link "Examples →" [ref=e29] [cursor=pointer]: - /url: /sx/(geography.(reactive.(examples))) - generic [ref=e30]: - link "← Imperative" [ref=e31] [cursor=pointer]: - /url: /sx/(geography.(reactive.(examples.imperative))) - link "Reactive List" [ref=e32] [cursor=pointer]: - /url: /sx/(geography.(reactive.(examples.reactive-list))) - link "Input Binding →" [ref=e33] [cursor=pointer]: - /url: /sx/(geography.(reactive.(examples.input-binding))) - generic [ref=e37]: - paragraph [ref=e38]: - text: When - code [ref=e39]: map - text: is used with - code [ref=e40]: (deref signal) - text: inside an island, it auto-upgrades to a reactive list. With - code [ref=e41]: :key - text: attributes, existing DOM nodes are reused across updates — only additions, removals, and reorderings touch the DOM. - generic [ref=e43]: - generic [ref=e44]: - button "Add Item" [ref=e45] [cursor=pointer] - generic [ref=e46]: 0 items - list - generic [ref=e48]: (defisland ~reactive-islands/index/demo-reactive-list () (let ((next-id (signal 1)) (items (signal (list))) (add-item (fn (e) (batch (fn () (swap! items (fn (old) (append old (dict "id" (deref next-id) "text" (str "Item " (deref next-id)))))) (swap! next-id inc))))) (remove-item (fn (id) (swap! items (fn (old) (filter (fn (item) (not (= (get item "id") id))) old)))))) (div (~tw :tokens "rounded border border-violet-200 bg-violet-50 p-4 my-4") (div (~tw :tokens "flex items-center gap-3 mb-3") (button (~tw :tokens "px-3 py-1 rounded bg-violet-600 text-white text-sm font-medium hover:bg-violet-700") :on-click add-item "Add Item") (span (~tw :tokens "text-sm text-stone-500") (deref (computed (fn () (len (deref items))))) " items")) (ul (~tw :tokens "space-y-1") (map (fn (item) (li :key (str (get item "id")) (~tw :tokens "flex items-center justify-between bg-white rounded px-3 py-2 text-sm") (span (get item "text")) (button (~tw :tokens "text-stone-400 hover:text-red-500 text-xs") :on-click (fn (e) (remove-item (get item "id"))) "✕"))) (deref items)))))) - paragraph [ref=e49]: - code [ref=e50]: :key - text: identifies each list item. When items change, the reconciler matches old and new keys — reusing existing DOM nodes, inserting new ones, and removing stale ones. Without keys, the list falls back to clear-and-rerender. - code [ref=e51]: batch - text: groups the two signal writes into one update pass. ```