A couple of weeks ago there was an article on the Freexian blog about
Using
JavaScript in Debusine without depending on
JavaScript. It
describes how JavaScript is used in the Debusine Django app, namely for
progressive enhancement rather than core functionality .
This is an approach I also follow when implementing web interfaces and I think
developments in web technologies and standardization in recent years have made
this a lot easier.
One of the examples described in the post, the Bootstrap toast messages, was
something that I implemented myself recently, in a similar but slightly
different way.
In the main app I develop for my day job we also use
the Bootstrap
framework. I have also used it for different
personal projects (for example the GSOC project I did for Debian in 2018, was
also a Django app that used
Bootstrap).
Bootstrap is still primarily a CSS framework, but it also comes with a
JavaScript library for some functionality. Previous versions of Bootstrap
depended on jQuery, but since version 5 of Bootstrap, you don t need jQuery
anymore. In my experience, two of the more commonly used JavaScript utilities
of Bootstrap are
modals
(also called lightbox or popup, they are elements that are displayed above
the main content of a website) and
toasts (also called
alerts, they are little notification windows that often disappear after a
timeout). The thing is, Bootstrap 5 was released in 2021 and a lot has happened
since then regarding web technologies. I believe that both these UI components
can nowadays be implemented using standard HTML5 elements.
An eye opening talk I watched was
Stop using JS for
that from last years JSConf(!).
In this talk the speaker argues that the
Rule of least
power is one of the core
principles of web development, which means we should use HTML over CSS and CSS
over JavaScript. And the speaker also presents some CSS rules and HTML elements
that added recently and that help to make that happen, one of them being the
dialog
element:
The <dialog> HTML element represents a modal or non-modal dialog box or other
interactive component, such as a dismissible alert, inspector, or subwindow.
The Dialog element at MDN
The baseline for this element is widely available :
This feature is well established and works across many devices and browser
versions. It s been available across browsers since March 2022.
The Dialog element at MDN
This means there is an HTML element that does what a modal Bootstrap does!
Once I had watched that talk I removed all my Bootstrap modals and replaced
them with HTML
<dialog> elements (JavaScript is still needed to
.show() and
.close() the elements, though, but those are two methods instead of a full
library). This meant not only that I replaced code that depended on an external
library, I m now also a lot more flexible regarding the styling of the
elements.
When I started implementing notifications for our app, my first approach was to
use Bootstrap toasts, similar to how it is implemented in Debusine. But looking
at the amount of HTML code I had to write for a simple toast message, I thought
that it might be possible to also implement toasts with the
<dialog> element.
I mean, basically it is the same, only the styling is a bit different. So what
I did was that I added a
#snackbar area to the DOM of the app. This would be
the container for the
toast messages. All the toast messages are simply
<dialog> elements with the
open attribute, which means that they are
visible right away when the page loads.
<div id="snackbar">
% for message in messages %
<dialog class="mytoast alert alert- message.tags " role="alert" open>
message
</dialog>
% endfor %
</div>
This looks a lot simpler than the Bootstrap toasts would have.
To make the
<dialog> elements a little bit more fancy, I added some CSS to make
them fade in and out:
.mytoast
z-index: 1;
animation: fadein 0.5s, fadeout 0.5s 2.6s;
@keyframes fadein
from
opacity: 0;
to
opacity: 1;
@keyframes fadeout
from
opacity: 1;
to
opacity: 0;
To close a
<dialog> element once it has faded away, I had to add one
JavaScript event listener:
window.addEventListener('load', () =>
document.querySelectorAll(".mytoast").forEach((element) =>
element.addEventListener('animationend', function(e)
e.animationName == "fadeout" && element.close();
);
);
);
(If one would want to use the same HTML code for both script and noscript users,
then the CSS should probably adapted: it fades away and if there is no
JavaScript to close the element, it stays visible after the animation is over.
A solution would for example be to use a close button and for noscript users
simply let it stay visible - this is also what happens with the noscript
messages in Debusine).
So there are many new elements in HTML and a lot of new features of CSS. It
makes sense to sometimes ask ourselves if instead of the solutions we know (or
what a web search / some AI shows us as the most common solution) there might
be some newer solution that was not there when the first choice was
created. Using standardized solutions instead of custom libraries makes the
software more maintainable. In web development I also prefer standardized
elements over a third party library because they have usually better
accessibility and UX.
In
How Functional Programming Shaped (and Twisted) Frontend
Development
the author writes:
Consider the humble modal dialog. The web has <dialog>, a native element with
built-in functionality: it manages focus trapping, handles Escape key
dismissal, provides a backdrop, controls scroll-locking on the body, and
integrates with the accessibility tree. It exists in the DOM but remains
hidden until opened. No JavaScript mounting required.
[ ]
you ve trained developers to not even look for native solutions. The platform
becomes invisible. When someone asks how do I build a modal? , the answer is
install a library or here s my custom hook, never use <dialog>.
Ahmad Alfy