Web user interfaces have become much more complex than they were a couple of years ago. Complex SPAs using multiple vendor widgets needing to work with open source widgets etc., are taxing developers and taking a toll on their productivity. There is a need for a development paradigm that frees developers from this grinding exercise and makes developing web applications a fun experience. Enter Web Components. Web Components is a w3c specification. It helps developing web UI applications in a modular way.

In this article, I explore the use of web components for a non-trivial web UI application, like a To-Do web application. Additionally, I’ll also use a state machine so the resulting application is more robust than otherwise. In a previous article, I presented a state machine based web UI development approach using vanilla JavaScript. It was shown that the resulting application was very modular. The modular nature of the approach naturally leads us to use web components.

State Transitions

The approach proposed here suggests we first write a set of state transitions for our UI application. So for the To-Do application which has a screen mock-up like:

Example to-do app

I assume that the following are the required state transitions.

Initials State Pre-Event Processor Post-Event Final State
unknownState onload processOnload() onloadSuccess readyForAdd
readyForAdd addTodo processAddTodo() addTodoSuccessNoneSelected readyForAddSelect
readyForAddSelect addTodo processAddTodo() addTodoSuccessNoneSelected readyForAddSelect
readyForAddSelect changeTodo processChangeTodo() changeTodoSuccessSomeSelected readyForAddSelectUnselectDelete
readyForAddSelect changeTodo processChangeTodo() changeTodoSuccessAllSelected readyForAddUnselectDelete
readyForAddUnselectDelete addTodo processAddTodo() addTodoSuccessSomeSelected readyForAddSelectUnselectDelete
readyForAddUnselectDelete changeTodo processchangeTodo() changeTodoSuccessNoneSelected readyForAddSelect
readyForAddUnselectDelete changeTodo processchangeTodo() changeTodoSuccessSomeSelected readyForAddSelectUnselectDelete
readyForAddUnselectDelete deleteTodo processDeleteTodo() deleteTodoSuccessAllDeleted readyForAdd
readyForAddSelectUnselectDelete addTodo processAddTodo() addTodoSuccessSomeSelected readyForAddUnselectDelete
readyForAddSelectUnselectDelete changeTodo processChangeTodo() changeTodoSuccessAllSelected readyForAddUnselectDelete
readyForAddSelectUnselectDelete changeTodo processChangeTodo() changeTodoSuccessSomeSelected readyForAddSelectUnselectDelete
readyForAddSelectUnselectDelete changeTodo processChangeTodo() changeTodoSuccessNoneSelected readyForAddSelect
readyForAddSelectUnselectDelete changeTodo processChangeTodo() changeTodoSuccessSomeSelected readyForAddSelectUnselectDelete
readyForAddSelectUnselectDelete deleteTodo processDeleteTodo() deleteTodoSuccessNoneSelected readyForAddSelect

Note that I have identified four application states: readyForAdd, readyForAddSelect, readyForAddUnselectDelete, and readyForAddSelectUnselectDelete. The state readyForAdd, for instance, implies only add events can be emitted from this state, while the readyForAddSelect state can only emit add and select events, etc.

The steps for the UI development include:

  1. Set up an HTML layout file for the UI application identifying the locations for the custom elements to be backed by the web components.
  2. Add script tags to the HTML file to reference the web component files.
  3. Configure the states and events identified above in the application-specific JavaScript.
  4. Write code in the processor() functions to communicate with the web components via the corresponding custom elements.
  5. Add the state machine controller code.

1. To-Do application Web UI Layout Template

The web UI template corresponding to the above mock-up that will be using for our To-Do app is:

This template is not to be confused with the HTML Template feature of the Web Component specification. The above is just a UI layout for our application. Note that I have identified three custom element tags usage — input-comp, checkbox-group-comp and button-comp. The attributes used in these tags follow the APIs published by the corresponding web components. 

For our demo purposes, I am using the data-request and data-response pattern so we can send the data (JSON) to the web component at the data-request attribute and get a JSON response at the data-response attribute. Also note the script tags for the JavaScript files — input-comp.js, checkbox-group-comp.js and button-comp.js.

2. Web Components

The source for the three web components are:


Note that for brevity of discussion, I am not using the Shadow DOM feature of web components.


The CheckboxGroupComp class handles three actions — create, delete, and update. After the action is performed, it writes back the items count and selected items of the checkbox group to the data-response attribute.


3. Events and States Configuration

The events and states identified in the table above can be configured using JavaScript const objects.

The states are configured in todoApp.js like:

The appStates object sets the visibility status of the various components. So, it acts as a “View” in the MVC pattern.

The events are configured in todoApp.js like:

Note that I have used the nextState() function in the appEvents object instead of in the appStates object since we see that only an event knows what the next state should be. Also, note that the process() functions are used for the pre-events, and the nextState() functions are used for the post-events. This, again, follows directly from the state transitions table. 

4. Processor Functions

It is interesting to note that the process() functions communicate with the custom element tags by posting their JSON data to the data-request attribute and collect a JSON response at the data-response attribute. The processor functions read the JSON data stored in the data-response attributes using a utility object, called appData.

The source for appData (defined as a const in todoApp.js):

The above appData object acts as a “Model” for the MVC pattern.

5. Controller

The engine of our state machine consists of these simple controller functions (in todoApp.js):

The handleAppEvent() function listens and receives all the HTML DOM events (pre-events), including those raised by the web component. Note that even if Shadow DOM is used, we can still receive the events at the custom element (see Eric Bidelman). The callback function, handlePostEvent(), handles all post-events. 

Note that for brevity of discussion the CustomEvent that is created above is used merely as a data transfer object and routed to the appropriate process function via the stateTransitionsManager()  function. If these custom events are dispatched then all the process() functions should be updated to listen to these events.

How One Transition Works

When the user performs an action on the screen the following steps are triggered:

  1. HTML DOM event (pre-event) is captured in the handleAppEvent() function.
  2. This event is wrapped in a custom event and sent to the stateTransitionsManager().
  3. The stateTransitionsManager() uses the appEvents configuration and calls the required processor function passing it a callback function.
  4. The processor function communicates with the required web components and determines and creates a custom event (post-event) and passes it to the callback function, handlePostEvent().
  5. The handlePostEvent() function uses the appEvents configuration and calls the  nexState() function.
  6. The nextState() function uses the appStates configuration to set the visibility status of a web component.
  7. The screen is now ready to receive the next user action.


A demo of the application is available at TodoApp. As the user walks through each transition listed in the table above, they can also view the result of each step on the same page as a log message. 


All the source for this article is available for download in GitHub.


A new approach to developing web UI applications using the state machine and MVC patterns is proposed. The approach is demonstrated for developing the TodoMVC application. Use of the Web Components is shown to further enhance the modular nature of the resulting application. 

A uniform mechanism to communicate with the web components via data-request and data-response custom element attributes is found to enable state transitions as per the design. The state transitions table is shown to serve as a requirements aid, a development aid, and as a test case aid.

Related Works:

Readers interested in exploring the use of web components for the To-Do app can checkout Polymer TodoMVC. Readers interested in using the Shadow DOM feature of the web components specification can checkout this video — Web Components: It’s about Time.

Source link

Write A Comment