Persist
stimeo--persist
Keeps a half-finished form and puts it back when you return.
Keeps what you had typed into a form and puts it back the next time you open it, surviving a reload and Turbo visits alike. Saving waits for a pause in typing rather than writing on every keystroke. Password fields are never saved, and you can name other fields to leave out. Restoring is reported and readable from CSS, and it never moves focus. You choose when the draft is dropped, such as once the form has been submitted. Nothing leaves this browser.
Keyboard
This component has no keyboard interactions of its own.
<%# Persist demo: type into the fields and the draft is saved to localStorage
(debounced). Reload or navigate away and back — the values are restored and the
"draft restored" note appears (data-persist-restored). "Clear draft" calls the
clear() action. The library owns the storage and the data hook; this demo only
styles the restored note. %>
<div class="persist-demo">
<form
class="persist"
data-controller="stimeo--persist"
data-stimeo--persist-key-value="stimeo-demo-contact">
<p class="persist__restored"><%= t("components.persist.demo.restored") %></p>
<label class="persist__field">
<span><%= t("components.persist.demo.name") %></span>
<input type="text" name="name">
</label>
<label class="persist__field">
<span><%= t("components.persist.demo.message") %></span>
<textarea name="message" rows="3"></textarea>
</label>
<button type="button" class="demo-trigger" data-action="click->stimeo--persist#clear">
<%= t("components.persist.demo.clear") %>
</button>
</form>
</div>
/*
* Presentation-only styles for the persist demo.
* The library toggles data-persist-restored on the form; this CSS reveals the
* "draft restored" note while that hook is present.
*/
.persist-demo {
max-width: 28rem;
}
.persist {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.persist__field {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.persist__field input,
.persist__field textarea {
padding: 0.5rem;
border: 1px solid var(--border);
border-radius: 0.375rem;
font: inherit;
resize: vertical;
}
/* The note appears only after a draft has been restored. */
.persist__restored {
display: none;
margin: 0;
font-size: 0.85rem;
color: var(--accent-700);
}
.persist[data-persist-restored] .persist__restored {
display: block;
}
This demo needs no consumer-side JS (the controller handles the behavior).
These demo styles use shared design tokens (light + dark). Copy the shared styles too, then toggle data-theme on your root element for dark mode.
The data-* attributes you add to your own HTML to wire this component. Put the data-controller below on a root element, then place its targets / values / actions inside that element.
On the root element
data-controller="stimeo--persist"
Targets
| Name | Description | Attribute |
|---|---|---|
field
|
Optional fields to limit persistence to; defaults to the form's named controls. | data-stimeo--persist-target="field" |
Values
| Name | Description | Attribute |
|---|---|---|
key
|
localStorage namespace; falls back to the element id. Disabled when neither is set. |
data-stimeo--persist-key-value |
debounce
|
Debounce in milliseconds before a save (default 400). | data-stimeo--persist-debounce-value |
exclude
|
Field names/types never saved (default ["password"]). |
data-stimeo--persist-exclude-value |
clearOn
|
Event name that clears the draft (e.g. submit); empty disables it. |
data-stimeo--persist-clear-on-value |
Actions
| Name | Action |
|---|---|
clear
|
stimeo--persist#clear |
Events
| Name | Description | Event |
|---|---|---|
restore
|
Fires when values are restored, with detail.key. |
stimeo--persist:restore |
save
|
Fires after a debounced save, with detail.key. |
stimeo--persist:save |
clear
|
Fires when the draft is cleared, with detail.key. |
stimeo--persist:clear |
error
|
stimeo--persist:error |
State hooks
The library only manages these ARIA/data attributes and custom properties. Your CSS reads them to render the look — selectors like [aria-selected], [aria-expanded], or var(--stimeo--…) hook into this state.
| Hook | Target | Meaning |
|---|---|---|
data-persist-restored |
Form (root) | Present when values were restored from a saved draft. |