DEV Community

Cover image for The benefits of Component Driven Web Development
Fredrik Söderquist
Fredrik Söderquist

Posted on

The benefits of Component Driven Web Development

The web consists of building blocks. When we decide to use <a> anchor tag in our HTML code we expect it to behave as a link, looking all nice and blue (or purple once visited), showing a little hand cursor when hovering the mouse pointer, getting tab focus when active and most importantly taking the user to a new URL when clicked. All this without the need to write any styling or logic our selfs. The same thing applies with any other HTML element such as buttons, input fields, headings, paragraphs etc. These have both a semantic and syntactic meaning, making the HTML code easy to write, read and understand.

By combining sets of HTML tags, some text content, class names and other attributes we can define our own patterns of how we want our HTML to look and behave using CSS and/or JavaScript to change the default look and feel. This sometimes results in really complex structures, with even more complex stylesheets and JavaScripts, which developers needs to understand in order to generate the correct markup to get the expected behaviour within the UI framework.

Keeping all this information in the head of the developer (or in some cases developers), might work fine during the early stages of developing a new website, when it seems to be working together great and everything is unicorns and rainbows. After a while though, the framework usually needs to be modified, due to design changes, when bugs are found in some legacy web browser or just because the preconditions might change. No problem, our developer is such a mastermind he/she can make minor changes to some CSS-classes, JS statements or HTML syntax to make framework adopt to the new conditions. After several iterations of these little unexpected changes in the framework, the clear structure and readability of the code is no longer as clear as before. Other developers are starting to back away from making any changes, since it might just break something (again). And you feel more and more dependent on your developer mastermind who (everyone agrees) is now the sole ruler of the framework.

When this happens in development we usually use the term technical debt. Technical dept is the cost of the gap between working code and maintainable (readable) code, which grows with every minor “solution” you do, which might make some future change harder to do. Most development projects are under strict timelines and during an agile process, with many changes in design or functionality along the way and with everyone focusing on how many hours you spend and that holy grail launch date. The technical debt just keeps creeping in and might feel impossible to avoid.

Avoiding the debt

The secret of maintainable code, is not as big a secret as you might think. Just as with most things in web development, the best way of getting better control is by breaking it down in smaller, more clearly defined components. Instead of having big JavaScript functions doing many things, you break it down into several smaller pure functions, all just doing one thing. This is the approach of functional programming, the smaller the function, the smaller the bugs and the easier they are to fix. The same principle can be applied to the entire stack of JavaScript, CSS and HTML of your front end framework.

Lets go though how to do this, one part at the time.

ES6 modules

JavaScript has with the EcmaScript 2015 standard introduced the concept of (ES6) modules, which basically is a way to import specific functions from other files. With these modules we can easily separate our JavaScript functions into separate files with one single purpose each, making it easier to find, read and modify the content of any single file.

Each module can define a single default function to export, to be the public API for other files to use the module. As long as this function‘s arguments stay the same and it´s expected output is maintained, the content of each module can easily be modified or updated without causing any other part of the application to break.

import myCustomEventHandler from '../helpers/customEventHandler';
/** Sets the variable myCustomEventHandler to the default exported function in "../helpers/customEventHandler.js" which later can be called just as a local variable myCustomEventHandler(…);
**/
export default function mySpecialComponent (el, options) {…}
/* Exports the function mySpecialComponent as default function for others to import */
Enter fullscreen mode Exit fullscreen mode

To dive deeper into ES6 Modules take a look at: http://exploringjs.com/es6/ch_modules.html

Since ES6 modules are part of the EcmaScript 2015 standard, it is not yet implemented in several browsers, and might need some help to get it working everywhere.

Babel

Babel (formerly known as 6to5) is a transpiler, translating futuristic looking code like EcmaScript 2015, to EcmaScript 5 (cross browser compatible JavaScript). Besides ES6 modules, Babel makes it possible to use other EcmaScript 2015 features like; const, let, arrow functions, destructuring, spread operators, map(), forEach(), filter(), reduce() and much more. To look into all the glory of EcmaScript 2015 go to http://exploringjs.com/es6/ and https://babeljs.io/.

