DEV Community

Nitipit Nontasuwan
Nitipit Nontasuwan

Posted on

Adapter - Adaptive Style Web Component Framework

Hi, recently I have created a new project call Adapter which bring CSS to the next Level with Web-Component. I'm very excited to share .
for more info: https://keenlycode.github.io/adapter/

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 {
    static css = `
        display: flex;
        justify-content: center;
    `;
}

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

WrapFlexBox.define('el-wrap-flexbox');
Enter fullscreen mode Exit fullscreen mode

This will produce CSS as

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

Enter fullscreen mode Exit fullscreen mode

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

Javascript

// Create <el-flexbox> in OOP manner.
const flexBox = new FlexBox();
document.body.append(flexBox);
Enter fullscreen mode Exit fullscreen mode

HTML

<el-wrap-flexbox></el-wrap-flexbox>
Enter fullscreen mode Exit fullscreen mode

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 {
    static css = `${bgColor('red')}`;
}

export { bgColor, RedFlexBox };
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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

<div class="componentA">
    <div><button>Button</button></div>
</div>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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.
     */
    static css = `div button { background-color: blue} `;
}

ComponentA.define('el-component-a');
Enter fullscreen mode Exit fullscreen mode

HTML

<el-component-a>
    <div><button>Button</button></div>
</el-component-a>
Enter fullscreen mode Exit fullscreen mode

Top comments (0)