Skip to content

material design

For now it totally went with material components for the web.

  • Because it's from google, which invented material design
  • It's the successor of material design lite, which I used before.
  • It has good constructs for building modules

Material design : material_design Material components for web : material_web Material components architecture : material_components

architecture

MDC Web is split into packages which can be either:

  • subsystems: usually some css style or motion
  • component: bound to a html component

Components tend to rely on subsystem packages, but rarely on other component packages.

Each component should be usable separate from any other component.

Subsystems

Subsystems usually end up altering css , and use sass for that, each package compiles it's sass files into a single .css file.

Components

components have two pieces:

  • Foundation: this is to reuse foundation code across multiple systems like react or angular.
  • Adapter: this is an interface with all the foundations methods, there can be many implementations of the adapter.

The relation between the two is : Foundation has-a adapter.

getting started

On the website, the example to build is a component called redblue-toggle. This is a very simple button that alternates between the two colors.

It is advised to code the component as a simple prototype, not worrying about turning it into a foundation yet.

You can view a running example at codepen : redblue_start

The important code snippets are :

red blue example
1
2
3
4
5
<main>
    <div class="redblue-toggle" role="button" aria-pressed="false">
        Toggle <span class="redblue-toggle__color">Blue</span>
    </div>
</main>

This is the entry within your html page, the "redblue-toggle__color" class will bind to the toggle functionality. This is the prototype for that :

prototype
class RedblueTogglePrototype {
    get toggled() {
        return this.root.getAttribute('aria-pressed') === 'true';
    }

    set toggled(toggled) {
        this.toggle(toggled);
    }

    constructor(root) {
        this.root = root;
        this.clickHandler_ = () => this.toggle();
        this.initialize();
    }

    initialize() {
        this.root.addEventListener('click', this.clickHandler_);
    }

    destroy() {
        this.root.removeEventListener('click', this.clickHandler_);
    }

    toggle(isToggled = undefined) {
        const wasToggledExplicitlySet = isToggled === Boolean(isToggled);
        const toggled = wasToggledExplicitlySet ? isToggled : !this.toggled;
        const toggleColorEl = this.root.querySelector('.redblue-toggle__color');
        let toggleColor;

        this.root.setAttribute('aria-pressed', String(toggled));
        if (toggled) {
        toggleColor = 'Red';
        this.root.classList.add('redblue-toggle--toggled');
        } else {
        toggleColor = 'Blue';
        this.root.classList.remove('redblue-toggle--toggled');
        }
        toggleColorEl.textContent = toggleColor;
    }
}

new RedblueTogglePrototype(document.querySelector('.redblue-toggle'));

CSS is :

style
:root {
    --google-red-300: #E57373;
    --google-red-900: #b71c1c;
    --google-blue-300: #64b5f6;
    --google-blue-900: #0D47A1;
}

.redblue-toggle {
    font-family: sans-serif;
    display: inline-block;
    padding: 8px;
    border-radius: 4px;
    cursor: pointer;
    user-select: none;

    background: var(--google-red-300);
    color: var(--google-blue-900);
}

.redblue-toggle--toggled {
    background: var(--google-blue-300);
    color: var(--google-red-900);
}

/* Superfluous styles below */

html, body {
    margin: 0 auto;
    height: 100%;
}

main {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
}

So this would tie the button to the code in this line :

code
new RedblueTogglePrototype(document.querySelector('.redblue-toggle'));

To make this applicable to different frameworks we need to split it into one Foundation and (possibly) more adapters. The example takes a sub step by replacing interface functions with lines like :

toggle
1
2
3
4
5
6
7
8
9
get toggled() {
    return this.root.getAttribute('aria-pressed') === 'true';
}

// altered to :

get toggled() {
    return SOMEHOW_GET_ATTRIBUTE('aria-pressed') === 'true';
}

Then this fake function is mapped onto an Adapter method signature :

SOMEHOW_GET_ATTRIBUTE(attr: string) => string getAttr(attr: string) => string

I leave this for now, since I realize this is not what I expected it to be, nor do I need it. These are not modules as i want, but these are for creating components fitting multiple framework. I will definitely choose 1 framework and also the only one to use it. .. maybe later.