Now that we have broken down our JavaScript in tiny clearly named and defined files, let´s look what we can do with out stylesheets.

BEM — Object Oriented CSS

BEM has become a widely popular syntax to achieve Object Oriented CSS, by suggesting a naming standard of class names in HTML to define and style; Blocks (components), Elements (component sub elements) and Modifiers (component variations) separately.

The idea of object oriented CSS is to create descriptive, single purpose class names which makes it crystal clear, what each class name is and where it is defined. A BEM class should only be used for styling, and never is used for unrelated styling or used to bind JavaScript to the DOM, since it causes unclear dependences. As with ES6 modules for JavaScript the idea is that since each class name is used for a single purpose only, changing or updating its definition will only affect the intended element with it´s intended purpose.

Block class names refer to the component name and is usually used for the wrapper element of any given component block.

.MyComponent {} /* Block class name */
Enter fullscreen mode Exit fullscreen mode

Element class names are used to define related sub elements which belongs to the block component.

.MyComponent-header {} /* Sub element class name */
Enter fullscreen mode Exit fullscreen mode

Modifier class names are versions of the block class name used for variations of the default block style.

.MyComponent--wide {} /* Modifier class name */
Enter fullscreen mode Exit fullscreen mode

By defining all modifiers on the Block, elements can be styled differently under each modifier. But it is clear which modifiers are available from reading the CSS.

.Component--wide .Component-header {} /* Element class name with block modifier */
Enter fullscreen mode Exit fullscreen mode

