Train Your Users with OnBoarding

We slave over our interactive projects as if they were our children, but we rarely focus on the other side until deployment.  There is of course UX, which offers us a framework to build from, but we don’t really know how our solutions will be used until we get some feedback from the end user.  Onboarding is a great way to ensure a successful transition to using your product / service and ease the end user into your interactive project.

The Markup

As with everything that exists in the world of coding, we have to begin with the markup.  We want our onboarding solution to be flexible, so we are gonna tie it to elements that have a specific data attribute.  As we can add these attributes to any elements we want, the onboading tour can do anything you like.

We use data attributes because they are easy to implement and they can be referenced by Javascript and parsed by JSON; giving them more extensible abilities.

For an example, we will add a tour tip to the navigation bar.  We find the navigation element and add this attribute: data-obtour='{“title”: “Responsive Menu”, “description”: “This element is for navigation”, “position”: “bottom” }’

The text after data- is specific to your project, change as necessary.  We are using JSON format, so it is {“property name”: “property value”, etc.}.  The title and description in our example will be displayed next to the element, while the position determines the relative placement of the modal window we use to view our tour.

The Javascript

We are going to use an OOP approach with our tour solution as it allows us to better encapsulate the tour presentation from the tour logic.  We need to add a reference to JS in the bottom before the </body>, and add this to the referenced JS page:


function OBTour() {
this.tourItems = document.querySelectorAll('[data-obtour]');

if (this.tourItems.length === 0) {
console.error(‘Sorry’);
return;
}
document.body.addEventListener(‘click’, this.handleClicks.bind(this)); //creating an event handler to listen for the clicks. The bind(this) portion at the end is good practice and necessary if we have multiple event handlers running concurrently.

this.initialize();
}

OBTour.prototype.initialize = function() {
this.stops = []; // stops refer to the elements in the page, nav is first stop, etc. This array will store all the JSON data from the attributes.
this.cursor = 0;
this.offset = 20; // distance between window and parent element

var tourWindowContents = “”; //create an empty variable

for (var i = 0; i < this.tourItems.length; i++) { //create loop to move through all tour items
this.stops[i] = JSON.parse(this.tourItems[i].getAttribute(‘data-obtour’)); //then add each tour item to the stops array
}

this.overlay = document.createElement(‘div’); //now we need to create the overlay, this code creates a div element in a variable called overlay
this.overlay.className = ‘obtour-overlay’; //now we give that new div element a class name
document.body.insertBefore(this.overlay, document.body.childNodes[0]); //then we append the new div element to the document before the very first child node of the body, so at the start of the page

//Now we build the tour window with +=, which just adds the values to the variable in sequential order.
this.tourWindow = document.createElement(‘div’);
this.tourWindow.className = ‘obtour-window’;
tourWindowContents += ‘

‘;
tourWindowContents += ‘

‘;
tourWindowContents += ‘

‘;
tourWindowContents += ‘‘; //these data attributes on the nav buttons will
tourWindowContents += ‘‘;
tourWindowContents += ‘‘;
tourWindowContents += ‘

‘;
this.tourWindow.innerHTML = tourWindowContents; // add our new tour window HTML to be the inner HTML of the tourWindow variable
document.body.insertBefore(this.tourWindow, document.body.childNodes[0]); //insert our new Tour Window before the first body element

this.moveTo(this.cursor);

};

OBTour.prototype.moveTo = function(index) {//this moveTo method will jump us around the page from the navigation buttons.
var parent = this.tourItems[index],
parentSpecs = parent.getBoundingClientRect(), //grab the window parameters so we can insert our modal window inside them
bodySpecs = document.body.getBoundingClientRect(), // grab the body space params
position = this.stopes[index].position,
left, top, scrollPosition;

if (parent.style.position ===”) { //check for a position from the data attribute
parent.style.position = ‘relative’; //if none present, just display the window relative to the element
}

parent.classList.add(‘obtour-active’); //add the active class to any item we are currently on

this.tourWindow.querySelector(‘header’).innerHTML = this.stops[index].title; //add the title to our modal window
this.tourWindow.querySelector(‘obtour-window-description’).innerHTML = this.stops[index].description; //then add the description

//set the tour window coordinates
swith(postion) {
case ‘top’:
left = parentSpecs.left + (parent.offsetWidth – this.tourWindow.offsetWidth) / 2;
top = parentSpecs.top + this.tourWindo.offsetHeight – this.offset – bodySpecs.top;
scrollPosition = parentSpecs.top – bodySpecs.top – this.tourWindow.offsetHieght – this.offset;
break;

case ‘right’:
left = parentSpecs.right + this.offset;
top = (parentSpecs.top + parentSpecs.bottom) / 2 – this.tourWindow.offsetHeight / 2 – bodySpecs.top;
scrollPosition = parentSpecs.top – bodySpecs.top;
break;

case ‘bottom’:
left = parentSpecs.left + (parent.offsetWidth – this.tourWindow.offsetWidth) / 2;
top = parentSpecs.bottom + this.offset – bodySpecs.top;
scrollPosition = parentSpecs.top – bodySpecs.top;
break;

case ‘left’:
left = parentSpecs.left – this.offset – this.tourWindow.offsetWidth;
top = (parentSpecs.top + parentSpecs.bottom) / 2 – this.tourWindow.offsetHeight / 2 – bodySpecs.top;
scrollPosition = parentSpecs.top – bodySpecs.top;
break;

}
window.scrollTo(0, scrollPosition);
this.tourWindow.style.left = left + ‘px’;
this.tourWindow.style.top = top + ‘px’;

};

OBTour.prototype.handleClicks = function(event) [ //add our event handler to the prototyple
var targetATTR = event.target.getAttribute(‘data-obtour-nav’); //event is an object returned by the event handler, so is target, which getAttribute is a method

if (targetATTR) {
event.preventDefault();

switch (targetAttr) {
case ‘previous’:
if (this.cursor > 0) {
this.tourItems[this.cursor].classList.remove(‘obtour-active’);
this.moveTo(–this.cursor); // — means to decrease the cursor value by 1, then pass in cursor value to method
}
break;

case ‘next’:
if (this.cursor < this.stops.length – 1) {
this.tourItems[this.cursor].classList.remove(‘obtour-active’);
this.moveTo(++this.cursor);
break;

case ‘close’:
document.body.removeChild(this.overlay);
document.body.removeChild(this.tourWindow);
break;
}
}
};

In a second page that is also referenced, we must add an event listener so the JS knows when to fire. We will add this particular event listener to watch for the document completing it’s render, which means we are ready to tour:

document.addEventListener(‘DOMContentLoaded’, function() {
var tour = new APTour(); //this code is instantiating the class, and we can do this multiple times should we wish
});

Styling

Now, we need to style our tour so it looks good and makes sense


.obtour-overlay {
position:fixed;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 10000;
}

.obtour-window {
background: white;
min-width: 15rem;
position:absolute;
z-index: 10002;
display:inline-block
}

.obtour-window header {
font-weight:bold;
}

.obtour_window footer {
padding: 1rem;
overflow:hidden;
}

.obtour-window-desc {
padding: 1rem;
}

.obtour-active {
z-index: 10001;
}

The Wrap Up

The above code will allow you to create a onboarding tour on any element with plain, simple vanilla JS. It can also be built upon to use Jquery animations and other advanced functions to make the onboarding tour as immersive and enjoyable as possible.

Web design continues to progress by leaps and bounds, we just have to make sure the leaps aren’t too big for our users. Onboarding is a great way to make the complex simple and guide our visitors in how we want them to use our websites. Give them a shot and be sure to let me know about your successes!