Replay Button
Re-runs (or resets) a demo by replacing the wrapping element's inner HTML with a saved snapshot, then calling Alpine.initTree() so every Alpine scope re-binds. Pairs with the data-replayable="true" attribute emitted by any WireKit preview that can be re-run or reset — animation-capable components (<x-wirekit::reveal>, <x-wirekit::stat animate>, animated card / hero / cta / feature / footer, chart) and state-mutating components whose demo is "used up" by interaction (a dismissible <x-wirekit::badge> or <x-wirekit::alert>).
Why this component exists: it primarily powers WireKit's own documentation site — docs.wirekit.app wraps every re-runnable example in the replay pattern and renders a ↻ Replay control on top. Since it ships in the package regardless, it doubles as a ready-made building block for your own app: wire it up to re-run an animation, reset an interactive demo to its starting state, or restore a dismissed badge or alert. Combine it with the data-replayable contract below and use it however fits your UI.
How it works
The pattern requires three pieces:
- A wrapper element carrying
data-replay-targetanddata-replay-source="<encoded snapshot>". - Inside that wrapper: the actual demo (
<x-wirekit::reveal>,<x-wirekit::stat animate>, etc.) which emitsdata-replayable="true". - The
<x-wirekit::replay-button>itself, anywhere in the same DOM tree.
On click, the button walks closest('[data-replay-target]') from itself, replaces that element's innerHTML with the snapshot, then calls Alpine.initTree(root) to re-mount.
The docs site auto-injects this pattern around every :::preview block whose source matches a data-replayable shape, so developers reading the docs see a "↻ Replay" button on every re-runnable or resettable example — an animated demo, or a dismissible badge / alert whose chips can be restored after they are dismissed.
Usage
The simplest shape — drop an animated demo into a :::preview block and the docs site auto-wires the replay-target wrapper around it:
For developers wiring the pattern manually in their own app (outside the docs auto-injection), the full shape is:
<div data-replay-target
data-replay-source="{{ e('<x-wirekit::reveal preset=\'fade\'>Hello!</x-wirekit::reveal>') }}">
<x-wirekit::reveal preset="fade">Hello!</x-wirekit::reveal>
</div>
<x-wirekit::replay-button />
The data-replay-source attribute MUST hold an HTML-escaped snapshot of the inner markup — the click handler decodes it and assigns it to innerHTML before re-running Alpine.initTree(). Use e(...) or Blade's {{ }} echo to escape angle brackets and quotes, otherwise the browser parses the snapshot prematurely and the replay restores broken HTML.
The button picks up the closest data-replay-target ancestor automatically. To target a specific selector instead, pass target="…":
<x-wirekit::replay-button target="[data-demo-root]" />
Customizing the icon
Pass slot content to override the default circular-arrow glyph:
<x-wirekit::replay-button>
<x-wirekit::icon name="refresh" size="sm" />
Replay
</x-wirekit::replay-button>
Style hooks
Single BEM root: wk-replay-button. Override via your app.css:
.wk-replay-button {
color: var(--color-wk-text-subtle);
transition: color var(--motion-wk-duration-md);
}
.wk-replay-button:hover {
color: var(--color-wk-text);
}
Props
| Prop | Type | Default | Notes |
|---|---|---|---|
label |
string |
'Replay' |
Becomes aria-label on the rendered <button>. |
target |
string|null |
null |
Optional CSS selector; when set, the click handler walks $el.closest(selector) instead of [data-replay-target]. |
Accessibility
- Default
aria-label="Replay"(overridable via thelabelprop). - Renders as a real
<button type="button">so keyboard activation (Space / Enter) works without extra wiring. - Dispatches
wirekit:replayed(bubbling) on thedata-replay-targetroot after re-mount; listeners can hook into the event for analytics / focus management.
Keyboard Interaction
| Key | Action |
|---|---|
Tab |
Move focus to / away from the button (native browser tab order). |
Space |
Activate the replay (re-mount the demo). |
Enter |
Activate the replay (re-mount the demo). |
Focus stays on the button after activation so a keyboard user can replay multiple times without needing to re-tab. The dispatched wirekit:replayed event fires after the inner DOM is replaced; developers can listen to it and shift focus elsewhere if the demo's first interactive element should receive focus instead.