Overview
The <action-history>
element provides an interface with interactive controls for a "History" system.
When developing something like an "Undo" feature, user actions are maintained in memory so that their effects can be reversed. This element is a helper for that kind of functionality. The term "History system" is used to describe the abstract version of an "Undo" feature which includes "Redo" functionality as well as direct-point-in-history access.
The <action-history>
element is intended to facilitate history functionality by both providing an interactive, timestamped ledger of the actions taken, and dispatching events to indicate the user's intention to undo or redo their actions.
Basic Examples
The <action-history>
element maintains a full list of actions by treating each of its child elements that has a data-entry
attribute as an entry in the history log.
Any child element with the data-entry
attribute will be "managed" by the action history, which means it will respond to click and selection events to set the history system's state.
For layout and styling convenience, all child elements that do not have the data-entry
attribute are unaffected by the <action-history>
element.
Static Entries
In this example the <action-history>
element has been given three children, each with the data-entry
attribute.
Each element can be clicked to "activate" the entry. When an entry is activated, all subsequent entries (if any) are "reversed", if they have not already been reversed, and all prior entries are un-reversed.
Customization
To facilitate styling and support any representation of arbitrary history functionality, the <action-history>
element does not dictate any type of content restrictions on its entry elements. Any element, including <button>
s or <input>
s can be used as entries.
This example uses buttons as entries so they can be activated using keypresses:
Reverse Chronological Order
History items are often listed in reverse-chronological order, meaning that the latest action would be at the top of the list, and the earliest action would be at the bottom.
The <action-history>
element is already styled as a flex display, so setting the flex-direction
style property to column-reverse
provides a visual solution for reversing the items.
Unfortunately, this causes an issue with key-based navigation. For users using tabs to navigate through entries, the entries would be iterated through in their chronological order, rather than the way they are visually presented: in reverse.
To prevent this unexpected behavior, the <action-history>
element can have its entries reversed by including a reverse
attribute.
Compare how tabs navigate through each of the examples below:
In this example, the style is set using the reverse
attribute:
In this example, the style is set using only the style:
Events and Functions
The <action-history>
element's functionality is mostly abstract so this is a practical example with actions that are being managed by the <action-history>
element, and their effects being managed by handlers for the element's events and functions.
Each input's change event is handled to add a new <action-history>
entry. The activation
and reverse
events each have handlers that read the entries' data and apply that back to the input elements.
The following methods of history navigation are available:
-
Selection
-
Reverse
-
Undo/Redo
-
Using the using the "Undo" and "Redo" buttons below the <action-history>
element.
-
This method utilizes the back()
and forward()
functions to navigate through the history.
Unlike the simple reverse, these functions do not require a reference point and, instead, determine the active entry and navigate from there.
Nested Slots
The <action-history>
element can use entries passed through from a parent element's <slot>
. If the <action-history>
element needs to be nested in another element, it can be populated using that element's slot functionality, rather than by writing code to handle passing the entries through to the <action-history>
element.
This example places an <action-history>
element inside of the custom <shadow-wrapper>
element. Events are managed on the <shadow-wrapper>
element, as well, via event bubbling.