Before-Cache Reset
stimeo--reset-before-cache
Resets transient UI on turbo:before-cache so Back restores a clean page.
The stimeo--reset-before-cache controller is the most Hotwire-specific gap part: on turbo:before-cache it returns transient UI — open menus/modals, typed-in values, lingering toasts — to its initial state, so a page restored by the Back button is not frozen mid-interaction. Place one on <body>. It applies declarative data-reset-* cleanup within scope: data-reset-attr removes the listed attributes (open, aria-expanded…), data-reset-class removes the listed classes (is-open, is-loading…), data-reset-form runs form.reset(), data-reset-value clears a standalone field, data-reset-hidden re-hides an element, and data-reset-remove drops a node. When dispatchReset is on it first fires stimeo--reset-before-cache:request so individual controllers can run their own close logic, then emits stimeo--reset-before-cache:reset. It is idempotent (every run converges on the same state) and the listener is paired to connect/disconnect. Behavior only — it adds no state hooks, it removes them.
Open the details, type a value, and show the toast — then simulate the cache.
Open me
This panel is open. After the cache reset it returns to closed.
<%# Markup for the before-cache reset demo.
On turbo:before-cache the controller returns transient UI to its initial state so a
Back-button restore is not frozen mid-interaction. This Playground has no real Turbo
navigation, so demo.js fakes the turbo:before-cache event. Open the details, type in
the field, and show the toast — then "Simulate before-cache" resets them all. %>
<div class="reset-demo" data-controller="stimeo--reset-before-cache">
<p class="reset-demo__note"><%= t("components.reset_before_cache.demo.note") %></p>
<details class="reset-demo__details" data-reset-attr="open">
<summary><%= t("components.reset_before_cache.demo.details_summary") %></summary>
<p><%= t("components.reset_before_cache.demo.details_body") %></p>
</details>
<label class="reset-demo__field">
<span><%= t("components.reset_before_cache.demo.input_label") %></span>
<input type="text" class="demo-input" data-reset-value
placeholder="<%= t("components.reset_before_cache.demo.input_placeholder") %>">
</label>
<div class="reset-demo__toast" data-reset-demo="toast" data-reset-hidden hidden role="status">
<%= t("components.reset_before_cache.demo.toast_text") %>
</div>
<div class="reset-demo__controls">
<button type="button" class="demo-trigger" data-reset-demo="show-toast">
<%= t("components.reset_before_cache.demo.show_toast") %>
</button>
<button type="button" class="demo-trigger" data-reset-demo="simulate">
<%= t("components.reset_before_cache.demo.simulate") %>
</button>
</div>
</div>
/*
* Presentation-only styles for the before-cache reset demo.
* The library only mutates the marked elements on turbo:before-cache (removing
* attributes, clearing values, re-hiding, removing nodes); this CSS owns layout.
*/
.reset-demo {
display: flex;
flex-direction: column;
gap: 0.75rem;
max-width: 32rem;
}
.reset-demo__note {
margin: 0;
font-size: 0.85rem;
color: var(--color-text-muted);
}
.reset-demo__details {
padding: 0.6rem 0.8rem;
border: 1px solid var(--border);
border-radius: 0.5rem;
}
.reset-demo__field {
display: flex;
flex-direction: column;
gap: 0.25rem;
font-size: 0.85rem;
}
.reset-demo__toast {
padding: 0.5rem 0.75rem;
border: 1px solid var(--leaf-500);
border-radius: 0.5rem;
background: var(--leaf-50);
color: var(--leaf-500);
font-size: 0.9rem;
}
.reset-demo__toast[hidden] {
display: none;
}
.reset-demo__controls {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
}
// Consumer-side JS for the before-cache reset demo (demo-only).
// Real Turbo navigation fires turbo:before-cache when caching a snapshot; this
// Playground has none, so the "Simulate" button dispatches that event to show the
// reset. The "Show toast" button reveals the transient toast the reset re-hides.
const toast = document.querySelector("[data-reset-demo='toast']");
const showToast = document.querySelector("[data-reset-demo='show-toast']");
const simulate = document.querySelector("[data-reset-demo='simulate']");
if (showToast && toast) {
showToast.addEventListener("click", () => {
toast.hidden = false;
});
}
if (simulate) {
simulate.addEventListener("click", () => {
document.dispatchEvent(new Event("turbo:before-cache"));
});
}
// The controller emits this once it has reset the snapshot's transient UI.
document.addEventListener("stimeo--reset-before-cache:reset", () => {
console.log("[reset-before-cache] transient UI reset before caching");
});
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--reset-before-cache"
Values
| Name | Description | Attribute |
|---|---|---|
scope
|
Selector narrowing the scan to a descendant; empty scans the whole subtree. | data-stimeo--reset-before-cache-scope-value |
dispatchReset
|
Whether to emit the request event for controllers (default true). |
data-stimeo--reset-before-cache-dispatch-reset-value |
Actions
| Name | Description | Action |
|---|---|---|
reset
|
Runs the reset sweep now (also bound to turbo:before-cache internally). |
stimeo--reset-before-cache#reset |
Events
| Name | Description | Event |
|---|---|---|
reset
|
Fires after the reset sweep runs. | stimeo--reset-before-cache:reset |
request
|
Sent so individual controllers can run their own close logic. | stimeo--reset-before-cache:request |