# History > Undo / redo via withHistory - a snapshot timeline that wraps the reducer. Every action is undoable by default. Source: https://docs.docmosaic.com/docs/concepts/history The history layer is a thin snapshot timeline on top of the reducer. Every mutation flows through `withHistory(reducer)`, which captures the previous state before applying each action. Users get the standard Cmd+Z / Cmd+Shift+Z experience without any per-action wiring. ## The timeline ```ts import { reducer, withHistory } from '@docmosaic/core'; const wrapped = withHistory(reducer); let state = wrapped.init(initialDocument); state = wrapped.reduce(state, { type: 'ADD_SECTION' /* ... */ }); state = wrapped.reduce(state, { type: 'UNDO' }); state = wrapped.reduce(state, { type: 'REDO' }); ``` `state` is `{ past: Document[], present: Document, future: Document[] }`. The `past` and `future` arrays are bounded - the timeline caps at the configured depth (defaults to 50) to keep memory predictable for image-heavy documents. ## What's undoable Every reducer action is undoable by default. There's no opt-out flag and no "transient" action - if it mutates the document, it lands on the timeline. - `ADD_SECTION` / `UPDATE_SECTION` / `DELETE_SECTION` - `ADD_PAGE` / `DELETE_PAGE` / `REORDER_PAGES` - `BRING_TO_FRONT` / `SEND_TO_BACK` / `MOVE_FORWARD` / `MOVE_BACKWARD` - `SET_DOCUMENT_NAME` / `SET_PAGE_SIZE` / `SET_ORIENTATION` - `SET_HIDDEN` / `SET_LOCKED` - `ADD_GUIDE` / `REMOVE_GUIDE` - `SET_PAGE_BACKGROUND` UI-only state (the selection, the active hover, the marquee rectangle) lives outside the document and isn't part of the timeline. ## Coalescing Continuous gestures coalesce into a single timeline entry. A drag that fires 60 `UPDATE_SECTION` calls becomes one undo step, not sixty. The hook detects same-target same-action sequences within a debounce window and merges them. Coalescing keeps the timeline tractable for image-heavy documents and matches user intent - one drag, one undo. ## Reading the timeline state The headless hook surfaces two booleans: ```ts const { canUndo, canRedo, actions } = useDocumentState(); ``` `canUndo` is `past.length > 0`; `canRedo` is `future.length > 0`. Editing dispatch clears `future` - the standard browser-style "redo doesn't survive a new edit" behavior. ## Controlled mode disables it `Editor.Root document={...} onDocumentChange={...}` (controlled) skips the timeline entirely - the parent owns state, so undo/redo would need to be implemented in the parent's own state container. `canUndo` / `canRedo` are always `false` and `actions.undo` / `actions.redo` are no-ops. If you want undo/redo in controlled mode, wrap your own state in `withHistory` and dispatch through it. ## Reset / replace There's no "clear timeline" action - to reset, swap the whole `Document` via the root: ```tsx const [doc, setDoc] = useState(initialDoc); function resetEditor() { setDoc(createDocument()); // remount-equivalent; timeline restarts } {/* ... */} ; ``` In uncontrolled mode, change `key` on `Editor.Root` to force a remount and discard the timeline. ## See also - [Document model](/docs/concepts/document-model) - what each timeline snapshot contains - [Keybindings](/docs/concepts/keybindings) - the default `mod+z` / `mod+shift+z` bindings - [Controlled vs uncontrolled](/docs/get-started/controlled-vs-uncontrolled) - when the timeline is active