Build a micro-javascript frontend framework based on Web Components and no-build
Creating a basic JavaScript framework on Web Components with Shadow DOM and ES Modules, including client-side routing, requires a few steps. I shall outline how one can set up a framework.
Step 1: Setting Up Your Project
Create a brand new directory for your project and initialize it.
mkdir my-framework
cd my-framework
npm init -y
Step 2: Creating the Base Class for Components
Create a base class for your components. This one should extend HTMLElement
and set up some basic functionality.
// src/MyComponent.js
export class MyComponent extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
connectedCallback() {
this.render();
}
disconnectedCallback() {
// Clean up if needed
}
render() {
// This method should be overridden by subclasses
this.shadowRoot.innerHTML = `<p>Override the render method in your component</p>`;
}
}
Step 3: Creating a Simple Component
Create a simple component that extends our MyComponent
base class.
// src/HelloWorld.js
import { MyComponent } from './MyComponent.js';
class HelloWorld extends MyComponent {
render() {
this.shadowRoot.innerHTML = `<p>Hello, World!</p>`;
}
}
customElements.define('hello-world', HelloWorld);
Step 4: Creating the Router
Build a simple client-side router. This router will be bound to changes in the URL and load an appropriate component accordingly.
// src/Router.js
class Router {
constructor(routes) {
this.routes = routes;
window.addEventListener('popstate', this.handleRoute.bind(this));
this.handleRoute();
}
handleRoute() {
const path = window.location.pathname;
const route = this.routes[path] || this.routes['/404'];
document.querySelector('router-view').innerHTML = `<${route}></${route}>`;
}
navigate(path) {
window.history.pushState({}, path, path);
this.handleRoute();
}
}
export const createRouter = (routes) => new Router(routes);
Step 5: Create the Entry Point
Now it is time to create an entry point for your application. This file should import the components that will be used and configure the router.
// src/index.js
import './HelloWorld.js';
import { createRouter } from './Router.js';
const routes = {
'/': 'hello-world',
'/404': 'not-found' // Create this component or use a default one
};
const router = createRouter(routes);
document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll('[route-link]').forEach(link => {
link.addEventListener('click', (e) => {
e.preventDefault();
router.navigate(e.target.getAttribute('href'));
});
});
});
Step 6: Setting Up Your HTML
Create an HTML file to serve your application. This file will import the entry point module and set up the routing links.
<!-- public/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Framework</title>
</head>
<body>
<nav>
<a href="/" route-link>Home</a>
<a href="/404" route-link>Not Found</a>
</nav>
<router-view></router-view>
<script type="module" src="./src/index.js"></script>
</body>
</html>
Step 7: Running the Application
Since we are using ES Modules, we can take advantage of modern browsers' native module support. Use a simple HTTP server to serve your application.
You can use a tool like http-server
to serve the public
directory.
npx http-server public
Outcome
Now you have a basic frontend javascript framework using Web Components with Shadow DOM, ES Modules, and client-side routing with no build step. Here is the summary of files that you should have:
my-framework/
src/
MyComponent.js
HelloWorld.js
Router.js
index.js
public/
index.html
package.json
Expanding the Framework
To expand this framework, consider adding:
State Management: Implement a simple state management solution.
Styling: Add scoped styles to components using the Shadow DOM.
HTTP Requests: Include utilities for making HTTP requests.
Advanced Routing: Implement more advanced routing features like nested routes and route guards.
This setup gives you a strong base for a modern, lightweight framework using Web Components, Shadow DOM, ES Modules, and client-side routing—with no build step.
Subscribe to my newsletter
Read articles from Vivek directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Vivek
Vivek
Curious Full Stack Developer wanting to try hands on ⌨️ new technologies and frameworks. More leaning towards React these days - Next, Blitz, Remix 👨🏻💻