View as Markdown
Closeable
A Stimulus behavior that removes its element from the page when dismissed, with optional delayed and automatic closing and an animated countdown bar.
100%
Loading...
<div data-controller="closeable" class="">
<div class="">
<p class="">Heads up!</p>
<p class="">This message can be dismissed.</p>
</div>
<button type="button" data-action="click->closeable#close" aria-label="Dismiss" class="">
<span aria-hidden="true" class="">×</span>
</button>
</div>
Installation
php bin/console ux:install closeable --kit common
Copy the following file(s) into your app:
assets/controllers/closeable_controller.js
import { Controller } from '@hotwired/stimulus';
/**
* @value autoClose Delay in milliseconds after which the element removes itself once connected.
* @target timerbar Element whose width animates down to 0 over the close delay to visualize the countdown. It is hidden until a delayed or automatic close starts.
* @action close Removes the element. Accepts a `data-closeable-delay-param` (milliseconds) to defer the removal.
* @action cancel Cancels a pending delayed or automatic close.
*/
export default class extends Controller {
static targets = ['timerbar'];
static values = {
autoClose: Number, // auto close delay in ms
};
#timeout;
connect() {
if (this.hasTimerbarTarget) {
this.timerbarTarget.hidden = true;
}
if (this.hasAutoCloseValue) {
this.#remove(this.autoCloseValue);
}
}
close({ params }) {
this.#remove(Math.max(0, params.delay || 0));
}
cancel() {
clearTimeout(this.#timeout);
if (this.hasTimerbarTarget) {
this.timerbarTarget.hidden = true;
}
}
#remove(delay = 0) {
// Cancel any pending close so repeated triggers can't race an earlier timeout.
clearTimeout(this.#timeout);
if (this.hasTimerbarTarget && delay) {
const timerbar = this.timerbarTarget;
timerbar.hidden = false;
// Snap to full width without animating, then transition down to 0 over the delay.
timerbar.style.transitionDuration = '0ms';
timerbar.style.width = '100%';
setTimeout(() => {
timerbar.style.transitionDuration = `${delay}ms`;
timerbar.style.width = '0';
}, 10);
}
this.#timeout = setTimeout(() => this.element.remove(), delay);
}
}
Usage
Add data-controller="closeable" to the element you want to remove, then trigger closeable#close from a child element:
<div data-controller="closeable">
<button type="button" data-action="click->closeable#close">Dismiss</button>
</div>
Examples
Delayed Close
Set a data-closeable-delay-param (in milliseconds) on the close action to defer the removal. Add a timerbar target to visualize the countdown.
100%
Loading...
<div data-controller="closeable" class="">
<div class="">
<p class="">Saved!</p>
<p class="">Dismiss to close after a short delay.</p>
</div>
<button type="button" data-action="click->closeable#close" data-closeable-delay-param="3000" aria-label="Dismiss" class="">
<span aria-hidden="true" class="">×</span>
</button>
<div data-closeable-target="timerbar" class=""></div>
</div>
Auto Close
Set data-closeable-auto-close-value (in milliseconds) to remove the element automatically once it connects. The timerbar target animates down over the same duration.
100%
Loading...
<div data-controller="closeable" data-closeable-auto-close-value="5000" class="">
<div class="">
<p class="">Copied to clipboard</p>
<p class="">This message closes on its own.</p>
</div>
<button type="button" data-action="click->closeable#close" aria-label="Dismiss" class="">
<span aria-hidden="true" class="">×</span>
</button>
<div data-closeable-target="timerbar" class=""></div>
</div>
Cancel Auto Close
Call closeable#cancel to stop a pending close. Here, hovering the message cancels the automatic close so the user has time to read it.
100%
Loading...
<div data-controller="closeable" data-closeable-auto-close-value="5000" data-action="mouseenter->closeable#cancel" class="">
<div class="">
<p class="">Hover to keep me</p>
<p class="">Move your pointer over this message to cancel the automatic close.</p>
</div>
<button type="button" data-action="click->closeable#close" aria-label="Dismiss" class="">
<span aria-hidden="true" class="">×</span>
</button>
<div data-closeable-target="timerbar" class=""></div>
</div>
API Reference
data-controller="closeable"
| Value | Type | Default |
|---|---|---|
data-closeable-auto-close-value Delay in milliseconds after which the element removes itself once connected.
|
Number |
- |
| Target | Description |
|---|---|
timerbar |
Element whose width animates down to 0 over the close delay to visualize the countdown. It is hidden until a delayed or automatic close starts. |
| Action | Description |
|---|---|
close |
Removes the element. Accepts a data-closeable-delay-param (milliseconds) to defer the removal. |
cancel |
Cancels a pending delayed or automatic close. |