MatcherJS — new way of making DOM extensionsAndrii TelenkoBlockedUnblockFollowFollowingMar 6Component-based development is the most popular approach of building web applications nowadays.
The origins of such architecture was years ago from such frameworks like Angular, React etc.
Later lots of other frameworks joined component-based approaches and even today we have a new wave — web components.
Why components become so popular?I don’t want to dive into benefits of declarative programming in comparison to imperative, but generally I can highlight such reasons:Html markup language is pretty easy to understand and re-use inside of any web-application without lots of setup.
Developer is mostly oriented on layouting business pages by using native and custom html elements.
Safe DOM — each component has it’s own isolated html scope (ShadowDOM in case of native web components) which won’t pollute global environment stylesheets or elements.
State-management approaches allows to build components as a reflection of a data.
This gives web developers their old dream: splitting out code between DOM representation and business logic.
I am a fan of new web components technology which allows to use all these features natively.
This makes some revolution in the world of web development, because now there are no borders between different frameworks and/or libraries.
Native web components can be used everywhere in browser (polyfills?) because native layer for sure is same for all web applications.
Looks nice isn’t it?Ok, so before I will dive into my new solution, let’s try find areas when web components are suitable and where are not.
Using Web ComponentsUsage example 1.
Implementation of new UI elementImagine that our customer realized that he doesn’t like our number-selection ui elements and wants something new.
He decided to introduce new UI element Slider.
For sure Slider should be a new UI element since there is no such native element which we can use.
So this UI element should provide ability to select some numeric value by moving pointer through the line.
Slider should emit event ‘change’ each time when user changes it’s value and has ability to return it’s inner value.
So Slider interface can look like this:emit ‘change’getValue(): NumbersetValue(value: Number): voidSo we introduced new UI element which has it’s own layout, behavior and API:Usage example 2.
Proposal of new tooltipOk, we solved Slider task and have to switch to another one.
Let’s pretend that our customer doesn’t like our tooltips on all pages (we use native via ‘title’ attribute) and wants to have 3 separate tooltips:warning tooltip — should be highlighted with yellow border and has warning icon insideerror tooltip — should be highlighted with red border and has error icon insidenotification tooltip — should be highlighted with green borderTooltip is a feature which can be used by any element on mouse-hover.
We always used just ‘title’ attribute and it was very simple, but how easily add support of new title to our DOM model and use it declaratively?Let’s come up with anything.
So API like this can work:Isn’t such API breaks readability of our DOM?.Isn’t it becomes more complex to maintain?.What if in the future our customer will ask for some other similar features which can be applied to any element?Usage example 3.
Extending API of native elementsImagine that our customer doesn’t like usual text inputs for selecting some date, native ones are (input type=’datetime’) also isn’t what he want for UI.
After some decisions he introduced new calendar which can appear for our inputs on click.
What should we do in this case?Ok, we are very familiar with web components and we will introduce new component which will look like an input, but will show calendar on click.
API will be something like this:But then we realized that we forgot about ‘required’, ‘disabled’, ‘readonly’, ‘placeholder’ attribute features of native input.
So we have to make some efforts for our component to reflect these features.
Hmm, isn’t there some other way which will allow us to stay with native input but with datepicker feature?.Likely native input suits our web application, we just want for it to support datepicker feature.
What is Matcher?What if there will be an ability to extend set of native global feature-attributes with our own?.It can prevent us from having unnecessary container-components and will make our HTML easier.
That are the thoughts which bring me into creation of my new library MatcherJS: https://github.
com/telenko/matcher-jsMatcher is a new term which allow us to bind any feature to some attribute and then use it everywhere inside our DOM.
Matcher has very similar API to customElements, so it won’t cause complex setup or even (maybe) will allow us to have one common API of defining DOM extensions in future.
Matchers connect/disconnect flowSo, algorithm looks like this:MatchersController catches new element, immediately checks all matchers in store and grabs only which passed validation.
MatchersController creates an instance of all passed validation matchers and connects them to element.
MatchersController will observe element attributes and if matcher’s condition won’t pass validation anymore, controller will disconnect matcher instance from element and destroy it.
Note, MatchersController creates a separate Matcher instance for each element.
It means that matcher is not polluting prototype of html elements, it is just “connects” to it, but it is still a separate object.
Ok, so let’s take a look at what it has.
Adding simple matcherMatcherJS has only a few exported functions.
One of them is ‘defineMatcher’ function.
Let’s try to use it to define simple matcher:Ok, so can we use it now in our DOM?.Is there something else needed to setup matchers?No, with such html matcher will be applied to both elements:Named matcherExcept of defining matchers only by attribute existence, there is an ability to define matcher which will require some value for attribute:Note, datepicker matcher in this example includes only rendering calendar by input click and listening to it.
Calendar itself is a really new UI element and for sure should be a web component.
Trying to re-write all our solutions with matcherSo matchers gives lot’s of freedom, but before starting use them let’s split up responsibilities between matcher and custom element.
Without some patterns and usage limitations code can become impossible to maintain and our html elements will conflict with each other.
So what to use?.Why need for matchers then?During this article I’ve highlighted several times “new UI element” and “element feature”.
Is there strict border between them?.I think no, but after lots of thinking I’ve created such set of rules when matchers can really help with organizing clean and easy to maintain code-base and when no.
Matchers can be used if1.
You are going to create css+js feature:Complex animation which may require some js calculations, some effects which are not supported by css etc.
You are going to introduce some new feature which can be added to any element:Tooltip, draggable elements (know about native, but this can support better animation), element resize-observation support etc.
You are going to extend API of any native element (safely):Adding resizable feature to <th> or datepicker to <input>4.
Unnecessary container:Can be useful to get rid of element-container-components.
Matchers shouldn’t be used if1.
New feature will add direct child elements to element or manipulate with it’s ShadowDOMSuch matcher can make our DOM very unsafe and unstable.
We should respect DOM encapsulation of each html element and not pollute it.
New feature represents a new UI element which is not exist in a set of native elements.
Data-responsible components (container components)Usually container components are wrappers for presenter components and responsible for controling of data and child components/elements.
They can be like a page builders and they always know how data looks like and what to do with it.
This case requires also safe DOM and represents also some sort of a new UI element like page.
ConclusionOk, so I hope that this small library will help you with organizing your web applications.
Thanks for reading!.