mBlocks - Frontend UI Library Tutorial
Alex Merced
Co-Author of “Apache Iceberg: The Definitive Guide” | Head of DevRel at Dremio | LinkedIn Learning Instructor | Tech Content Creator
What is mBlocks
In my journey building different frontend libraries to improve my own comfort with frontend development I made libraries like MercedUI and AMPonent that are built around the Web Component browser API. I wanted to try building a library that doesn't use the web component API to build reactive UI and this was my first attempt (I later created RenderBlocks).
*You can find this and my other libraries at AlexMercedCoder.com
*mBlocks Github Page: https://github.com/AlexMercedCoder/mBlocks/blob/master/block.js
Setup
- in a folder somewhere on your computer create three files.
- index.html
- app.js
- style.css
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <!-- mBlocks --> <script src="https://www.alexmercedcoder.com/block.js" charset="utf-8" defer ></script> <!-- Your Code --> <script src="app.js" defer></script> <link rel="stylesheet" href="style.css" /> </head> <body></body> </html>
Your first block
The way m-blocks works is you bind an element to the instance and it will render a template to that element. To create a new block do the following.
app.js
class HelloWorld extends Block { constructor(id) { super({ //The Name of the Tag to look for <m-helloworld> name: "helloworld", //The Initial State state: {}, //The id of particular element the instance will bind to id, }) } //the builder function returns the template to be rendered builder(state, props) { return `<h1>Hello World</h1>` } } //Create an instance and bind to <m-helloworld id='hw'> const hw = new HelloWorld("hw")
index.html
<body> <m-helloworld id="hw"></m-helloworld> </body>
Props
Just like React, props can be passed in.
class HelloWorld extends Block { constructor(id) { super({ //The Name of the Tag to look for <m-helloworld> name: "helloworld", //The Initial State state: {}, //The id of particular element the instance will bind to id, }) } //the builder function returns the template to be rendered builder(state, props) { return `<h1>${props.hello}</h1>` } } //Create an instance and bind to <m-helloworld id='hw'> const hw = new HelloWorld("hw") <body> <m-helloworld id="hw" hello="hello world"></m-helloworld> </body>
State
mBlocks has reactive state built in, and just like React triggers a re-render with every update as seen below. The assemble function runs after every render which is the perfect place to initialize new mBlock instances in the blocks template and wire necessary event listeners.
class HelloWorld extends Block { constructor(id) { super({ //The Name of the Tag to look for <m-helloworld> name: "helloworld", //The Initial State state: { hello: "Hello World" }, //The id of particular element the instance will bind to id, }) } //the builder function returns the template to be rendered builder(state, props) { return `<h1>${state.hello}</h1><button>Click Me</button>` } assemble(state, props) { const button = document.querySelector("button") button.addEventListener("click", () => { this.setState({ hello: "Goodbye World" }) }) } } //Create an instance and bind to <m-helloworld id='hw'> const hw = new HelloWorld("hw")
Conclusion
That's all there really is to mBlocks. It may not be as smooth as my web component libraries like MercedUI and AMPonent but you don't have to worry about browser compatibility of the Web Component API.