Motivation
We want to have something like this
There are a number of ready-made components out there, so what was our motivation for this control?
As always, there are several reasons to develop your own components and not use existing ones. When you write code yourself, you not only have full control, but you also always learn something new.
The learning effect cannot be overemphasized.
Here we would like to pass on a few learnings.
Maybe it helps you!
Technical conditions
But now let's get to our latest achievement, a notify control.
The component itself is not rocket science. Showing and hiding is done via CSS properties display
and the setTimeout
functionality. Quite simple.
An exciting question when creating the component was the positioning. How can the messages be arranged?
Naive implementation
One possibility is absolute positioning.
You simply define the top value for each message and thus have a first solution.
<style>
.message {
position: absolute;
right: 20px;
}
:nth-child(0) {
top: 0;
}
:nth-child(1) {
top: calc(1 * 40px);
}
:nth-child(2) {
top: calc(2 * 40px);
}
</style>
<div class="message">
this is message 1
</div>
<div class="message">
this is message 2
</div>
<div class="message">
this is message 3
</div>
Looks quite nice already. Unfortunately, the solution has several problems. For example, what happens when the text of the notification is longer. Then the positions of the underlying are no longer correct.
An improvement would be to calculate the height via Javascript
This is done by calculating the height and top of the messages and placing the next message below them accordingly.
const element = document.querySelector('.message')
var domRect= element.getBoundingClientRect();
const margin = 20;
const nextPosition = domRect.bottom+margin;
console.log(nextPosition);
This can be cast into a nice function and used. This works quite well and is also done by some components in the wild.
CSS should do the job
However, Javascript has the disadvantage that it is Javascript. Any calculation that has to run in Javascript is slower than native code.
So what to do?
The further consideration was, whether there is not a simpler system. Among other things, you can set up a div
as a container and display the messages below each other.
This has the advantage, you don't need to calculate distances and you can adjust the positioning via flex
.
<style>
.container {
position: absolute;
top: 0;
right: 0;
display:flex;
flex-direction: column;
}
.message {
margin-top: 25px
}
</style>
<div class="container">
<div class="message">
this is message 1
</div>
<div class="message">
this is message 2<br>
second line
</div>
<div class="message">
this is message 3
</div>
</div>
However, a absolute positioned div
has a disadvantage. The content behind it is not clickable or selectable.
This is where the CSS property user-select
comes into play.
This allows a div to be expanded and pretend it's not there.
That's really all we need.
The final component
We have integrated all of this knowledge into a component.
You can examine the code in detail on our gitlab or in npm.
This is simply included via the tag monster-notify
.
<monster-notify id="notify"
data-monster-options='{
"orientation": "right top"
}'>
</monster-notify>
The parameters, such as the positioning or the length of the overlay can be specified via a JSON data-monster-options
.
New messages can be included via push method.
import {Notify} from "@schukai/component-notify/notify.js"
// create new message
const message=document.createElement('monster-notify-message');
// simple HTML content
message.innerHTML='this is a message!';
// change standard timeout
message.setAttribute('data-monster-timeout', 1000)
// notify container
const notifyElement = document.getElementById('notify');
// show message
notifyElement.push(message);
The component itself has only one dependency to our own Monster library and uses only a few objects here.
hope you enjoy it!
Top comments (0)