Chariot

Don't walkthrough with your tooltips, fly high with chariot.


Chariot.startTutorial([
  {
    selectors: 'header',
    tooltip: {
      position: 'bottom',
      title: 'Chariot in action',
      text: 'This is an example Chariot tooltip.'
    }
  }
]);
            

Basics

Chariot highlights elements and displays tooltips alongside the elements, taking the user on a guided tour of your page.

Chariot.startTutorial([
  {
    selectors: "div.example2.header",
    tooltip: {
      position: 'top',
      title: 'Highlights & Tooltips',
      text: "Chariot highlights element(s), like this div element, over a " +
        "semi-transparent overlay, and creates a tooltip, like the one " +
        "you're reading now.",
      iconUrl: '/images/chariot.svg'
    },
  },
  {
    selectors: "div#example2",
    tooltip: {
      position: 'right',
      title: 'Easy to configure',
      text: 'This is all the code required to create this two-step tutorial.'
    }
  }
]);
        

Configure everything

The content of a tooltip is all configurable: title text, body text, icon, button text, subtext. The tooltip and arrow positions can be offset, and the arrow size tweaked. Assign HTML attributes. You can even anchor the tooltip to another DOM element separate from the elements being highlighted.

The overlay color can be tweaked, or can be completely optional.

Animations for tooltip bouncing or scrolling the tooltip into view can be disabled.

Chariot.startTutorial({
  steps: [
    {
      selectors: ["div#bling-the-chariot a", "div#example3"],
      tooltip: {
        position: 'left',
        title: 'Customize all the things',
        text: 'This step customizes the major tooltip options.<br/>' +
          'Notice how multiple selectors are specified to highlight the ' +
          'button and code section, but the tooltip is anchored to the anchor ' +
          'icon below.',
        cta: 'Custom Button',
        subtext: function() { return 'Subtext here!'; },
        iconUrl: '/images/blueprint_sparkle.svg',
        anchorElement: '#anchor-example',
        attr: { 'custom-tooltip-attr': 'custom value'},
        arrowLength: 20
      },
    },
    {
      selectors: "div#example3",
      tooltip: {
        position: 'top',
        title: 'Overlay options',
        text: 'Change the overlay color, as shown here, or disable it entirely.' +
          ' Offset the tooltip position, or offset the arrow from the center.' +
          ' Note how we had to specify <code>steps</code> key in the ' +
          'configuration because we customize the <code>overlayColor</code>.',
        xOffsetTooltip: 500,
        yOffsetTooltip: 300,
        offsetArrow: 450
      },
    }
  ],
  overlayColor: 'rgba(0,0,0,0.5)'
});
            
Anchor icon

Launch options

You can also instantiate Chariot with a configuration containing several named tutorials, allowing you to launch these tutorials at a later time.

chariot = new Chariot({
  example4: [
    {
      selectors: 'div#example-named-tutorial',
      tooltip: {
        position: 'right',
        title: 'Named tutorials',
        text: 'The chariot instance launches the tutorial named "example4" ' +
          'defined in the configuration above.'
      }
    },
    {
      selectors: 'div#example4',
      tooltip: {
        position: 'left',
        title: 'Launch programmatically',
        text: "This one line launched the tutorial you're seeing now."
      }
    }
  ]
});
            
              chariot.startTutorial('example4')
            

Delegate Lifecycle callbacks

Pass in an optional delegate object to listen and react to Chariot lifecycle events. You can optionally return promises from each callback if you need to wait for other tasks to finish.

This can be useful for delaying tooltip rendering until specific parts of your DOM are ready.

