Atom global state
Atom is for process-wide shared state: theme, logged-in user, cross-page cache, and global selections. This example puts “committed state” into atoms and keeps “draft input” in page-local use_state, so global state is not polluted by every keypress.

This recording is generated by docs/tapes/atom-state.tape. The example enters the focus editor and types write atom docs; after submission, dashboard subscribers immediately show the new value. It then enters the score editor, changes the score, and another component reads the same Atom back on the dashboard.
Run it
Section titled “Run it”On the dashboard, press 1 to edit focus, 2 to edit score, and q to exit. In the focus editor, type text and press Enter to submit. In the score editor, press +/-/r to change the score and Esc to go back.
State flow
Section titled “State flow”Declare atoms
Section titled “Declare atoms”Atoms are module-level declarations and do not need a macro:
Atom::new receives an initializer function. The real state is created lazily on the first read or use_atom, then lives for the process lifetime.
Subscribe to atoms
Section titled “Subscribe to atoms”Use use_atom inside a component:
use_atom(&FOCUS) returns AtomState<T>. Like State<T>, it is a copyable reactive handle: read with get() or read(), write with set(), write(), or operators such as +=.
FocusCard, ScoreCard, and EventCard are independent components. Each subscribes only to the Atom it needs; writing SCORE does not require putting focus text into the same large structure.
Do not put local drafts into atoms
Section titled “Do not put local drafts into atoms”The focus editor has a single-line input. Characters typed during editing are local state:
This boundary matters. A draft belongs to the current editor page and should disappear when the page unmounts. The submitted focus belongs to the whole application. Writing every keypress to an Atom would wake unrelated components frequently and make “cancel edit” awkward.
Boundary with Router
Section titled “Boundary with Router”The example uses RouterProvider to switch between three pages, but Router history itself is not stored in an Atom:
Router state is provider-scoped and belongs inside RouterProvider. Atom is process-wide state for business data that multiple pages need to read and write. When one navigation needs a temporary payload, use push_with_state / replace_with_state; do not emulate route state with a global Atom.
When to use Atom
Section titled “When to use Atom”Prefer the smallest scope that works:
| State | Where to put it |
|---|---|
| Input draft | use_state |
| List cursor | Component-internal state or external State<ListState> |
| Current logged-in user | Atom<User> |
| Cross-page cache | Atom<Cache> |
| Router history | State inside RouterProvider |
Next, read Input isolation to see how terminal keyboard events are routed by layer beyond shared state.