Lit vs Rimmel - Comparing template-tagged UI libraries
Tags: lit, javascript, webdev, frontend
Published: 2024-05-09 09:30:00

[Lit](https://lit.dev) and [Rimmel](https://github.com/hellomenu/rimmel) are some relatively similar libraries as they both make use of tagged templates.

There are some key differences which we're going to explore here

## Architecture and Programming Paradigm
Lit is a simple, lightweight library for building web components using JavaScript or TypeScript. It uses a reactive update system where changes in data trigger updates to the DOM. It leverages JavaScript template literals for HTML templating, encapsulated in its html tagged templates.
Rimmel emphasizes a functional-reactive programming approach, integrating RxJS for managing data streams. This library focuses on using RxJS's Observables, Subjects, and BehaviorSubjects to create and manage UI state and behaviors, which can lead to more declarative and predictable UI code.

## Templating and Data Binding
Lit offers a straightforward templating syntax (`html` and `css` tagged templates) and employs directives for advanced functionality like repeating templates, guarding updates, and managing attributes. It has built-in reactive data binding.
Rimmel utilises the `rml` tagged template for its HTML structure intertwined with dynamic data streams. Rimmel’s approach is highly declarative, using Observables directly within the template to manage data changes, which automatically handles subscriptions and unsubscriptions to avoid memory leaks.

## Component Model
Each Lit component is a class that extends HTMLElement, allowing the use of lifecycle callbacks and state management features provided by the web component standards.
Rimmel Components are designed as plain functions, which might appeal to developers looking for a more functional style of programming. This approach can make components easier to test and maintain.


## State Management
Lit manages state internally within components or through external libraries. The state handling is less declarative compared to Rimmel but fits well within the object-oriented paradigm.
Rimmel leverages RxJS for state management, making it inherently reactive. This method provides more robust control over state changes through streams, which can be more intuitive for developers familiar with reactive programming.


## Community and Ecosystem
Lit is backed by Google and has a larger community and ecosystem. This popularity brings more third-party tools, libraries, and plugins that integrate well with it.
Rimmel, as a newer and more specialized library, might have a smaller community and fewer resources available. However, its tight integration with RxJS could attract developers looking for advanced functional-reactive programming solutions.

## Performance
Lit is highly optimised for performance, with efficient update checks and minimal overhead for reactive updates.
Rimmel's performance depends almost entirely on the reactive streams being used, as it only binds them to DOM events and sinks. Proper use can lead to extremely efficient updates.

## Use Case Suitability
Both Lit and Rimmel are suitable for a wide range of projects. The former fits more where traditionally-structured OOP approaches are preferred whilst the latter shows it true power when creating complex interactive user interfaces.

## Action
Let's compare both with a code example: a little component with two buttons that prints "Hello" when both are clicked.

```javascript
import { LitElement, html, css } from 'lit';

class HelloButtons extends LitElement {
  static properties = {
    firstClicked: { type: Boolean },
    secondClicked: { type: Boolean },
    showMessage: { type: Boolean }
  };

  constructor() {
    super();
    this.firstClicked = false;
    this.secondClicked = false;
    this.showMessage = false;
  }

  firstButtonClicked() {
    this.firstClicked = true;
    this.checkBothClicked();
  }

  secondButtonClicked() {
    this.secondClicked = true;
    this.checkBothClicked();
  }

  checkBothClicked() {
    if (this.firstClicked && this.secondClicked) {
      this.showMessage = true;
    }
  }

  render() {
    return html`
      <button @click="${this.firstButtonClicked}">Button 1</button>
      <button @click="${this.secondButtonClicked}">Button 2</button>
      <div>${this.showMessage ? 'Hello' : ''}</div>
    `;
  }
}

customElements.define('hello-buttons', HelloButtons);
const element = document.createElement('hello-buttons');
document.body.appendChild(element)
```

Follwing is the Rimmel example, managing state exclusively as RxJS streams. You may notice how shorter did the code become as a result:


```javascript
import { BehaviorSubject, zip, take } from 'rxjs';
import { rml } from 'rimmel';

function HelloButtons() {
  const first = new Subject();
  const second = new Subject();

  const msg = zip([first, second]).pipe(
    map(() => 'Hello'),
    take(1)
  );

  return rml`
    <button onclick="${first}">Button 1</button>
    <button onclick="${second}">Button 2</button>
    <div>${msg}</div>
  `;
}

document.body.innerHTML = HelloButtons();
```

<hr>

Which programming paradigm do you prefer? Imperative or Functional? Pushing or Pulling data?