function sleepFor(sleepDuration, message) {
  return new Promise(resolve => {
    setTimeout(resolve, sleepDuration);
    console.log(message);
  });
}
function willBeginTutorial(tutorial) {
  console.log("delegate - willBeginTutorial\n  tutorial:" + tutorial);
  return sleepFor(0, "willBeginTutorial promise resolved");
}
function willBeginStep(step, stepIndex, tutorial) {
  console.log("delegate - willBeginStep\n  step:" + step + "\n  stepIndex:" + stepIndex + "\n  tutorial:" + tutorial);
  return sleepFor(0, "willBeginStep promise resolved");
}
function willShowOverlay(overlay, stepIndex, tutorial) {
  console.log("delegate - willShowOverlay\n  overlay:" + overlay + "\n  stepIndex:" + stepIndex + "\n  tutorial:" + tutorial);
  return sleepFor(0, "willShowOverlay promise resolved");
}
function didShowOverlay(overlay, stepIndex, tutorial) {
  console.log("delegate - didShowOverlay\n  overlay:" + overlay + "\n  stepIndex:" + stepIndex + "\n  tutorial:" + tutorial);
  return sleepFor(0, "didShowOverlay promise resolved");
}
function willRenderTooltip(tooltip, stepIndex, tutorial) {
  console.log("delegate - willRenderTooltip\n  tooltip:" + tooltip + "\n  stepIndex:" + stepIndex + "\n  tutorial:" + tutorial);
  return sleepFor(0, "willRenderTooltip promise resolved");
}
function didRenderTooltip(tooltip, stepIndex, tutorial) {
  console.log("delegate - didRenderTooltip\n  tooltip:" + tooltip + "\n  stepIndex:" + stepIndex + "\n  tutorial:" + tutorial);
  return sleepFor(0, "didRenderTooltip promise resolved");
}
function didFinishStep(step, stepIndex, tutorial) {
  console.log("delegate - didFinishStep\n  step:" + step + "\n  stepIndex:" + stepIndex + "\n  tutorial:" + tutorial);
  return sleepFor(2000, "didFinishStep promise resolved");
}
function didFinishTutorial(tutorial, forced) {
  console.log("delegate - didFinishTutorial\n  tutorial:" + tutorial + " forced:" + forced);
  return sleepFor(0, "didFinishTutorial promise resolved");
}

window.willBeginTutorial = willBeginTutorial;
window.willBeginStep = willBeginStep;
window.willShowOverlay = willShowOverlay;
window.didShowOverlay = didShowOverlay;
window.willRenderTooltip = willRenderTooltip;
window.didRenderTooltip = didRenderTooltip;
window.didFinishStep = didFinishStep;
window.didFinishTutorial = didFinishTutorial;

var delegate = window;
Chariot.startTutorial([
  {
    selectors: "div#example5",
    tooltip: {
      position: 'right',
      title: 'Delegate callbacks',
      text: "Open up the console to see the lifecycle callbacks. Once you " +
        "click next, notice that the didFinishTutorial log is not printed " +
        "until after the 2 second promise from the didFinishStep has been " +
        "resolved."
    }
  }
], delegate);
            

(Advanced) Overlay Strategies

By default, Chariot uses a cloning strategy to highlight the elements specified by your selectors. Selected elements are cloned, and CSS styles are recursively computed for the elements and its children tags. These cloned elements are placed above an overlay.

Since this strategy can be computationally expensive depending on your markup, the useTransparentOverlayStrategy can be used to render an overlay that highlights the element without needing to clone the element markup and styling. The downside is that this method can only be used with one selector.

Chariot.startTutorial({
  steps: [
    {
      selectors: "div#example6",
      tooltip: {
        position: 'top',
        title: 'Semi-transparent overlay',
        text: "Open up the devtools and notice how the element specified by " +
          "the selector is not cloned. Instead, the overlay uses CSS to " +
          " obscure non-relevant portions.<br/>" +
          "This strategy is more performant than the default, but " +
          "unfortunately multiple selectors cannot be specified."
      }
    }
  ],
  useTransparentOverlayStrategy: true
});
            

Dependencies

The following dependencies are not bundled with Chariot and must be included separately.

  • jQuery

Predefined Templates

Only one stylesheet provided for now. Feel free to open a pull request and contribute more!

Download .zip Download .tar.gz View on GitHub