While instruments such as guitar and drums are part of a band, how they are used by the musicians define the style of the band’s music. Similarly, the elements of an application user interface connected together define the user experience. In this post as part of our ongoing series about frameworks, we are going to explore in depth the ways in which frameworks enable an overall UX design.

Many of us in software engineering look at UX design as a bit of a mystical art, populated by overtly creative people, wearing checked shirts, who get upset when the button is one pixel off from their original design, is just the wrong shade of pink, or does not have the right snap within an animation. For those in UX design, the software engineering teams may be thought of as the modern day construction workers, who never estimate anything correctly, and fail to build things as designed.

At the end of the design and development partnerships, the users of our applications have their own expectations, voiced and unvoiced, which we are trying to satiate. Our choice of framework has a significant impact on our ability to meet these needs.

Design ethos

Some JavaScript frameworks offer an overall design ethos, of how not only the UI should look and feel, but offer strong options of how a transaction is completed. Depending on your development needs, having a well designed and coherent design ethos will make it easier to rapidly provide an application which has a look and feel that is familiar and intuitive. In some cases though, your unique selling point might be the overall design of the application, providing a user experience that differentiates you in the marketplace. The ease of expressing a UX design would be of greater import to you when providing a differentiated user experience.

Customizing look and feel

Even if you adopt the supplied design philosophy, the ability to tweak the look and feel to meet your needs is likely to be a requirement. While we touched on this subject in the previous post in this series, it is good to revisit some of these concepts in the context of the entire user experience.

Design workflow

Materializing a design vision can be difficult, often with designers and software engineers speaking two different languages. How this workflow is achieved in practice will impact your delivery timelines. Do frameworks offer anything to make this process easier?

Jump to:

  • logo
  • logo
  • logo
  • logo
  • logo
  • logo

Angular 2+

Design ethos

On its own, Angular 2+ does not express any opinions on theming an application. The framework focuses on defining components from a code and template perspective and leaves the styling options to the developer.

The Material 2 project does encapsulate Google’s Material Design. Material 2 includes four pre-built themes and offers a framework for customizing and/or creating new themes.

Customizing look and feel

Assuming Angular Material is used, the look and feel of an Angular 2+ application can be customized by defining a custom theme with the SASS pre-compiler. Gesture support is provided by Angular Material’s applications by including HammerJS into the application.

Design workflow

Angular does provide guidance for how to design a user experience from the top down. Most of the documentation focuses on the implementation level. Angular components are HTML template based. HTML mockups with accompanying CSS could be a starting point for creating components, but many of the user interactions and relationship to the application likely would not be easy to express in an HTML + CSS mockup.

React + Redux

Design ethos

React focuses on the architecture of writing components and does not offer opinions on design aesthetics. There are no officially maintained libraries of React components. There are several third-party libraries that are built on top of React which do offer an opinionated design ethos.

Customizing look and feel

Styling React components is accomplished in a straightforward manner using either the className or style JSX attribute. Beyond providing these mechanisms to parse and apply styles and classes to rendered DOM respectively, React offers no mechanism to switch out component themes dynamically or to modify behavior based on device type.

Because React applications expect an ES6+ runtime environment and thus inherently rely on transpilation, it is very common to process a React application using a build tool like Webpack. By using Webpack, CSS class names can be imported into a React component and optionally localized using CSS modules; these imported class names can then be applied to specific nodes during the component’s .render() method:

MyComponent.css

.root {
    background: blue;
}

MyComponent.jsx

import React from 'react';
import styles from './MyComponent.css';

export default function MyComponent(props) {
    return (
        <div className={ styles.root }>
            { children }
        </div>
    );
}

Design workflow

A React + Redux application lends itself to a separation of concerns when it comes to design and development as well as any other JavaScript framework. Design teams can articulate their intentions in the form of mock-ups or static examples that use HTML and CSS. These mock-ups can then be translated into rendered DOM within a component and styled as necessary. Because there is no opinionated abstraction for themes, the long-term maintainability of the look and feel of a library of React components requires up-front thought and planning.

