One of the most difficult aspects about building a UI framework that is flexible enough to meet the ever-changing demands of a large scale application is to provide a way to build advanced UI's by combining multiple components. The challenge lies in that a component must control all of its own aspects, while being un-opinionated enough to allow other components to appear within. To show this through an example, let's take the avatar component. Looking at the markup below, the avatar doesn't have a lot of complexity:
<div class="iris-avatar" data-size="large"> <div class="iris-avatar__inner"> <img class="iris-avatar__image" alt="Avatar" src="URL" /> </div> </div>
While not obvious at first glance, the key to this component is that the
iris-avatar class is completely un-opinionated and serves only as a generic wrapper for the content. Conversely the
iris-avatar__inner class is very opinionated and handles the
padding, and scaling of the image. This is important because the avatar component is built to have another component appear within it, and it needs to keep a separation of concerns so to speak. Let's look at a more advanced example of the avatar:
<!-- Avatar Component --> <div class="iris-avatar pos--relative" data-size="large"> <!-- Badge Component --> <div class="iris-badge iris-badge--circular iris-badge--info" data-position="top-right"></div> <!-- Avatar Specific Content --> <div class="iris-avatar__inner"> <img class="iris-avatar__image" alt="Avatar" src="URL" /> </div> </div>
Because of how the avatar component is structured, it allows a second component (in this case, badge) to live side by side with the avatar specific content. This is a cornerstone in the philosophy and structure of the Iris library as a whole. Let's dive a bit deeper into this concept.
When one component appears within another component, we call this "nesting" components. In the previous example, the badge was able to be "nested" inside of the avatar component and both were able to control the aspects they needed to. Almost every Iris component is built with nesting in mind and some are even unable to exist in a standalone fashion, and require components to be nested in them to be useful. Let's take a card for example:
<div class="iris-card iris-card--shadow"> <div class="iris-card__header"> // Header Content </div> <div class="iris-card__content"> // Body Content </div> <div class="iris-card__footer"> // Footer Content </div> </div>
The iris-card at its basic, is a shell with minimum styling to enable a myriad of permutations to be built. It has a header section with the option of a title, a content section that has a bit of
padding, and a
footer section that has some
margin between the rest of the areas. Without any content added in, the card appears as a white box (like above), with a border around the edges. Let's look at a card that has nesting:
Upgrade Your Account
<div class="iris-card iris-card--shadow"> <div class="iris-card__header"> <h4 class="iris-card__title">Upgrade Your Account</h4> </div> <div class="iris-card__content"> <!-- Checkbox Component --> <!-- Account Component --> <!-- Checkbox Component --> <!-- Account Component --> </div> <div class="iris-card__footer flex-justify--end"> <!-- Button Component --> <!-- Button Component --> </div> </div>
The UI we are building with this card is full of other components. It contains checkboxes, accounts, and buttons all living in harmony with one another. The card provides the structure and expects the components to do the rest. If we think about this in a tree view, it would look like this:
|— Card |— Card Header |— Card Body |— Checkbox |— Account |— Checkbox |— Account |— Card Footer |— Button
Another way to think about this is to imagine a set of LEGOs. There are thousands (2,350 according to national geographic) of different elements that have been produced, and almost every one can fit together with no additional work necessary. Building with LEGOs is as easy as having an idea and snapping together various pieces to create a product. The way one would "compose" the Millennium Falcon of LEGO elements, we would "compose" UIs with Iris components.
"Composing" is what we call the concept of building multiple advanced (read: nested) components and using them along side each other to build complex UI's. If you think about the atomic structure of matter, there are a lot of parallels to how UIs are built:
- At the lowest level of this analogy you have an atom which would be a simple component in Iris terms.
- If you combine multiple atoms together you would have a molecule, which would be an advanced component (or nested component) in Iris terms.
- If you put multiple molecules together you would have an organism, which would be the composition of advanced components in Iris terms.
To fully explore this concept, let's take a look at an advanced composition example. Of all the Iris components, the
record is the least opinionated, and the most dependant on nested components to make it functional. Here is an example of a record to show the power and flexibility of composing UI's with Iris components:
<div class="iris-record" data-spacing="comfortable"> <div class="container-fluid"> <div class="row flex-items--center"> <div class="col-1"> <!-- Iris Date Component --> </div> <div class="col-1"> <!-- Iris Avatar Component --> </div> <div class="col-3"> <div class="font-weight--bold width--100 pad-bottom--md"> <span class="pad-right--md">$150.00</span> <span>America</span> </div> <small> <span class="font-icon-add"></span> Monthly </small> </div> <div class="col-4"> <div class="flex flex-items--center width--100 pad-bottom--md"> <small class="pad-right--sm">from</small> <!-- Iris Account Component --> </div> <small> est to send on <!-- Iris Date Component --> </small> </div> <div class="col-2"> <!-- Iris Badge Component --> </div> <div class="col-1 flex flex-justify--end"> <!-- Iris Chevron Component --> </div> </div> </div> </div>
record component is a generic wrapper (just like the
iris-avatar element is) and only provides a
border and some outer
padding to its children. The rest of the structure and content is purely driven by utility classes and other components appearing within the loose boundaries
record provides. This example is the epitome of the flexibility of nesting and composing UIs in the Iris library.
In finishing up, let's talk about the key concepts to keep in mind when building UI's with Iris components.
- Nesting is a way to build advanced components and is the act of combining components together.
- Almost every component is able to be nested or have another component nested within it.
- Components can be nested multiple levels deep and will exist in harmony with each other.
- Composing UI's is the terminology for combining simple and advanced components to form a much more complex UI.