Invoker Commands API
The Invoker Commands API provides a way to declaratively assign behaviours to buttons, allowing control of interactive elements when the button is enacted (clicked or invoked via a keypress, such as the spacebar or return key).
src
What does that mean though? Basically we have a possibly growing amount of declarative HTML that can add interactivity, without javascript 🤯
If you're a old and kind of clever like me this might trigger happy memories of the <marquee>Do you believe in love after love</marquee>
element
HTML attributes
commandfor
Turns a element into a button, controlling the given interactive element; takes the ID of the element to control as its value.command
Specifies the action to be performed on an element being controlled by a control , specified via the commandfor attribute.
and an example from MDN
<button commandfor="mydialog" command="show-modal">Show modal dialog</button>
<dialog id="mydialog">
<button commandfor="mydialog" command="close">Close</button>
Dialog Content
</dialog>
So what's interesting about the above example, at least to me is it actually runs with javascript disabled!?! So only built in the browser commands will work, but I think this is cool. Really primitive elements that add a better UX to the user can now run in environments without javascript. Also this pattern has better Accessibility out of the box.
You can also write your own custom js events and handlers...
<button commandfor="my-img" command="--rotate-left">Rotate left</button>
<button commandfor="my-img" command="--rotate-right">Rotate right</button>
<img id="my-img" src="photo.jpg" alt="[add appropriate alt text here]" />
js
Copy to Clipboard
const myImg = document.getElementById("my-img");
myImg.addEventListener("command", (event) => {
if (event.command == "--rotate-left") {
myImg.style.rotate = "-90deg";
} else if (event.command == "--rotate-right") {
myImg.style.rotate = "90deg";
}
});
Thought I'd fork this article
<button commandfor="modalexample" command="show-modal">
Open modal dialog
</button>
<dialog class="modal-content" id="modalexample" class="">
<h2>Welcome to the Modal!</h2>
<p>This modal window is created using only HTML and CSS!</p>
<button commandfor="modalexample" command="close">Close Modal</button>
</dialog>
/* Modal container - hidden by default */
.modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.6);
opacity: 0;
pointer-events: none;
transition: opacity 0.3s ease;
/* Center the modal content */
display: flex;
align-items: center;
justify-content: center;
z-index: 100;
}
/* When the modal is targeted via URL hash, make it visible */
.modal:target {
opacity: 1;
pointer-events: auto;
}
/* Modal content box */
.modal-content {
background-color: white;
padding: 2rem;
border-radius: 6px;
width: 90%;
max-width: 500px;
max-height: 90vh;
overflow-y: auto;
box-shadow: 0 5px 30px rgba(0, 0, 0, 0.2);
}
/* Backdrop close link - covers the entire screen */
.modal-backdrop {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
cursor: default;
z-index: -1; /* Place behind modal content */
}
dialog:modal {
transition: all 1s ease;
overlay: auto !important;
}
/* Keyframes for dialog and popover elements */
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes fadeOut {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
/* Keyframes for the backdrop pseudo-element */
@keyframes backdropFadeIn {
from {
background: hsl(0 0% 0% / 0%);
}
to {
background: hsl(0 0% 0% / 50%);
}
}
@keyframes backdropFadeOut {
from {
background: hsl(0 0% 0% / 50%);
}
to {
background: hsl(0 0% 0% / 0%);
}
}
dialog::backdrop {
transition: all 1s ease;
opacity: 1;
transform: scaleX(1);
}
[dialog] {
font-size: 1.2rem;
padding: 10px;
/* Final state of the exit animation */
opacity: 0;
transform: scaleX(0);
transition:
opacity 0.7s,
transform 0.7s,
overlay 0.7s allow-discrete,
display 0.7s allow-discrete;
/* Equivalent to
transition: all 0.7s allow-discrete; */
}
/* Needs to be included after the previous [popover]:popover-open
rule to take effect, as the specificity is the same */
@starting-style {
[popover]:popover-open {
opacity: 0;
transform: scaleX(0);
}
}
/* Transition for the popover's backdrop */
[popover]::backdrop {
background-color: rgb(0 0 0 / 0%);
transition:
display 0.7s allow-discrete,
overlay 0.7s allow-discrete,
background-color 0.7s;
/* Equivalent to
transition: all 0.7s allow-discrete; */
}
[popover]:popover-open::backdrop {
background-color: rgb(0 0 0 / 25%);
}
/* Nesting selectors (&) cannot represent pseudo-elements, so this
starting-style rule cannot be nested. */
@starting-style {
[popover]:popover-open::backdrop {
background-color: rgb(0 0 0 / 0%);
}
}
#modalexample {
animation: fadeOut 0.5s forwards;
&::backdrop {
animation: backdropFadeOut 0.5s forwards;
}
&[open] {
animation: fadeIn 0.5s forwards;
&::backdrop {
animation: backdropFadeIn 0.5s forwards;
}
}
}
https://github.com/jswhisperer/re-modals
I'm not 100% overall on how I feel about that though, maybe it helps lower level with creating interactive elements... Maybe it feels like too little too late, time will tell.
Top comments (1)
css animations sourced from this article