Vue.js

Design ethos

Vue.js does not express any design ethos. Its primary concern is with the structure of an application, not the look and feel. There are available third-party component libraries for Vue.js which express a design ethos.

Customizing look and feel

Vue.js provides an HTML-based template syntax and some convenience methods for managing CSS classes and inline styles on elements. However, the look and feel decisions for a Vue.js app are left entirely to the developer.

Design workflow

Vue.js itself is not concerned with the UX design process and provides no specific tools to help. Because its components are HTML template based, HTML mocks can be a starting point for the design process. Because there is no opinionated abstraction for themes, the long-term maintainability of the look and feel of a library of components requires up-front thought and planning.

Dojo 2

Design ethos

The Dojo 2 out of the box widgets are being built to a consistent user interface design. Dojo 2 has a default theme and design guidelines. The post Dojo 2.0 release has plans for at least two additional themes that can be adapted and tailored as needed.

Customizing look and feel

Dojo 2 is designed to leverage CSS modules. It also designed to leverage the postcss post processor that focuses authoring of modern CSS but down-emitting to ensure older browser support. This system allows the code to be tightly coupled with the styles it requires. The build tooling ensures that the required CSS is available at run-time and is namespaced to avoid class name collisions. The tooling also provides the necessary information to allow easy integration to the IDE. For example, you would author a CSS module and import it as you would any other JavaScript or TypeScript module, receiving code completion if using a TypeScript language services aware IDE:

MyWidget.m.css

.root {
    background: black;
}

.selected {
    color: red;
    font-weight: bold;
}

MyWidget.ts

import { v } from '@dojo/widget-core/d';
import { WidgetBaseProperties } from '@dojo/widget-core/interfaces';
import WidgetBase from '@dojo/widget-core/WidgetBase';
import * as css from './MyWidget.m.css';

interface MyWidgetProperties extends WidgetBaseProperties {
    label: string | null;
    selected?: boolean;
}

export default class MyWidget extends WidgetBase {
    render() {
        return v('div', {
            classes: [
                css.root,
                this.properties.selected ? true : false
            }
        }, [ this.properties.label ]);
    }
}

Dojo 2 also offers a theming system, which creates the concept of themeable classes versus those that are structural and therefore fixed. When a theme is then applied to the properties of a themeable widget, the classes from the theme will be substituted. An example of creating a themeable widget:

MyThemeWidget.ts

import { v } from '@dojo/widget-core/d';
import { theme, ThemeableMixin, ThemeableProperties } from '@dojo/widget-core/mixins/Themeable';
import WidgetBase from '@dojo/widget-core/WidgetBase';
import * as css from './MyWidget.m.css';

interface MyThemeWidgetProperties extends ThemeableProperties {
    label: string | null;
    selected?: boolean;
}

const ThemedBase = ThemedMixin(WidgetBase);

@theme(css)
export default class MyThemeWidget extends ThemedBase {
    render() {
        return v('div', {
            classes: [ this.theme(selected && css.selected), css.rootFixed]
        }, [ this.properties.label ]);
    }
}

And applying a theme:

index.ts

import { w } from '@dojo/widget-core/d';
import Projector from '@dojo/widget-core/mixins/Projector';
import WidgetBase from '@dojo/widget-core/WidgetBase';
import theme from './themes/dark';
import MyThemeWidget from './MyThemeWidget';

class App extends WidgetBase {
    render() {
        w(MyThemeWidget, {
            key: 'mythemewidget',
            theme
        });
    }
}

const ProjectorApp = Projector(App);
const projector = new ProjectorApp();
projector.append();

Dojo 2 makes it easy to provide support for gestures and other user input events without the developer needing to know the details of the DOM event system.

Design workflow

