Skip to content

Instantly share code, notes, and snippets.

@basiszwo
Last active May 13, 2023 14:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save basiszwo/c736641e462d1cee0b70172a3f5d2224 to your computer and use it in GitHub Desktop.
Save basiszwo/c736641e462d1cee0b70172a3f5d2224 to your computer and use it in GitHub Desktop.
Dialog Component with Stimulus Dialog Controller

Goal

I have multiple dialogs / modals in my application. A couple of the are on the same page, accessible at the same time.

I use the DialogComponent as a wrapper to set up the dialog stimulus controller.

Besides other actions which are not yet implemented, I want to close the dialog by clicking a button and by pressing ESC.

Therefor I defined two actions click->dialog#close and keydown.enter->dialog#close.

Problem

The dialog closes when clicking on the supposed close button but pressing ESC key does not do anything.

Why does pressing ESC not work? Do I need to assign the action on another element?

Solution

Using keydown.enter@document->dialog#close appends the event listener to the document. The problem was that with @document the eventlistener is just bound to the button and doesn't work as expected.

<div
class="dialog-wrapper p-5 md:p-8 fixed w-full h-full left-0 top-0 z-90 flex items-start hidden flex overflow-y-auto backdrop-<%=@backdrop%>"
id="<%= @id %>"
data-controller="dialog"
data-dialog-target="dialogWrapper">
<div class="dialog-backdrop absolute w-full h-full top-0 left-0 opacity-0"></div>
<div class="dialog relative z-20 m-auto w-full text-brand-primary bg-white rounded-lg shadow-xl opacity-0 translate-y-32 <%= @max_width %>">
<%= content %>
</div>
</div>
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = [
"dialogWrapper",
]
connect() {
console.debug("Connecting dialog controller ...")
}
open(event) {
event.preventDefault()
}
close(event) {
console.debug("Closing dialog ...")
event.preventDefault()
this.dialogWrapperTarget.classList.add("hide-dialog")
setTimeout(() => {
this.dialogWrapperTarget.classList.remove("hide-dialog", "show-dialog", "unveil-dialog", "dialog-is-shown")
}, 200);
}
confirm(event) {
event.preventDefault()
}
}
<%# This is how the markup is used with the dialog component %>
<%= render(DialogComponent.new(id: 'add-person-dialog', max_width: 'max-w-lg', backdrop: 'dark')) do %>
<div class="dialog-body text-center">
<%= inline_svg 'icons/80x80/add_user.svg', class: 'preserve-appearance ml-auto mr-auto mb-6' %>
<h2 class="mb-2"> Teilnehmer hizufügen</h2>
<p>Um einen Teilnehmer hinzuzufügen, kopieren Sie bitte den folgenden Link. Senden Sie ihn an die Person, die Sie einladen möchten:</p>
<div class="pt-4 flex justify-between">
<input type="text" readonly="readonly" value="<%= request.original_url %>">
<button class="btn-copy ml-3 relative hover:text-brand-highlight w-12 bg-brand-fill-light rounded-md flex items-center justify-center"
data-tooltip="Kopieren"
data-action="copy-to-clipboard">
<%= render(IconComponent.new(name: 'copy', size: 20, css_class: "copy-icon")) %>
<%= render(IconComponent.new(name: 'success', size: 20, css_class: "success-icon text-brand-success")) %>
</button>
</div>
</div>
<div class="dialog-footer justify-center">
<a href="#" class="btn btn-primary btn-cta" data-action="click->dialog#close keydown.esc->dialog#close" data-turbo="false">Fertig</a>
</div>
<% end %>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment