Dissecting the Slideshow component

Examples are often the best way to learn so let’s look in detail on one of the components in our library, the slideshow component, and see what parts it consists of.

The Slideshow component

Purpose, appearance and functionality

The purpose is to display a predefined set of images in a sequence only showing one image at the time, which is useful, e.g. when you want to save valuable screen real estate.

Appearance and functionality

The slideshow shows the current image together with an optional title and caption. The title can be used as a link to another resource.

In addition to that, there are arrows which link to the next and previous image. The slideshow, by default, has a carousel behavior. There is also an indicator that displays which image is currently shown, e.g image 2/3.

On touch screen devices you can also browse images by swiping.

The slideshow component currently also supports the following configurations:

  • interval: ms
  • autoplay: true/false

So far, nothing really new or too exciting.

The component template

First, let’s look at the component template XML for a slideshow with 3 images. It includes information about the content model, data and settings.

<gbg:slideshow autoplay="false">
<gbg:slideshow-item> 
<gbg:element name=”url”>/animals/dog.html</gbg:element>
<gbg:element name=”title”>Dog</gbg:element>
<gbg:element name=”image”>/images/dog.jpg</gbg:element>
<gbg:element name=”caption”>My favorite dog</gbg:element> </gbg:slideshow-item>
<gbg:slideshow-item> 
<gbg:element name=”url”>/animals/cat.html</gbg:element>
<gbg:element name=”title”>Cat</gbg:element>
<gbg:element name=”image”>/images/cat.jpg</gbg:element>
<gbg:element name=”caption”> My favorite cat</gbg:element> </gbg:slideshow-item>
<gbg:slideshow-item> 
<gbg:element name=”url”>/animals/rabbit.html</gbg:element>
<gbg:element name=”title”>Rabbit</gbg:element>
<gbg:element name=”image”>/images/rabbit.jpg</gbg:element>
<gbg:element name=”caption”> My favorite rabbit</gbg:element> </gbg:slideshow-item>
</slideshow>

The XML is the template markup that goes into our applications. It uses the gbg namespace (an abbrevation of Gothenburg).

Any allowed configurations is provided as attributes on the start node of each component, e.g autoplay=false (see example above).

Then, we need to provide the specific data and content for each slideshow image. In our XML these are represented by the tag <gbg:slideshow-item>.

Each item contains the tags needed to pass the data for each image (image, title, caption and URL). The important thing here is that we are able to abstract away any details of the structural markup and classes that are needed in HTML.

Since it is the XML that is used in our applications we are able to completely replace or alter the HTML without actually having to make any changes in the source code of our applications.

Let’s now look at how the component templates are stored in the repository. The templates consists of an XML schema definition file and an XSL stylesheet. It also has a defined set of dependencies to CSS and JS resources. Possibly also one or more icons or images.

XML Schema definition file

The XML Schema file defines what XML the slideshow component can consist of, which attributes it allows and it is also where we keep meta data of the component such as the description and usage examples.

Below is the XML Schema file for the slideshow component

<?xml version=”1.0" encoding=”UTF-8"?>
<xsd:schema xmlns:xsd=”http://www.w3.org/2001/XMLSchema"
xmlns=”http://teik.goteborg.se/components"
targetNamespace=”http://teik.goteborg.se/components"
elementFormDefault=”qualified”>
<xsd:include schemaLocation=”../core/core.xsd”/>
<xsd:element name=”slideshow” type=”slideshow”/>
// declaration of the slideshow element
<xsd:complexType name=”slideshow”>

<xsd:annotation>
<xsd:documentation>
<p>Use to display images in a slideshow with ...</p>
</xsd:documentation>