Dojo 2 was specifically designed to make it easier to integrate different roles in the workflow. By providing a pattern for separating structural styles from thematic styles, it is possible for the look and feel to be created independently, but work in an integrated way at design time.

Dojo 2 does prefer a functional style for describing the DOM structure of a widget. Using this style means there is no direct path from an HTML + CSS mock-up to a widget. Dojo 2 does support TSX, the JSX extensions for TypeScript which would allow an HTML-like template to be embedded in a widget.

Ember

Design ethos

Ember.js components are built with Handlebars templates, so theming and styling are left entirely up to the user. There are third-party component libraries which provide components that embody a particular design ethos.

Customizing the look and feel

Class names can be set in the template when the component is invoked, or dynamically using a bound property. Ember.js focuses on a two-way data binding methodology, therefore attributes in the template are bound to the JavaScript object and bound to values in the application.

In 2017, the Ember project created Glimmer, which is separate from Ember.js. Written and available in Typescript, Glimmer uses ES6 class syntax and eliminates the sometimes-confusing Ember configuration object.

For example, Ember.js syntax:

export default Ember.Component.extend({
  tagName: 'input',
  attributeBindings: ['disabled', 'type:kind'],
  disabled: true,
  kind: 'range'
});

And in Glimmer:

<input class="{{type}}" disabled="disabled" type="range" />
import Component from '@glimmer/component';

export default class extends Component {
  type = 'primary'
}

Design workflow

Theming with Ember.js is left entirely to the developer. Classes can be added within templates just as they would be in static HTML files, and style sheets are not integrated into the framework. There are though several third-party libraries that provide a design framework as well as user input abstractions like gestures.

Aurelia

Design ethos

While not a requirement for using Aurelia, Aurelia UX expresses an opinionated design ethos. It encourages encapsulating styles within an element and allows for data binding within styles. Aurelia UX has the concept of hosts (web, Cordova, Electron, etc.), platforms (web, iOS, Android), and design languages (Material Design, iOS Design). The host and platform are detected by Aurelia UX, and this information is all accessible from the component’s styles and can be used via the in-style data binding to tailor the component’s styles.

The Aurelia UX source code repository provides some basic components as well as the tools for providing additional styling and theming. There is an additional Aurelia UX showcase which highlights some of the functionality and components.

Customizing look and feel

Aurelia UX provides a solution for the look of components and the project team has plans to address the feel in a similar way, though it is currently a work in progress. According to the interaction, movement, and flow section of the Aurelia wiki, Aurelia UX will build on top of its components and add these higher-level features. However, while the patterns may still be in development, there is already the animator-css library for performing animations.

Here’s an example of extending the snippet in the UI section to make a themed widget

Todo.ts:

import {customElement, bindable, ViewResources, View, processAttributes} from 'aurelia-templating';
import {inject} from 'aurelia-dependency-injection';
import {StyleEngine} from 'aurelia-ux/styles/style-engine';
import {Themable} from 'aurelia-ux/styles/themable';
import {processDesignAttributes} from 'aurelia-ux/designs/design-attributes';

@inject(ViewResources, StyleEngine)
@customElement('todo')
@processAttributes(processDesignAttributes)
export class Todo implements Themable {
    @bindable public fontSize = null;
    @bindable public color = null;
    @bindable public hue = null;
    @bindable public theme = null;
    @bindable items: string[];
    public view: View;

    constructor(public resources: ViewResources, private styleEngine: StyleEngine) {}

    public created(_: any, myView: View) {
        this.view = myView;
    }

    public bind() {
        if (this.theme) {
            this.styleEngine.applyTheme(this, this.theme);
        }
    }

    public themeChanged(newValue: any) {
        this.styleEngine.applyTheme(this, newValue);
    }
}

Todo.html:

<!-- styles.todo attribute tells Aurelia UX to apply a 
    unique class to apply the theme styles to this element -->
