The Power Of Dialog/ue - Part 1
Using powerful elements to enhance communication
Good communication is an essential element to every successful relationship. Whether in our families, friendships or communities how clearly we express ourselves can often make the difference between building connection or aggravating conflicts.
Having lived in intentional communities of one form or another for most of my adult life I have learned from both failure and success the power of effective and empathic dialogue. If you are having problems in your relationships or just want to take them to another level of intimacy, understanding and trust then I highly recommend Nonviolent Communication as a more compassionate way to both express yourself and listen to others.
Effective communication can make a big difference in the workplace as well. Building software on tight deadlines and budgets, team members can struggle to hear and be heard by others once emotions have run high. If you would like a great explanation of how NVC can make a difference check out this great talk by Stephanie Minn about using NVC when pair programming.
Drawing from some experiences on recent projects, in this three part blog post
series, I will be exploring ways to use NVC to dialogue more effectively in the
workplace. Interleaving this with similar lessons learned on the technical side,
I hope to demonstrate that good dialogue is powerful in all realms of work and
life.
Communicating effectively with users of an application is important and a different kind of dialog
, the relatively new html5 element, is also essential for doing that well. The semantic naming isn’t a coincidence since this element provides a way to convey information or provide possible actions to a user which is natively clear and accessible without having to resort to hacks that lead to problems.
The dialog element has been part of the html5 specification since 2017 but was not widely implemented by all major browsers until 2022. It has the flexibility to be used for both modal and non-modal applications. Some of the benefits include:
- accessibility: autofocus support, aria-roles assigned, keyboard navigation like closing with ESC
- consistency: standard apis for opening and closing provide ease of development and maintenance and cross browser reliability
- styling: includes a ::backdrop pseudo-element which can be custom styled with css and integrates with a top-layer stacking context to avoid z-index wrestling matches.
Basically, like with most modern html5/css3 innovations, the dialog element provides a standard solution for problems that website designers and developers had to find custom fixes for in the past. The dialog element is a powerful tool for attracting the attention of and communicating with your users whether it is through modals, slide-outs, alerts, tooltips or other similar elements.
Recently, we found ourselves working on a project with some unusual user interactions and found some creative ways to work with dialogs and Hotwire to meet the design requirements. The first use of dialogs came from a more standard use case: a drawer with a menu of user actions needed to open from below.
These days we are often using Jumpstart to kick off new projects both because it gives us a head start, especially for SaaS apps, but also because we get caught up on best practices and new innovations for Rails apps. In fact, it was due to our leaning on Jumpstart and their use of the tailwind-stimulus-components library maintained by Chris Oliver, the creator of Jumpstart itself, that got us excited about using dialogs.
For our drawer component we adapted the Jumpstart slideover component which connects to the related stimulus controller to slide up from the bottom. We just needed to add our own animation keyframes and css:
@keyframes slide-up-from-bottom {
from {
transform: translateY(100%);
}
}
@keyframes slide-down-to-bottom {
to {
transform: translateY(100%);
}
}
dialog.drawer[open] {
animation: slide-up-from-bottom 200ms forwards ease-in-out;
}
dialog.drawer[closing] {
pointer-events: none;
animation: slide-down-to-bottom 200ms forwards ease-in-out;
}
body:has(dialog[open]:not(.context-menu, .slideout)) {
filter: blur(4px);
overflow: hidden;
}
For our drawer we wanted it to interrupt interactions with the rest of the page so we used the showModal method to open the drawer. This option adds the ::backdrop
element to block the rest of the page and transfers the dialog content into the special top-layer stacking context. Notice that the css adds a blur to the rest of the body to highlight this effect; however, this does not affect the dialog because of the top-layer separation.
One virtue of the dialog element is that you can place it anywhere in your html and not have to worry so much about how it stacks with later contexts because of the top-layer context. Nevertheless, we chose to instead just add one drawer dialog element at the bottom of our body element and to inject the content with a turbo_frame
. This provides for a standard pattern without cluttering all our html with dialogs.
<dialog data-drawer-target="dialog"
data-action="click->drawer#backdropClose"
class="drawer w-screen max-w-none h-100 m-0 mt-auto rounded-t-lg">
<div class="relative w-full h-full p-18 pt-12 rounded-t-lg">
<button type="button" class="absolute top-12 right-18" data-action="drawer#close:prevent:stop medallion#unset">
<%= render_svg("xmark") %>
<span class="sr-only">Close</span>
</button>
<%= turbo_frame_tag "drawer-panel", class: "flex flex-col gap-6" %>
</div>
</dialog>
Now in our links and buttons we can specify the data-action
to open the drawer and data-turbo-frame: "drawer-panel"
to populate it. Note that we needed to assign the drawer
stimulus controller to our body element so that we could call the drawer#open
action from anywhere on the page. Our drawer stimulus controller simply augments the slideover version as needed. For example, we wanted a way to close the drawer before clicking on a link that leaves the page so that turbo would not cache the page with the drawer open if someone returned with the back button:
import { Slideover } from "tailwindcss-stimulus-components"
export default class extends Slideover{
leavePage(e) {
e.preventDefault()
this.close()
window.location = e.target.href
}
}
We will uncover in more depth how this all works and show some other tricks in part two of this exploration of the virtues of dialogs in hotwired Rails apps. We will also go into more depth into some of the nuances of effective dialogues when working with clients and team mates in the workspace. We can already see how using the right tool can make our communication more effective and our work and life more maintainable and peaceful.
If you’re looking for a team to help you discover the right thing to build and help you build it, get in touch.
Published on August 15, 2025