I prefer using the SUIT syntax (https://suitcss.github.io/) which is a popular implementation of BEM using PascalCase naming.

By making all styles of a specific component part of the same block class the component can be completely independent from other framework styling, making both debugging and development much easier.

Variables and utility classes

Some styling doesn’t make sense to repeat in every single component, like colors, typography, spacing, layouts, breakpoints, animations etc. In cases like this we can use global variables which components in turn can use, for instance:

:root {
  --color-deep-blue: #000080;
}
/* And then later used like this */
color: var(--color-deep-blue);
Enter fullscreen mode Exit fullscreen mode

In some cases it might suit you better with specific utility classes, which are single element classes with a single, very specific purpose. Like setting viewport specific styles or a certain typography.

<p class="text-small s-max-hidden color-dark-red">Example of utility class names defining a certain small typography, with red color which is hidden on small viewports.</p>
Enter fullscreen mode Exit fullscreen mode

Utility classes and variables with good names, make it clear for a new developer exactly which styles apply to any given element and makes it easier to update a component or change utility classes without causing new bugs elsewhere.

PostCSS

CSS variables are a relatively new standard which is not yet implemented in all browsers (and are not available between files), but by using a transpiler for CSS (just like Babel for our JavaScript) we can use these features today.

It also makes it easy to write clean standardized CSS and trusting PostCSS to manage variables, vendor prefixes, calculations and custom breakpoints and bundle all your CSS files together.

To start using PostCSS checkout http://postcss.org/ and http://cssnext.io/.

HTML Templates

One of the biggest issues when maintaining a big framework is managing all implemented HTML code in the website. In many cases a fix, a bug or a design update in one part of the website, may result in changes to the markup. Changes of HTML is usually a big forbidden no no, making redesigns and bug fixes almost impossible, since the HTML needs to be updated in (sometimes) hundreds of places throughout the application.

Most server side implementations use some sort of templating language to generate the HTML to the client, usually with a little too much logic and back end functionality, to represent something like component design. But imagine if you could separate the logic layer of an application from the presentational layer, allowing the back end focus on just generating data for pure design templates.

There are a lot of templating languages, all with their own set of features and limitations, but most focus on the same thing; generating HTML from a set of data variables. Many even have support in multiple platforms and back end languages, making it possible to build HTML templates which could run just as well on the client with a static JSON file as on the backend with live database content.

One of the most important feature of a templating languages, in regards to component driven development, is the use of template partials.

Template partials is a way to include other template files as part of the page. By implementing support for the the server to use template partials, instead of writing HTML, we can modify any template partial without any changes needed to the back end. And all changes to the template will be implemented everywhere the partial is used.

One of the most simplistic templating languages with support in almost any platform is Mustache (https://mustache.github.io). But I prefer, when possible, it´s closely related, but a bit more sophisticated cousin Handlebars (http://handlebarsjs.com).

Handlebars

Handlebars is a implementation of Mustache with some extra functionality thrown in making it easy to use and customize for each project’s specific needs. Handlebars have a strong (sometimes unofficial) support for server side languages, usually a bit more restricted than the JavaScript version, but definitely good enough in most cases.

Just like we have broken down our JavaScript and CSS in smaller modules, we can easily write Handlebars templates for each of our components and make them configurable using different sets of data variables.

Handlebars uses, just as Mustache, the curly brackets to define variables {{myVar}}, block helpers {{#each myArr}}…{{/each}} and template partials {{> MyComponent}}.

<section class="Component {{#each modifier}} Component--{{this}}{{/each}}">
  <header class="Component-header">
    {{#with title}}
      {{> Title class="Component-title"}}
    {{/with}}
  </header>
  <div class="Component-content">
    {{#each content}}
      <p class="text-plain">{{{this}}}</p>
    {{/each}}
  </div>
</section>
Enter fullscreen mode Exit fullscreen mode

Writing a simple json data structure for each template, we can render our templates to make sure they work nicely together with the CSS and JavaScript but also define the expected data the back-end needs to implement to use the component correctly.

{
  "modifier": ["wide"],
  "title": "My awesome component",
  "content": [
    "Hello component",
    "i dig your style"
  ]
}
Enter fullscreen mode Exit fullscreen mode

File structure

Now we have separate files for our JavaScript, CSS, templates and JSON, we just need a place to put them. Since they all are related to any specific component, why not just put them all together. The nice thing working with html, css and js in the same folder, is that if you name the files index.css, index.js or index.html they will be assumed the default file when importing the folder from other files. This way by using an import statement in CSS or JS importing the component folder will fetch the correct index file.

In JavaScript we can include a component like this.

import MyComponent from '../components/MyComponent';
Enter fullscreen mode Exit fullscreen mode

And in CSS

@import url('../components/MyComponent');
Enter fullscreen mode Exit fullscreen mode

This is easy to implement in handlebars as well making it possible to just include the component folder name, to use the actual index.hbs file.

components/MyComponent
  - index.css
  - index.js
  - index.hbs
  - default.json
  - readme.md
Enter fullscreen mode Exit fullscreen mode

Now I guess you are imagining the chaos in your code editor with index files everywhere. And I won’t lie, it is hard to trust your editor tabs, but most modern editors have easy quick-find functionality making it simple to jump between files, based on the directory name.

The other exciting part of getting a standardized structure of your components, is that it is now really easy to build a parser to read all the files and present them in a styleguide like component library and I will come back to this later.

There are different kind of components. Some are small and reusable, some are cumbersome and only used once, and some might not even have any template files just CSS or JS, like the utility classes we talked about under the CSS section.

In my projects I have set up a folder structure for different kinds of components as this.

/base contains the fundamentals in the design such color, typography, animations etc. These components are mostly utility components, defining CSS variables and styling utility classes.

/components contains all reusable common components which (in theory) can be used anywhere in the application.

/modules contains the components which are more complex and usually used once or twice, like PageHeader and PageFooter.

/helpers contains helper components which can be used by other components, this can be handlebars loop partials or mostly JavaScript functions not tied to any specific component.

/views contain the components or combination of components used to create the page templates.

/layouts contain the one or several root document template used by all or most view components.

What we now have is an architecture of UI components, independent from any back-end implementation. But easily used by almost any server side language with just some minor path configurations. I hope you can realise the strength in managing the UI completely separate from the back end. It means that as long as the backend prepares the data correctly for the components, the components can be modified and updated in parallel with the server implementation leaving those waterfall processes back in the past, where they belong.

To work with these components, separate from the back-end, we need a simple prototype server, rendering the components with our json data.

Getting the prototype up and running

With a component structure as described, all we need is a file parser, template renderer and HTTP server to make our folder structure into a working prototype.

You can do this in any server side language, but as front end developer I prefer to do it using NodeJS.

With nodeJS, I can set up a KoaJS (http://koajs.com/) server rendering handlebars and configure the paths to my component folders. Then I can setup URL rules so they coincide with the names of my view components. But instead of me walking you through how to set this up step by step, I have as any good TV chef, prepared it for you.

Living Design System

We call it a Living Design System since it’s core goal is to create a design system which actually survives the website launch. It is a tool to run a parser, server and styleguide which will render exactly same UI code as the server implementation, and it gives you some nice other tools just as a bonus.

It is developed by me and my colleagues at Daytona Sthlm (daytona.se). It is 100% open source and can be downloaded and used for free, with the knowledge that it is still in early beta, and changes might still occur between versions.

Install Living design system (LDS for short) using npm.

$ npm install -g @daytona/living-design-system
Enter fullscreen mode Exit fullscreen mode

This will install LDS globally on your machine, making the namespace “lds” globally available and allowing you to start up a project anywhere without installing any additional packages in your project. Once the packages are installed, create a new folder and run:

$ lds init
Enter fullscreen mode Exit fullscreen mode

This will set up a new project with the setup we just went through.

And running:

$ lds watch
Enter fullscreen mode Exit fullscreen mode

will fire up a server running a simple startpage on http://localhost:4000, and a styleguide on http://localhost:4000/styleguide. The watch command will start up the server, transpile and bundle your assets and watch your files for any changes and automatically re-parse and reload your browser or stylesheet link on any file change.

Please give it a spin and create som components and views of your own and see how component driven development suits you.

This is a setup I feel comfortable with, but it is completely free to configure your own preferences for working with CSS, JS, Images and Template languages. To read up on what LDS does and how to configure it, look at https://www.npmjs.com/package/@daytona/living-design-system.

For further inquires on using LDS in your organisation to gain control over the digital brand and present it in a practical styleguide, please don’t hesitate to contact me personally.

In summary

Breaking down the UI in components makes good sense since it makes reading, developing and updating the code much easier. If you want to change or replace a component it is just the files in the component directory that affect how the component looks and behaves.

We can even develop and test components in isolation from others to make sure they work as expected in all devices under different sets of data.

Each component can consist of its own CSS with a BEM syntax making it easy to understand, a ES6 JavaScript module which has a clear purpose and only exports what is needed to initialize the component. We also encapsulates the HTML in a template partial, making the back end implementations a UI user, instead of the UI owner. And by adding some additional info like example data, documentation, configuration schemas and screenshots, we can present a nice looking style guide with all the information needed to understand how to use, develop and extend the components.

By taking control of the UI development and maintenance, you might just succeed in having a UI library which survives your next website launch.

If you just want to try it out for yourself, be my guest and head over to https://www.npmjs.com/package/@daytona/living-design-system and you will hopefully realise why this is a good idea.

Top comments (2)

Collapse
 
link2twenty profile image
Andrew Bone

Polymer makes web components easy (and backwards compatible), large companies like EA use it to quickly release sites for their new games.

polymer-project.org/

Collapse
 
fregu profile image
Fredrik Söderquist

That is true, but Polymer still requires client side rendering of components, if Im not mistaken. And that is still a dealbreaker in many projects.