// Resource dependencies and usage example XML
<xsd:appinfo>
<resource type=”CSS” name=”components.slideshow.css” path=”components.slideshow.css”/>
<children/>
<gbg:wrapper name=”Basic slideshow” xmlns:gbg=”http://teik.goteborg.se/components”>
<gbg:slideshow settings=”{‘autoplay’: ‘false’}”>
<gbg:slideshow-item>
<gbg:element name=”url”>/animals/dog.html</gbg:element>
<gbg:element name=”title”>Dog</gbg:element>
<gbg:element name=”image”>/images/dog.jpg</gbg:element>
<gbg:element name=”caption”>My favorite dog</gbg:element>
</gbg:slideshow-item>
</gbg:slideshow>
</gbg:wrapper>
</xsd:appinfo>
</xsd:annotation>
 // Declaration of possible child nodes
<xsd:sequence>
<xsd:element name=”element” type=”slideshow-item” maxOccurs=”unbounded”/>
</xsd:sequence>
// Declaration of attibutes
<xsd:attribute name=”autoplay” type=”xsd:string”>
<xsd:annotation>
<xsd:documentation>true|false</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name=”interval” type=”xsd:integer”>
<xsd:annotation>
<xsd:documentation>milliseconds</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
 </xsd:complexType>
// declaration of the slideshow-item element
<xsd:complexType name=”slideshow-item”>
<xsd:annotation>
<xsd:appinfo>
<children>
<child name=”url” mandatory=”true”>
<description>Image address</description>
</child>
<child name=”title”>
<description>Image title</description>
</child>
<child name=”caption”>
<description>Image caption</description>
</child>
</children>
</xsd:appinfo>
</xsd:annotation>
 <xsd:sequence>
<xsd:element name=”element” type=”element” minOccurs=”1" maxOccurs=”unbounded”/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

XSL Stylesheet

The XSL Stylesheet transforms XML into HTML. This is done by the server, before anything is sent to the browser, using a central transformation service which is shared by all pages that are configured to use the component framework. If we need to update the HTML of a component, this is where it is done and once an update is published, it immediately affects the output of all the pages containing that component.

The transformation step has a very small footprint on performance.

So, for example, let’s say we decide to change the placement of the back and forward arrows.

Normally, this probably would require a change of the HTML markup and possibly also changes of the CSS-classes used.

Instead of making this update in each applications that are using the Slideshow component, we update this in one place — the XSL Stylesheet.

The idea behind our concept of abstraction is that the content model is more stable and changes less often compared to the HTML mark-up. A major change of a component that also affects or changes its content model or attributes would require us to update each applications as before.

The XSL Stylesheet uses XSL template tags to transform our XML to HTML — taking the different variations into account.

Below are parts of the XSL Stylesheet for the slideshow component.

<?xml version=”1.0" encoding=”UTF-8"?>
<xsl:stylesheet version=”1.0"
xmlns:xsl=”http://www.w3.org/1999/XSL/Transform"
xmlns:gbg=”http://teik.goteborg.se/components"
xmlns=”http://www.w3.org/1999/xhtml">
<xsl:template match=”gbg:slideshow”>
<div class=”c-slideshow” data-name=”slideshow” data-js=”makeSlideshow”>
<xsl:if test=”@settings”>
<xsl:attribute name=”data-settings”>
<xsl:value-of select=”@settings”/>
</xsl:attribute>
</xsl:if>

<xsl:apply-templates select=”gbg:slideshow-item”/>
...
</div>
</xsl:template>
<xsl:template match=”gbg:slideshow-item”>
<figure>
<xsl:attribute name=”class”>
<xsl:text>c-slideshow__item</xsl:text>
<xsl:if test=”position()=1"> is-active</xsl:if>
</xsl:attribute>
<xsl:apply-templates select=”gbg:element[@name=’image’]”/>
<figcaption class=”c-slideshow__caption”>
<xsl:apply-templates select=”gbg:element[@name=’title’]”/>
<xsl:apply-templates select=”gbg:element[@name=’caption’]”/>
</figcaption>
</figure>
</xsl:template>
...
</xsl:stylesheet>

The XSL Stylesheet will generate the following HTML. Compare it to the XML and you’ll see the abstraction that is accomplished.

<div class=”c-slideshow” data-name=”slideshow”> 
<figure class=”c-slideshow__item is-active”> 
<div class=”c-slideshow__figure”>
<img class=”c-slideshow__image” alt=”” src=”/images/dog.html"/> </div>

<figcaption class=”c-slideshow__caption”>
<h3 class=”c-slideshow__title”>
<a href=”#”>Dog
<svg xmlns:xlink=”http://www.w3.org/1999/xlink" role=”presentation” class=”c-icon” aria-hidden=”true”>
<use xlink:href=”/img/sprite.symbol.svg#arrow-right”></use>
</svg>
</a>
</h3>
<p>My favorite dog</p>
</figcaption>
</figure>
<figure class=”c-slideshow__item”> 
<div class=”c-slideshow__figure”>
<img class=”c-slideshow__image” alt=”” src=”/images/cat.html"/> </div>

<figcaption class=”c-slideshow__caption”>
<h3 class=”c-slideshow__title”>
<a href=”#”>Cat
<svg xmlns:xlink=”http://www.w3.org/1999/xlink" role=”presentation” class=”c-icon” aria-hidden=”true”>
<use xlink:href=”/img/sprite.symbol.svg#arrow-right”></use>
</svg>
</a>
</h3>
<p>My favorite cat</p>
</figcaption>
</figure>
<figure class=”c-slideshow__item is-active”> 
<div class=”c-slideshow__figure”>
<img class=”c-slideshow__image” alt=”” src=”/images/rabbit.html"/> </div>

<figcaption class=”c-slideshow__caption”>
<h3 class=”c-slideshow__title”>
<a href=”#”>Rabbit
<svg xmlns:xlink=”http://www.w3.org/1999/xlink" role=”presentation” class=”c-icon” aria-hidden=”true”>
<use xlink:href=”/img/sprite.symbol.svg#arrow-right”></use>
</svg>
</a>
</h3>
<p>My favorite rabbit</p>
</figcaption>
</figure>
<div class=”c-slideshow__controls”>
<div class=”c-slideshow__indicator”></div>

<button xmlns:xlink=”http://www.w3.org/1999/xlink" class=”c-button c-slideshow__prev has-icon-only”>
<svg role=”presentation” class=”c-icon” aria-hidden=”true”>
<use xlink:href=”/img/ui-framework/sprite.symbol.svg#arrow-left”> </use>
</svg>
</button>
  <button xmlns:xlink=”http://www.w3.org/1999/xlink" class=”c-button c-slideshow__next has-icon-only”> 
<svg role=”presentation” class=”c-icon” aria-hidden=”true”>
<use xlink:href=”/img/ui-framework/sprite.symbol.svg#arrow-right”> </use>
</svg>
</button>
</div>
</div>

CSS and JS resources

For the component to render correctly it is also dependent on a number of resources. Always one or more CSS-files and possibly one or more JavaScript-files and icons.

CSS dependencies

Our CSS framework, which is built on the ITCSS-architecture, is separated from, but closely related to, the XML components defined by our XML Schema file and XSL file.

Each component is dependent on and inherits styles from what is called the the elements layer of the ITCSS architecture which gives basic styling for bare HTML elements. In addition to that it is often also dependent on one or more CSS-files closely related to the specific component.

The Slideshow component has the following CSS dependencies:

  • components.slideshow.css
  • components.button.css
  • compontents.icon.css

JS

In this case the component is also dependent on JavaScript to work. The dependencies to JS files for the slideshow component are:

  • components.slideshow.js

JavaScript hooks are added using the data-js attribute. In this case the transformation prints the correct attribute and value by default as it is mandatory for the component to work as expected.

To summarize

A component template consists of an XML Schema file that defines the XML used to represent a components content model (possibly together with a number of attributes), an XSL stylesheet that is responsible for transforming the XML into HTML and dependencies to CSS and JavaScript files.

If our assumption, that a component’s content model over time is more stable than the HTML used to render it, then we believe that the added complexity of this extra abstraction layer will be worth the initial cost and effort.


This was part 4 in the publication: Our Story: Building a component library