DEV Community

Cover image for Ardi: Welcome to the Weightless Web
James Lovallo
James Lovallo

Posted on • Updated on

Ardi: Welcome to the Weightless Web

πŸ‘‹πŸ» Hi all, this is my first post here. Be nice 😝

I've been working on a new Web Component framework called Ardi. Ardi packs a ton of features into a tiny 3kb package.


Features

  • Reactive props
  • Reactive state management
  • Declarative rendering
    • Conditional rendering
    • Loops (supporting keyed elements)
    • @event handlers in the template
    • FAST rendering thanks to Β΅html
  • A ready() helper to handle effects after the initial render
  • A intersect() helper to handle effects after the component is scrolled into view, i.e.
    • Lazy-loading data
    • Scroll-triggered animations
  • Works out-of-the-box with React, Vue, Svelte, Angular, etc
  • Allows developers to bring their own templating library, i.e. Handlebars or JSX.

Goals

The question you're probably already asking is "for f***'s sake, why do we need another web component framework?" and that's a really good question. I had a few specific goals in mind when I started working on Ardi.

  1. Make web components fast
  2. Make web components fun and familiar
  3. Make web components work with any existing framework

1. Make web components fast

Though I love custom elements, there are a few issues that make them problematic for production work.

CLS

Challenge: Client-side custom elements either 1) cause horrible CLS when they load or 2) need to block rendering until they are loaded to prevent CLS. Solution: That means the framework itself needs to be tiny and fast itself. Compressed and minified, Ardi is only 3kb, and you can load it from NPM or a CDN.

Efficient Rendering

Challenge: With declarative rendering in other libraries, oftentimes entire DOM trees are re-painted because of simple prop or state changes that could have been handled faster by imperative DOM manipulation. I wanted a framework that, like Lit, only updated content or attributes that had changed instead of re-painting entire DOM elements and trees. Solution: I chose Β΅html for the default templating system because it accomplishes this goal and other advanced templating features in a tiny bundle size. To make rendering even faster and smoother, I throttled uhtml's rendering using requestAnimationFrame.

In the devtools on the right, notice how the whole element isn't re-painted, just the parts that have changed.

Image description


2. Make web components fun and familiar

I wanted a simple and modern DX that lets me start exploring a new idea quickly without typing a bunch of boilerplate code first. I also wanted to make it easy for developers to bring their favorite templating systems like Handlebars or JSX.

Boilerplate

Challenge: Many of the current web component libraries make you import and extend classes, write opinionated boilerplate code and manually define the custom element. Solution: Reduce boilerplate code as much as possible.

State Management

Challenge: Custom elements do not provide any state management solution. State management is a huge part of what makes modern frameworks modern and is an essential component of declarative rendering. Solution Ardi provides its own reactivity solution in the form of this.state.

ardi({
  component: 'keyboard-demo',

  state: {
    recording: false,
    tracks: [],
  },
})

Enter fullscreen mode Exit fullscreen mode

In the example above, the component's state contains a "recording" boolean and a "tracks" array. When this.state.recording is set to true, any note played on the keyboard is saved with a timestamp into a new array. When recording is set to false, the array of recorded notes is saved into the tracks array. When this.state.tracks is updated, the list of recorded tracks at the bottom of the component is updated immediately, just like you would expect if you were using React, Vue, or similar.

Learning Curve

Challenge: I've worked with a lot of developers who are very opinionated and passionate about one templating system, and who are therefore reluctant to try out new frameworks or new standards like custom elements. Solution: Ardi is very unopinionated and allows you to easily override the default render() function to support other templating libraries like Handlebars or JSX (click those links for demos).


3. Make web components work with any existing framework

The true magic of web components is being able to build them once and use them anywhere, but there are still some limitations to the API.

Reactivity and Interoperability

Challenge: Properties are not the same thing as attributes. When you (or React, or Vue) update an attribute on a custom element, nothing happens. That change is not reflected in the component's properties. Custom elements do provide an observedAttributes getter and attributeChangedCallback, but it is cumbersome to 1) define observed attributes, 2) recognize when those attributes have changed, 3) get the value of the attribute, 4) convert that value from a string to another data type, and 5) update the template appropriately. Solution: Make it easy to create reactive props, each of which has a setter function and an optional default value.

ardi({
  component: 'keyboard-demo',

  props: {
    instrument: [(v) => (v === 'sitar' ? 'acoustic' : v), 'piano'],
    octaves: [Number, 2],
    start: [Number, 3],
    sustain: [Number, 2],
  },
})

Enter fullscreen mode Exit fullscreen mode

In the example above, if the "octaves" attribute is changed on the element, this.octaves will also be set to the value of Number(this.getAttribute('octaves')) and the template will be updated. If this.octaves is changed, the attribute will also be updated, along with the template. Data is kept perfectly in-sync.

Ardi ❀️ React

Ardi ❀️ Vue


Check it out!

If you're looking for a lightweight, un-opinionated and highly-optimized web component framework, I'd encourage you to check out the docs, play with the demos, or try it out in the playground.

If you like Ardi, like this post or give it a star. If you have an issue or you're interested in contributing, feel free to open an issue or create a pull request.

Top comments (0)