<template styles.todo>
    <require from="./todo-theme"></require>
    <ul>
        <li repeat.for="item of items" class="
                        ${fontSize !== null ? fontSize : $todoTheme.fontSize}
                        ${color !== null ? color : $todoTheme.color}
                        ${hue !== null ? hue : $todoTheme.hue}">
            ${item}
        </li>
    </ul>
</template>

TodoTheme.ts:

import {styles} from 'aurelia-ux';

@styles()
export class TodoTheme {
    public fontSize = 'medium'; // small, medium or large
    public color = 'primary'; // primary or accent
    public hue = 'default'; // default, dark, or light
}

todo.css:

styles.todo li.small {
    font-size: 8px;
}

styles.todo li.medium {
    font-size: 13px;
}

styles.todo li.large {
    font-size: 24px;
}

styles.todo li.primary.default {
    background-color: ${background || $design.primary};
    color: ${foreground || $design.primaryForeground};
}

styles.todo li.primary.light {
    background-color: ${background || $design.primaryLight};
    color: ${foreground || $design.primaryLightForeground};
}

styles.todo li.primary.dark {
    background-color: ${background || $design.primaryDark};
    color: ${foreground || $design.primaryDarkForeground};
}

styles.todo li.accent.default {
    background-color: ${background || $design.accent};
    color: ${foreground || $design.accentForeground};
}

styles.todo li.accent.light {
    background-color: ${background || $design.accentLight};
    color: ${foreground || $design.accentLightForeground};
}

styles.todo li.accent.dark {
    background-color: ${background || $design.accentDark};
    color: ${foreground || $design.accentDarkForeground};
}

Design workflow

While it seems that Aurelia has not given specific considerations for a design workflow, it has a fairly robust system for supporting different contexts and designs within a single application. Aurelia also uses HTML templates and CSS, which can make it easy to adapt HTML + CSS mock-ups into components. The abstraction of the feel is still evolving and how that will work in practice is not completely clear at this time.

Summary

Angular 2+

If you like Google’s Material Design then Material 2 delivers on that with a fairly robust system for tailoring components and creating new ones. There is also an increasing number of third-party alternatives that can help you.

React + Redux

React is far more focused on being a toolkit and does not provide a higher order framework for UX design. There are several third-party libraries, but with varying degrees of maturity. If you are building your own UX design and have the engineering skills to build it properly, then React can be a tool to help render that on the screen.

Vue.js

Vue.js focuses on the application, often used in situations where there is an existing UI/UX that needs a modern application framework to power it. There are quite a few third-party component libraries that provide a fairly complete UX design and additional abstractions to make it easy to maintain. There are also no real limitations to building your own component library.

Dojo 2

Currently, Dojo 2 provides some strong abilities for creating and managing the look of components and the feel aspect is under development. There is an intent to make it easy to create and manage reusable libraries of components and provide the systems and patterns for managing the UX design, though that vision is yet to be fully delivered.

Ember.js

Ember.js is focused on the application. There are a significant amount of third-party components, but without an opinionated way to manage the look, integrating these components into a coherent UX design can be challenging. There are some larger libraries of components as well as libraries that allow expression of themes and user input management. Like some of the other frameworks, if the Ember.js application framework is for you and you want to create your own UX, then you will find many options to accelerate your efforts.

Aurelia

Aurelia UX provides an existing UX design as well as an advanced set of tools that allow expressing the look of components. The Aurelia UX team have expressed their intent to mature the feel aspects and Aurelia is one of the more advanced frameworks that has identified the challenges of dealing with a UX design and how to manage it in practice.

Up next

Now that we have wandered down the aisles of the local web framework shop, and may be narrowed down how we want things to look and feel, we need to go back to the basics. Especially with the rapidly changing web platform, we need to look at the frameworks in context of how they support the standards, what sort of foundational APIs they supply, and how they help make our code future proof.