Sass in the Real World: book 1 of 4

Modules and UI patterns

Now that we have established the architecture for our UI foundation, it is time to start assembling some modules. In essence, modular Sass is an assembly of foundational elements with only enough additional presentational Sass to hold it together. The use of elemental styles to build a module is strongly encouraged; while defining new elements in the scope of building a module is strongly discouraged.

A module's Sass is exclusive to a particular interaction of the application. Modules will come in all shapes and sizes, while larger modules may also consist of smaller modules or UI patterns.

UI patterns are subject to personal interpretation. In practice when engineering modules, from one to the next, UI patterns will emerge. It is practical to try and encapsulate these smaller patterns for reuse, but I don't lose sleep over them.

Module

A module is a singular functional deliverable and will be unchanged in form, functionality and content. Examples are site header, main navigation and footer.

One could argue that a module is engineered as a 'plug-n-play' element. Taking the main navigation for example, there would be no good reason why you would want to re-purpose this UI element and functionality in another module? That would be very confusing to your users. Your functional code, your Sass and your application should represent this as a singular modular object.

UI Patterns

UI Patterns, on the other hand, are representations of assembled UI elements. Dialog boxes are a great example. These patterns consist of design elements such as, typography, arrangement, color, border and spacing. These patterns can be re-purposed again and again throughout the application/site. But the content and functionality of this pattern are subject to redefinition based on use.

The module file structure

Module and UI patterns are directories unto themselves. An exploded module directory may look like the following:

|- sass/
|--- modules/
|----- registration/
|------- _extends.scss
|------- _functions.scss
|------- _mixin.scss
|------- _module_registration.scss
|------- _module_personal-info.scss
|----- purchase/
|------- _extends.scss
|------- _functions.scss
|------- _mixin.scss
|------- _module_summary.scss
|------- _module_purchase.scss

The idea here is that while engineering modules you may need to create complex functional Sass that is exclusive to a module. While I strongly encourage making UI logic as abstract as possible and available to the whole app, this process discourages the practice of creating junk-drawers.

Keeping these logic files close to the actual use-case helps maintain clean organization of your code. As shown in the example above, a primary module may consist of smaller modules. As a naming convention, I will name the primary module Sass file after the name of the directory prefixed with module_. For example: _module_registration.scss. Any sub-modules in this directory will simply be named by the purpose in which it serves, _module_personal-info.scss for example.

Sub-modules of a UI in many cases will contain similar characteristics. This close relationship between a module's functional Sass and it's presentational Sass also serves code reuse and management purposes. Take for example the use of a silent placeholder. In the extends.scss file you may engineer a reusable UI module that utilizes several variables. In the corresponding presentational Sass module file you can @extend this UI while resetting some of the default variables.

All modules should be name-spaced by the semantic name of the module itself. .registration {} or .purchase {} for example. If the sub-module is exclusive to the primary module then it would extend the name like so, .purchase_summary {}.

Keep in mind that at the level we are working at it is scoped to the module itself. Keeping the selectors shallow will encourage reuse throughout the application without causing additional engineering. If you find yourself engineering complex UIs within the module, this may be an opportunity to abstract into a mixin or silent placeholder selector.