Light-weight, no-dependency, vanilla JavaScript engine to drive user's focus across the page
With Animation Without Animation💡 This library is a a port of driver.js. The reason behind refactoring that library, is because driver.js under the hood works by elevating elements using css with z-index. This means it can very easily break your layout if you rely anywhere on the css stacking context.
So how does this library approach the problem? It doesn't touch any styles at all. Instead the library renders the overlay using an SVG element. This means it works with any layout.
It has the small downside that an SVG is less customizable in terms of how it looks visually than the approach that driver.js had. But maybe better support for styling will be added in the future, since there are other ways to approach that problem.
A lightweight (~7.5kb gzipped) yet powerful JavaScript engine that helps you drive the user's focus on page.
Some sample use-cases can be creating powerful feature introductions, call-to-action components, focus shifters etc.
Boarding is compatible with all the major browsers and can be used for any of your overlay needs. Feature introductions, focus shifters, call-to-action are just a few examples.
In it simplest, it puts the canvas on top of the whole page and then cuts the part that is over the element to be highlighted and provides you several hooks when highlighting, highlighted or un-highlighting elements making it highly customizable.
Features | Boarding.js | Driver.js |
---|---|---|
Works with complex layouts (no z-index conflicts) |
||
Define steps for elements which are not mounted yet (for highly interactive websites, such as react applications, where elements might only appear once an action has been taken) |
||
Has the concept of a stage (a customizable background for the highlighted element) * Boarding.js will add the boarding-highlighted-element class to the
higlighted element for optional custom styling.
|
* | |
Auto popover positioning | ||
Control popover alignment | ||
Control allowed user (click) actions (strictClickHandling) |
||
Allow preparing/validating a move before it happens (prepareElement) |
||
Written in TypeScript |
Besides the above, Boarding.js also has a few more options available
for each individual step, a more stable event system and more hooks
for it, such as onBeforeHighlighted
.
Below you find some of the examples and sample use-cases on how you can use it.
If all you want is just highlight a single element, you can do that simply by passing the selector
Show Democonst boarding = new Boarding();
boarding.highlight('#create-post');
A real world use-case for this could be highlighting an element when user is interacting with it
const focusBoarding = new Boarding();
// Highlight the section on focus
document.getElementById('creation-input')
.addEventListener('focus', (e) => {
focusBoarding.focus('#creation-input');
});
Focus any of the inputs and see how it moves the highlight from one element to the other
You can also turn off the animation or set the padding around the corner. More on it later.
If you would like to show some details alongside the highlighted element, you can do that easily by specifying title and description
Show Democonst boarding = new Boarding();
boarding.highlight({
element: '#some-element',
popover: {
title: 'Title for the Popover',
description: 'Description for it',
}
});
You can modify the behavior of this popover also by a certain set of options. More on it below.
You can also, change the preffered position of the popover to be
either
top
, bottom
, left
,
right
.
And for even more fine-grain control define the alignment of the
popover to be either
start
, center
, end
const boarding = new Boarding();
boarding.highlight({
element: '#some-element',
popover: {
title: 'Title for the Popover',
description: 'Description for it',
// prefferedPosition can be top, bottom, left, right
prefferedPosition: 'left',
// alignment can be start, center, end
alignment: "start"
}
});
If you don't specify the position or specify it to be
auto
, it will automatically find the suitable position
for the popover and show it
You can also specify HTML in the body or the title of the popovers. Here is an example:
Show Democonst boarding = new Boarding();
boarding.highlight({
element: '#some-element',
popover: {
title: '<em>An italicized title</em>',
description: 'Description may also contain <strong>HTML</strong>'
}
});
And of course it can be any valid HTML.
By default, boarding.js gets reset if user clicks outside the highlighted element, you can disable this:
Show Democonst boarding = new Boarding({
allowClose: false,
});
boarding.highlight({
element: '#some-element',
popover: {
title: '<em>An italicized title</em>',
description: 'Description may also contain <strong>HTML</strong>'
}
});
If you use this option, for multi-step boarding, it would close after you are done with the popover or you can close it programmatically. For single element popover, you need to close it properly, otherwise it won't be closed
boarding.reset()
You can also make powerful feature introductions to guide the users about the features. Just provide an array of steps where each step specifies an element to highlight.
Below is just a quick example showing you how to combine the steps in introduction.
Show Democonst boarding = new Boarding();
// Define the steps for introduction
boarding.defineSteps([
{
element: '#first-element-introduction',
popover: {
className: 'first-step-popover-class',
title: 'Title on Popover',
description: 'Body of the popover',
prefferedPosition: 'left'
}
},
{
element: '#second-element-introduction',
popover: {
title: 'Title on Popover',
description: 'Body of the popover',
prefferedPosition: 'top'
}
},
{
element: '#third-element-introduction',
popover: {
title: 'Title on Popover',
description: 'Body of the popover',
prefferedPosition: 'right'
}
},
]);
// Start the introduction
boarding.start();
This is just a quick example for the feature introduction. For a richer one, please have a look at the "Quick Tour"
You may also turn off the footer buttons in popover, in which case user can control the popover using the arrows keys on keyboard. Or you may control it using the methods provided by Boarding.
You can create feature introductions and do everything listed above without overlays also. All you have to do is just set the opacity to `0`.
Show Democonst boarding = new Boarding({
opacity: 0,
});
boarding.highlight({
element: '#run-element-without-popover',
popover: {
title: 'Title for the Popover',
description: 'Description for it',
prefferedPosition: 'top', // can be `top`, `left`, `right`, `bottom`
}
});
..and you can do the same for the feature introductions
If you want to customize the rendered popover, for example by adding a a counter for the "current step", you can do so by modifying the popover html elements using onPopoverRender.
Show Democonst boarding = new Boarding({
// modify the rendered popoverElements.popoverTitle
onPopoverRender: (popoverElements) => {
// setTimeout, so we the count runs immediatly after all internal boarding logic has run. Otherwise we would get an outdated boarding.currentStep number
setTimeout(() => {
popoverElements.popoverTitle.innerText = `${
popoverElements.popoverTitle.innerText
} (${boarding.currentStep + 1}/${
boarding.getSteps().length
})`;
}, 0);
},
});
boarding.defineSteps([/* ...steps */]);
boarding.start();
..and you can do the same for the feature introductions
Boarding comes with many options that you can manipulate to make boarding behave as you may like
Here are the options that Boarding understands
const boarding = new Boarding({
className: 'scoped-class', // className to wrap boarding.js popover
animate: true, // Animate while changing highlighted element
opacity: 0.75, // Overlay opacity (0 means only popovers and without overlay)
padding: 10, // Distance of element from around the edges
allowClose: true, // Whether clicking on overlay should close or not
overlayClickNext: false, // Should it move to next step on overlay click
overlayColor: 'rgb(0,0,0)', // Fill color for the overlay
doneBtnText: 'Done', // Text on the final button
closeBtnText: 'Close', // Text on the close button for this step
nextBtnText: 'Next', // Next button text for this step
prevBtnText: 'Previous', // Previous button text for this step
showButtons: false, // Do not show control buttons in footer
keyboardControl: true, // Allow controlling through keyboard (escape to close, arrow keys to move)
scrollIntoViewOptions: {
behaviour: "smooth",
}, // We use `scrollIntoView()` when possible, pass here the options for it if you want any. Alternatively, you can also disable this functionallity by setting scrollIntoViewOptions to "no-scroll"
onBeforeHighlighted: (Element) {}, // Called when element is about to be highlighted
onHighlighted: (Element) {}, // Called when element is fully highlighted
onDeselected: (Element) {}, // Called when element has been deselected
onReset: (Element) {}, // Called when overlay is about to be cleared
onStart: (Element) {}, // Called when `boarding.start()` was called
onNext: (Element) => {}, // Called when moving to next step on any step
onPrevious: (Element) => {}, // Called when moving to next step on any step
strictClickHandling: "block-all", // Can also be `true` or if not wanted at all, `false`. Either block ALL pointer events, or isolate pointer-events to only allow on the highlighted element (`true`). Popover and overlay pointer-events are of course always allowed to be clicked
// Make changes to the actual popoverElements once they get rendered.
onPopoverRender: (el) => {
// ...
},
});
Note that all the button options that you provide in the boarding definition can be overridden for a specific step by giving them in the step definition
Here are the set of options that you can pass in each step i.e. an
item in array of steps or the object that you pass to
highlight
method
const stepDefinition = {
element: '#some-item', // Query selector string or Node to be highlighted
popover: { // There will be no popover if empty or not given
className: 'popover-class', // className to wrap this specific step popover in addition to the general className in Boarding options
title: 'Title', // Title on the popover
description: 'Description', // Body of the popover
showButtons: false, // Do not show control buttons in footer
closeBtnText: 'Close', // Text on the close button for this step
nextBtnText: 'Next', // Next button text for this step
prevBtnText: 'Previous', // Previous button text for this step
onPopoverRender: (el) => { // Make changes to the actual popoverElements once they get rendered.
// ...
},
}
prepareElement: () => {}, // Called *before* moving to this step (for both cases when coming from "onNext" or "onPrevious")
onNext: (Element) => {}, // Overwrite the original onX eventhandlers for the current step. Same for on[Previous/Highlighted/BeforeHighlighted/Deselected]
};
Below are the set of methods that are available to you
const boarding = new Boarding(boardingOptions);
const isActivated = boarding.isActivated; // Checks if the boarding is active or not
boarding.next(); // Moves to next step in the steps list
boarding.previous(); // Moves to previous step in the steps list
boarding.start(stepNumber = 0); // Starts driving through the defined steps
boarding.highlight(string|stepDefinition); // highlights the element using query selector or the step definition
boarding.reset(); // Resets the overlay and clears the screen
boarding.hasHighlightedElement(); // Checks if there is any highlighted element
boarding.hasNextStep(); // Checks if there is next step to move to
boarding.hasPreviousStep(); // Checks if there is previous step to move to
// Prevents the current move. Useful in `prepareElement`, `onNext`, `onPrevious` if you want to
// perform some asynchronous task and manually move to next step
boarding.preventMove();
boarding.continue(); // Continue the move that was prevented using preventMove
boarding.clearMovePrevented(); // preventMove will just "pause" the tour. If you want to clear that paused state, you can call clearMovePrevented, to clean up that paused state. You should do this, when your logic has a condition where it never calls continue
// Gets the currently highlighted element on screen
const activeElement = boarding.getHighlightedElement();
const lastActiveElement = boarding.getLastHighlightedElement();
activeElement.getCalculatedPosition(); // Gets screen co-ordinates of the active element
activeElement.hidePopover(); // Hide the popover
activeElement.showPopover(); // Show the popover
activeElement.getNode(); // Gets the DOM Element behind this element
You can use a variety of options to achieve whatever you may want. I have some plans on improving it further, make sure to keep an eye on the GitHub page
You can find the contribution instructions on the GitHub page. Feel free to submit an issue, create a pull request or spread the word