Adapter

Intro

Setup

CSS like OOP 🔥

Component Isolation

Mixins & APIs

Scoped Style

Style Filtering

Introduction

What is Adapter ?


Adapter is a JavaScript framework designed to seamlessly integrate CSS-in-JS with Web Components. Setting it apart from other CSS libraries, Adapter is framework which focus is on Web Component Styling.

Despite its simplicity, Adapter unlocks endless possibilities for enhancing UX/UI in web applications. While traditional CSS frameworks have faced limitations, on the other hand, Adapter can implement features such as encapsulation, inheritance, composition, event-interaction, and other complex styling requirements which opens up new potential for creating dynamic and feature-rich user interfaces.

Examples


OOP

import { Adapter } from '@devcapsule/adapter';

class FlexBox extends Adapter {};
FlexBox.css = `
  display: flex;
  justify-content: center;
`;

/** WrapFlexBox also inhertit styles from FlexBox */
class WrapFlexBox extends Flexbox {
WrapFlexBox.css = `flex-wrap: wrap;`;

WrapFlexBox.define('el-wrap-flexbox');

This will produce CSS as

el-wrap-flexbox {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
}

Then, you can use them in html or create an instance by javascript

Javascript
// Create <el-wrap-flexbox> in OOP manner.
const wrapFlexBox = new WrapFlexBox();
document.body.append(wrapFlexBox);
HTML
<el-wrap-flexbox></el-wrap-flexbox>

Variables and Functions

Javascript
import Color from 'color';

function bgColor(color) {
  return `
    background-color: ${color};
    color: ${Color(color).isDark() ? 'white' : 'black'};
  `.trim();
}

class RedFlexBox extends FlexBox {};
RedFlexBox.css = `${bgColor('red')}`;

export { bgColor, RedFlexBox };

Variables / Functions / OOP / Modules , That's it !

CSS now is programmable with ES6 ! ... What else do we need ? 😉

What problem is the adapter trying to solve ?


One of the most common problems for CSS which is hard to implement is Style Encapsulation and Inheritance, since we can't easily make sure that element styles won't unintentionally be inherited or overridden from somewhere else.

Consider this situation where button style has been defined in one of <style> tag

<style>
  div > button { background-color: red }
</style>

If we have a component somewhere which contains <button> without using customElements

<div class="componentA">
  <div><button>Button</button></div>
</div>

In this situation, your components style might be overridden by global <style> from somewhere if you don't make CSS selector more specific like,

<style>
/* this won't work */
.componentA {
  div button { background-color: blue }
}

/* this work */
.componentA {
  div > button { background-color: blue }
}
</style>

This is just a simple example. Imagine when we have many elements and more style properties; this could be a headache and prone to causing errors in component styling, or at least it prevents us from achieving a composed style between elements/components or libraries.

Component Styling to save the world !

Web Component Styling can solve this problems, because

  1. When you use customElements.define(), it will show errors if the custom element has already been defined somewhere else, allowing you to decide how to deal with it.
  2. Defined custom elements have their own unique tags, preventing global styles from unintentionally overriding components and their elements. However, you still have full control of a component from global styles if desired, making it ideal for theming which Shadow DOM lacks this features.

Let's see how to implement CSS Styling in Adapter Component.

JS
class ComponentA extends Adapter {};

/** CSS will be isolated in ComponentA
 * Moreover, we can write CSS for this component without worrying
 * about this component tagName.
 */
ComponentA.css = `div button { background-color: blue }`;
ComponentA.define('el-component-a');
HTML
<el-component-a>
  <div><button>Button</button></div>
</el-component-a>