Yugen UI

useOptimisticList

Optimistic list updates: the UI changes the moment you click and syncs with the server in the background; on failure, exactly that change is rolled back and a toast explains why.

mutate(update, commit, options) applies update to the list right away and waits for commit(). On success the change is merged into the base data. On failure only that change is removed (other pending changes stay), and an error toast that doesn't close on its own offers a Retry button. update must be a pure function based on ids, because it is reapplied to the latest data. mutate returns true / false so you can follow up (e.g. put the text back in the input).
All changes saved

Import

Install from npm, copy the source into your project with @yugen-ui/cli or the shadcn CLI, or import directly when working in this repo.

TSX
// npm install yugen-uiimport { useOptimisticList } from "yugen-ui";

Variants

Each tile is a standalone example: hover to copy, or press Code to see the source.

Wait for server
Optimistic

Waiting for the server vs. optimistic

On a slow network the left button spins for 2 seconds; the right one changes at once and only reverts on an error.

  • Love this shade of pink!
  • The blossoms came out earlier than usual this year.

Add an item and restore the input on error

mutate returns false on failure; put the comment back in the input so people don't lose their text.

Usage

Do
  • Use it for actions that almost always succeed and are easy to undo: liking, checking off tasks, reordering, renaming.
  • Write update by id, not by position.
  • Report the error clearly when rolling back, and offer a retry.
Don't
  • Don't use it for payments, permanent deletion or other actions that can't be undone. Wait for the server.
  • Don't roll back silently.
  • Don't lock the whole list while waiting. That is the pessimistic approach.

Props

Prop · TypeDefaultDescription
useOptimisticList(initial)T[] | () => T[]Default: —Initial (confirmed) data.
itemsT[]Default: —Base data plus every pending change.
mutate(update, commit, options?)(T[] => T[], () => Promise, OptimisticOptions) => Promise<boolean>Default: —Applies update at once and waits for commit; true on success.
options.errorTitle / errorBodyReactNodeDefault: "Couldn't save changes"Toast content on failure.
options.toast / onErrorboolean · (error) => voidDefault: trueTurns off the default toast / handles the error yourself.
setItemsDispatch<SetStateAction<T[]>>Default: —Replaces the base data (e.g. after reloading from the server).
pendingbooleanDefault: —There are pending changes; combine it with useSpinDelay for a “Saving…” line.

Messages

Text built into the component: labels, aria-labels, screen reader announcements.

English by default. Change it with the messages prop of YugenProvider, by the namespace below; messagesVi has the Vietnamese set. See Interface language.

messages.optimisticList

Key · TypeDefault (English)messagesVi
errorTitlestringDefault (English)"Couldn't save changes"messagesVi"Không lưu được thay đổi"
errorBodystringDefault (English)"Your changes were undone."messagesVi"Thay đổi đã được hoàn tác."
retrystring

Nút trong toast.

Default (English)"Retry"messagesVi"Thử lại"
retryAltTextstring

Mô tả thay thế của nút (cho trình đọc màn hình).

Default (English)"Retry the last action"messagesVi"Thực hiện lại thao tác vừa rồi"