Cover image for I Coded My Personal Site With Web Components

I Coded My Personal Site With Web Components

steveblue profile image Steve Belovarich Updated on ・5 min read

Ugh. The chore of refactoring a personal site. We all should do it but who has the time? This is the seventh iteration of my personal site, so I was in dire need of some inspiration. I'm looking for a part-time job teaching web development, so that was some motivation.

I needed more to get me excited. All it took was solving problems with vanilla JavaScript and CSS. I'm over JavaScript frameworks. I’m done trying to wrangle all the tooling needed to develop modern JavaScript anything. I kept it simple. I designed the site mainly in browser which led to some fits and starts but the payoff was worth it. Little things like the way the nav animates made me excited to keep going. It was nice getting back to my roots. A decade ago I was a one man full service agency, designing and developing marketing sites and e-commerce solutions for small businesses. It helped I was also building something fun.

The last iteration of the site was very different. At the time in 2015 I wanted to showcase my mastery over AngularJS and WebGL. The site drained your battery due to all the graphics processing, was not very SEO friendly (SPA), and well we know how well AngularJS has aged. Any modern JavaScript framework is a better alternative, however for a site that is mostly static content I decided to move in a different direction.

scrolling through my new personal site

Nope, this is not Gatsby. Sorry folks. I don't believe in the hype. I do believe in spec. I decided to implement my entire site with the custom elements v1 spec. As long as the solution could meet several criteria I would be fine.

  1. be viable five years into the future
  2. demonstrate my ability to architect and implement UI
  3. SEO friendly
  4. fun and easy to update, minimal maintenance

I chose Web Components instead of a modern JavaScript UI framework for several reasons. Spec is relatively future proof. Browsers will continue to implement the custom elements v1 spec for years to come, while JavaScript frameworks go in and out of fashion. I don't want to be in the same place in five years, regretting that I implemented my site with a JavaScript framework that is no longer supported. No... I want to look back and think "I made it so I only have myself to blame." 🤣

Last year I developed a microlibrary for coding Web Components with TypeScript decorators called Readymade. I used this library throughout the project, implementing each view and component with Readymade. Readymade is a thin layer around the custom elements spec, reducing some of the typical boilerplate while adding some features with minimal overhead. If I went with another library I would have used Stencil or LitElement, but I chose to stay the course with Readymade despite some shortcomings.

Coding my personal site with Web Components just feels right. I honestly don't understand the JavaScript community's aversion to custom elements. I definitely prefer this way of working compared to React. There are some quirks when it comes to styling custom elements, but when isn't there? I feel like abstracting CSS to make styles reusable is always a problem no matter what you are doing. With Readymade I get one-way data binding, but the library doesn't have the equivalent of ngFor in Angular: a way to loop over a data model and bind it to template. That would be handy for dynamic layouts. To be honest that is the only feature I miss from frameworks. I don't miss the dependency management. I don't miss the tooling. I don't miss Virtual DOM. This is a fantastic way to work!

To make my new site SEO friendly, I needed to server side render each view. Server side rendering Web Components was a breeze. One of the few third party packages I used in the project was @skatejs/ssr, a package that enables SSR in node.js for the custom elements v1 spec.

SkateJS needs to interpret the JavaScript for each component, so I bundled the components for the server, exporting each custom element tied to a route. Some of the components act as a view, while other components are smaller units of functionality. I devised a route config that could be injected into the server-side code, which is also Express middleware. When a user visits a particular route, SkateJS renders the components on the server and then Express responds to the request for the route with the compiled HTML. One of the pain points for this project was when I ended up having to implement a Router that was compatible with both Readymade and SkateJS. It turned out not to be so bad. 76 lines of code later and I had a router that worked.

I used Parcel for a development environment, coupled with a separate node process running an Express server that hosts a REST API. The API is only for the blog page. I display post thumbnails and descriptions from my posts on dev.to. To limit the amount of requests going to the DEV API, I setup my environment to query for the posts and then store them locally in production. I implemented a simple JSON database with LowDB which seems to be proficient for this project.

Web Components will be supported in web browsers well into the future, so when deciding which client-side technology would be viable in five to ten years custom elements seemed like a no-brainer. I can still do all the things I could have with a JavaScript library, only with a smaller footprint and less tooling. My hands touched virtually everything end to end. I feel like I learned a lot. I had a lot of control over the stack, so I could pivot easily.

Possibly the best story to come out of this project is about performance. The site when bundled for production weighs in around 23Kb (gzipped). That includes the microlibrary, router, the HTML, CSS, and JavaScript that actually displays content on the page. 23Kb is smaller than some JavaScript libraries. I consider that a huge win. Users don't have to download a ton of JavaScript. The homepage can load ~3.5sec over the "Fast 3G" network emulation in Chrome Dev Tools.

Alt Text

The site was just released so there are probably some minimal production bugs lurking around in some responsive states and devices. I decided to ship the MVP and circle back later to fix some of these issues.

Visit stephenbelovarich.com if you're interested in viewing my new personal site. The code is public on Github for anyone interested in what the development environment looks like.

What do you think?

Posted on by:

steveblue profile

Steve Belovarich


full stack web engineer, creative coder, teacher, cultural critic and indie music fan.


Editor guide

Hey Steve! This is really cool, I actually am developing my portfolio this way too! My goal is to make a mobile-friendly aesthetic website with no frameworks, CSS or JS. It is still in the making, but would love you could check it out here: github.com/raghav-misra/oblivionte...


Looking through your code I think it’s fairly well organized.

One of the biggest pain points for me working with custom elements was event handling. I don’t particularly like calling addEventListener all over the place, which is why I made a Decorator in Readymade that makes for cleaner code. That’s just preference though. It doesn’t hurt to use a library for web components to abstract things like this into a mixin, decorator, or other form of reusable logic. I do like how you’ve gone down a path implementing things from scratch. It means you’ll learn a lot more.

A note about the polyfills: import them from npm packages instead of static code in your repo that way you pick up bugfixes and improvements. Make a polyfill file, import each polyfill from npm packages then load the file in the head of the website.


Oh, the polyfill predicament. I am using Netlify to host my site and I am unable to access node_modules in my published directory. I was thinking of using cdnjs to serve the polyfill but wasn't sure.

Also, what you said is precisely the reason I reinvented every wheel possible lol. I wanted to learn the internals. Even my crappy SPA router! To alleviate some pain to no frameworks, I wrote some JSX factory function to build DOM nodes. But honestly, something like Readymade, even though it's so small of an abstraction, would ease development a lot.


What issues are you experiencing? AFAIK the only view in need of a perf boost is the blog, which could use some lazy loading for the images.


Ah, I think that’s a work in progress!


It looks amazing 👌😍


Seems to be unreachable in Russia:

stephenbelovarich.com refused to connect.

lemme guess, it's hosted on Netlify?


Sorry about that. It seems Russia federal censor blocks DigitalOcean I.P. as well.


What a cool interaction!


Steve, Your portfolio is very good, don't you think the hamburger size is huge?


Could be. Maybe to keep the recommended 44 x 44px hit area I should add some padding.


Looks neat. that visible scrollbar could be hidden though, while still keep it scrollable?


Hi! "The two sides of the brain..." is just a myth, please stop using this.