Compass

Compass simplifies complex workflows by guiding users through progressive interactions to accomplish a task.

Coming soon...

Please enjoy a cat while you wait

Compass simplifies complex workflows by guiding users through progressive interactions to accomplish a task.

Coming soon...

Please enjoy a cat while you wait

Compass simplifies complex workflows by guiding users through progressive interactions to accomplish a task.

Examples

For details on when to use this component, please see the Usage tab.

Basic Compass

Compass will generally be used with other components like Drawer but it can also be used to handle a wizard-like workflow when put by itself. For simplicity, here is a very basic example of how to use it. Notice that you need to specify the id of each step as well as the data-compass-next-step, and data-compass-previous-step to tell compass how to proceed through your flow.

  • Not including a data-compass-next-step causes Compass to display the done action elements and hide the next action elements.
  • Having a data-compass-previous-step causes Compass to display the previous action elements.
  • Not having a data-compass-previous-step causes Compass to hide the previous action elements.

Step 1
Step 2
Step 3
<div id="basic_compass" class="iris-compass" >
    <div class="iris-compass__header">
        <h2 class="iris-compass__title" data-compass-title></h2>
    </div>
    <div class="iris-compass__steps">
        <div id="basic_compass__step_1" class="iris-compass-step"
            data-compass-step-title="My First Step"
            data-compass-next-step="basic_compass__step_2">
            <div class="iris-compass-step__body">
                Step 1
            </div>
        </div>
        <div id="basic_compass__step_2" class="iris-compass-step"
            data-compass-step-title="My Second Step"
            data-compass-previous-step="basic_compass__step_1"
            data-compass-next-step="basic_compass__step_3" >
            <div class="iris-compass-step__body">
                Step 2
            </div>
        </div>
        <div id="basic_compass__step_3" class="iris-compass-step"
            data-compass-step-title="My Last Step"
            data-compass-previous-step="basic_compass__step_2">
            <div class="iris-compass-step__body">
                Step 3
            </div>
        </div>
    </div>
    <div class="iris-compass__footer">
        <button class="iris-button iris-button--secondary" type="button" data-compass-action="previous">Back</button>
        <button class="iris-button iris-button--primary" type="button" data-compass-action="done">Done</button>
        <button class="iris-button iris-button--primary" type="button" data-compass-action="next">Next</button>
    </div>
</div>

Basic Compass with Autowire

This example uses the data-compass-autowire-steps technique which should only be used on the simplest of flows where each step comes right after the other. In this case you don't have to specify the id of each step as it can infer that for you as well as which step should come next and which step was previous based on the order in the DOM.

Step 1
Step 2
Step 3
<div id="autowire_compass" class="iris-compass" data-compass-autowire-steps>
    <div class="iris-compass__header">
        <h2 class="iris-compass__title" data-compass-title></h2>
    </div>
    <div class="iris-compass__steps">
        <div data-compass-step-title="My First Step" class="iris-compass-step">
            <div class="iris-compass-step__body">
                Step 1
            </div>
        </div>
        <div data-compass-step-title="My Second Step" class="iris-compass-step">
            <div class="iris-compass-step__body">
                Step 2
            </div>
        </div>
        <div data-compass-step-title="My Last Step" class="iris-compass-step">
            <div class="iris-compass-step__body">
                Step 3
            </div>
        </div>
    </div>
    <div class="iris-compass__footer">
        <button class="iris-button iris-button--secondary" type="button" data-compass-action="previous">Back</button>
        <button class="iris-button iris-button--primary" type="button" data-compass-action="done">Done</button>
        <button class="iris-button iris-button--primary" type="button" data-compass-action="next">Next</button>
    </div>
</div>

Controlling Compass Remotely

Getting all the controls into Compass isn't always possible. When you need to work with Compass externally, in a Drawer for example, you need to have the buttons in that footer and not in the compass footer. The data-compass attribute can be used to create a context for our compass to use.

Step 1
Step 2
Step 3
<div id="remote_compass" class="iris-compass">
    <div class="iris-compass__header">
        <h2 class="iris-compass__title" data-compass-title></h2>
    </div>
    <div class="iris-compass__steps">
        <div id="remote_compass__step_1" class="iris-compass-step"
            data-compass-step-title="My First Step"
            data-compass-next-step="remote_compass__step_2">
            <div class="iris-compass-step__body">
                Step 1
            </div>
        </div>
        <div id="remote_compass__step_2" class="iris-compass-step"
            data-compass-step-title="My Second Step"
            data-compass-previous-step="remote_compass__step_1"
            data-compass-next-step="remote_compass__step_3" >
            <div class="iris-compass-step__body">
                Step 2
            </div>
        </div>
        <div id="remote_compass__step_3" class="iris-compass-step"
            data-compass-step-title="My Last Step"
            data-compass-previous-step="remote_compass__step_2">
            <div class="iris-compass-step__body">
                Step 3
            </div>
        </div>
    </div>
</div>

<!-- our remote controls -->
<div class="flex flex-justify--center" data-compass="remote_compass">
    <button class="iris-button iris-button--secondary" type="button" data-compass-action="previous">Back</button>
    <button class="iris-button iris-button--primary" type="button" data-compass-action="done">Done</button>
    <button class="iris-button iris-button--primary" type="button" data-compass-action="next">Next</button>
</div>

Sometimes you need content controlled externally by a Compass. This could be anything from a single button to a content area div.

Step 1
Step 2
Step 3
show on step 2
show everywhere but step 2
show only on step 2 and step 3
show everywhere but step 2 and step 3
<div data-compass="remote_compass">
    <div data-compass-step-show="basic_compass__step_2">show on step 2</div>
    <div data-compass-step-hide="basic_compass__step_2">show everywhere but step 2</div>
    <div data-compass-step-show="basic_compass__step_2 basic_compass__step_3"> show only on step 2 and step 3</div>
    <div data-compass-step-hide="basic_compass__step_2 basic_compass__step_3">show everywhere but step 2 and step 3</div>

    <button id="cancel_button" class="iris-button iris-button--primary" type="button" data-close>
        <span data-compass-step-show="basic_compass__step_3">Return to Page after Success</span>
        <span data-compass-step-hide="basic_compass__step_3">Cancel before Finishing</span>
    </button>
</div>

Using Compass in Drawer

Here is a practical example of how Compass would be used in Drawer. Using data-compass on the Drawer's element we can give the drawer full control over the Compass's actions. We also use the Compass to show the cancel button only when it is necessary. A suggestion would be to call compass.reset() when the drawer closes. An example on how to wire up the drawer close event can be found in the Drawer Documentation.

<button class="iris-button iris-button--primary" id="basic" data-drawer="example_drawer">Basic drawer</button>

<div class="iris-drawer" id="example_drawer" aria-hidden="true" data-size="wide" data-compass="example_compass">
    <section class="iris-drawer__content">
        <header class="iris-drawer__header">
            <div class="flex flex-items--center">
                <button class="iris-button iris-button--ghost iris-drawer__back-button" data-modifier="compressed" aria-label="back" data-compass-action="previous">
                    <div class="iris-chevron iris-chevron--left" data-size="xs" ></div>
                </button>
                <h2 class="iris-drawer__title" data-compass-title></h2>
            </div>
            <button class="iris-button iris-button--ghost" data-modifier="compressed" data-close> <span class="font-icon-cancel-x" aria-hidden="true"></span> </button>
        </header>
        <div class="iris-drawer__body">
            <div id="example_compass" class="iris-compass" >
                <div class="iris-compass__steps">
                    <div id="example_compass__step_1" class="iris-compass-step"
                        data-compass-step-title="My First Step"
                        data-compass-next-step="example_compass__step_2">
                        <div class="iris-compass-step__body">
                            Step 1
                        </div>
                    </div>
                    <div id="example_compass__step_2" class="iris-compass-step"
                        data-compass-step-title="My Second Step"
                        data-compass-previous-step="example_compass__step_1"
                        data-compass-next-step="example_compass__step_3" >
                        <div class="iris-compass-step__body">
                            Step 2
                        </div>
                    </div>
                    <div id="example_compass__step_3" class="iris-compass-step"
                        data-compass-step-title="My Last Step"
                        data-compass-previous-step="example_compass__step_2">
                        <div class="iris-compass-step__body">
                            Step 3
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <footer class="iris-drawer__footer">
            <button class="iris-button iris-button--primary mar-bottom--md" data-size="full-width" type="button" data-compass-action="done" data-close>Done</button>
            <button class="iris-button iris-button--primary mar-bottom--md" data-size="full-width" type="button" data-compass-action="next">Next</button>
            <button class="iris-button iris-button--secondary" data-size="full-width" type="button" data-close data-compass-step-hide="example_compass__step_3">Cancel</button>
        </footer>
    </section>
</div>

Branching Steps

Compass supports branching steps through a little javascript manipulation.

Step 2 A
Step 2 B
Step 3
<div id="branching_compass" class="iris-compass" >
    <div class="iris-compass__header">
        <h2 class="iris-compass__title" data-compass-title></h2>
    </div>
    <div class="iris-compass__steps">
        <div id="branching_compass__step_1" class="iris-compass-step"
            data-compass-step-title="My First Step"
            data-compass-next-step="branching_compass__step_2_a">
            <div class="iris-compass-step__body">
                <fieldset class="iris-form-groupset iris-form-groupset--stacked">
                    <div class="iris-form-groupset__container">
                        <legend class="iris-form-groupset__label"></legend>
                        <div class="iris-form-groupset__groups" id="radio_group">
                            <div class="iris-radio">
                                <input class="iris-radio__input" name="radio" type="radio" id="radio_1" checked value="branching_compass__step_2_a" />
                                <label class="iris-radio__label" for="radio_1"><span class="iris-radio__content">Go to Step 2 A</span></label>
                            </div>
                            <div class="iris-radio">
                                <input class="iris-radio__input" name="radio" type="radio" id="radio_2" value="branching_compass__step_2_b" />
                                <label class="iris-radio__label" for="radio_2"><span class="iris-radio__content">Go to Step 2 B</span></label>
                            </div>
                        </div>
                    </div>
                </fieldset>
            </div>
        </div>
        <div id="branching_compass__step_2_a" class="iris-compass-step"
            data-compass-step-title="My Second Step"
            data-compass-previous-step="branching_compass__step_1"
            data-compass-next-step="branching_compass__step_3" >
            <div class="iris-compass-step__body">
                Step 2 A
            </div>
        </div>
        <div id="branching_compass__step_2_b" class="iris-compass-step"
            data-compass-step-title="My Second Step"
            data-compass-previous-step="branching_compass__step_1"
            data-compass-next-step="branching_compass__step_3" >
            <div class="iris-compass-step__body">
                Step 2 B
            </div>
        </div>
        <div id="branching_compass__step_3" class="iris-compass-step"
            data-compass-step-title="My Last Step"
            data-compass-previous-step="branching_compass__step_2_a">
            <div class="iris-compass-step__body">
                Step 3
            </div>
        </div>
    </div>
    <div class="iris-compass__footer">
        <button class="iris-button iris-button--secondary" type="button" data-compass-action="previous">Back</button>
        <button class="iris-button iris-button--primary" type="button" data-compass-action="done">Done</button>
        <button class="iris-button iris-button--primary" type="button" data-compass-action="next">Next</button>
    </div>
</div>
Alkami.Iris.dom.ready(function() {
    var radioGroup = document.getElementById('radio_group');
    radioGroup.addEventListener('change', function(event) {
        var stepOne = document.getElementById('branching_compass__step_1');
        var stepThree = document.getElementById('branching_compass__step_3');

        stepOne.setAttribute('data-compass-next-step', event.target.value);
        stepThree.setAttribute('data-compass-previous-step', event.target.value);
    });
});

Accessibility

As always we want to keep all of the components in the application accessible. Please keep these notes in mind while using this component:

  • Use button elements with type="button" for Next, Previous, and Done Compass actions.
  • Use disable functions in API with doing async tasks. See Methods in API.

Accessibility that Compass provides for you:

  • Automatic focus management when switching steps.
  • Automatic handling of hidden and visible content e.g. aria-hidden.

API

Examples

Getting the CompassComponent Object of an Element

var element = document.getElementById('test_compass');
var compassComponent = Alkami.Iris.CompassComponent.componentForElement(element);


// get a compass step by it's id
var compassStep = compassComponent.stepById('test_compass_step_1');

Using Compass's Step Change Handlers

Inevitably we are going to need to be able to process data between steps in a Compass. It may be for validation or you might be creating new steps on the fly. In cases such as these you will want to use the Step Change Handlers to make defining those actions easier than using the actual event listeners.

For each step you can define an object of actions: before, after, and done which handle the iris.compass.stepchange.before, iris.compass.stepchange.after, and iris.compass.done respectively. The event object is the same ones used for each of the dispatched events. See Using Events for Compass Example to see what properties are available in the event object.

Action Lifecycle:

  • before fires just before the step defined by id becomes the active step.
  • after fires just after the step defined by id became the active step.
  • done fires when the done event fired on the step defined by id.
compassComponent.stepChangeHandlers = {
    test_compass_step_1: {
        before: function(event) {
            console.log('I fire before the step changes.');
        },
        after: function(event) {
            console.log('I fire after the step changes.');
        },
        done: function(event) {
            console.log('I fire when done is called on this step.')
        }
    }
}

For those who have default actions that need to happen on steps you can specify the default handler. Any step that doesn't have a handler specified will call these functions instead. In contrast if you really don't want the default action to happen on a specific step, you can pass null to one of the actions for that step.

compassComponent.stepChangeHandlers = {
    test_compass_step_1: {
        before: function(event) {
            console.log('I fire only on step 1.')
        }
    },
    test_compass_step_2: {
        after: null  // `after` won't fall to default handler because we set it to `null`.
    }
    default: {
        before: function(event) {
            var step = event.detail.nextStep;
            console.log('I fired for everybody else. I fired for ' + step.id);
        },
        after: function(event) {
            var step = event.detail.activeStep;
            console.log('Successfully displayed step ' step.id)
        }
    }
}

Using Events for Compass

Some very simple or highly advanced problems are just better suited to use an event directly than using the configuration object. These problems might include having a highly dynamic set of steps that require oversight or something as simple as you just need to do something when the Compass done action has fired. stepChangeHandlers is built using these events so the event objects referenced here can be used there too.

function doneHandler(event) {
    var detail = event.detail;
    var component = detail.component; // Compass Component
    var step = detail.step; // Compass Step which fired the done event

    component.reset(); // Resets the component back to the beginning
}

function beforeHandler(event) {
    var detail = event.detail;
    var component = detail.component; // Compass Component
    var activeStep = detail.activeStep; // Compass Step which is still active
    var nextStep = detail.nextStep; // Compass Step which is about to be active
}

function afterHandler(event) {
    var detail = event.detail;
    var component = detail.component; // Compass Component
    var activeStep = detail.activeStep; // Compass Step which is now active
    var previousStep = detail.previousStep; // Compass Step which was active
}

compassElement.addEventListener('iris.compass.done', doneHandler);
compassElement.addEventListener('iris.compass.stepchange.before', beforeHandler);
compassElement.addEventListener('iris.compass.stepchange.after', afterHandler);

Canceling a Step Change

On the before action, you still have a chance to cancel the impending step change. By using compass.cancelStepChange() you can send a signal to compass that you want to abort the current step change. This can be done both is the stepChangeHandlers and the events approach. In the stepChangeHandlers approach you can alternatively return false; to fire a cancelation.

function beforeHandler(event) {
    var component = event.detail.component;

    component.cancelStepChange(); // do this method when using the event

    return false; // alternatively do this when using stepChangeHandlers
}

compassElement.addEventListener('iris.compass.stepchange.before', beforeHandler);

/*... or ... */

compassComponent.stepChangeHandlers = {
    test_compass_step_1: {
        before: beforeHandler
    }
}

Asynchronous Step Changes

We might need to wait to do a task before actually switching to the next step. This could be when we need to make a call to the server to do some validation or to get data for the next step. To reduce the amount of boilerplate code, Compass contains a action handler function to help you out. You pass in a callback that has success and event arguments. You call success if your event is successful, otherwise do your error logic.

compassComponent.stepChangeHandlers = {
    test_compass_step_1: {
        before: Alkami.Iris.CompassComponent.createAsyncHandler(
            function(success, event) {
                setTimeout(function() {
                    console.log('Do all the async things!');

                    success();
                }, 10);
            })
    }
}

Events

Name Description
iris.compass.done Fires on compass element after a step's done action has been trigger through API or wired up button
iris.compass.stepchange.after Fires on compass element after a step change has happened.
iris.compass.stepchange.before Fires on compass element just before the step change has happened. Gives the developer a chance to bail out of the step change.
iris.compass.transition.start Fires on compass steps and associated elements just before the transition animation starts but after the step change.
iris.compass.transition.end Files on compass steps and associated elements just after the transition animation has ended.

Methods

static CompassComponent.init([nodeOrNodeList])

  • nodeOrNodeList - The optional node or node list that will be configured to be compasses. Default: the query .iris-compass is used.

static CompassComponent.destroy(nodeOrNodeList)

  • nodeOrNodeList - The node or node list that will be untied from the Compass.

static CompassComponent.refresh([nodeOrNodeList])

  • nodeOrNodeList - The optional node or node list that will be configured to be compasses. This will call a destroy if the component exists before initing again. Default: the query .iris-compass is used.

static CompassComponent.componentForElement(element)

  • element - The element that may be a Compass

Checks if a DOM element has a CompassComponent object associated with it. Returns the CompassComponent object if one exists or null if one is not found.

static CompassComponent.createAsyncHandler(callback)

  • callback - function(success){} - a callback that wraps the async call. call success(); to signify the async operation was successful.

A handler that can be inserted into a stepChangeHandler. See the Asynchronous Step Changes Example.

compass.activateDone()

Triggers the 'done' action and puts the Compass Component into the 'done' state. Use compass.reset() to get Compass out of the done state.

compass.activateNextStep()

Triggers the 'next' action and tries to push to the next step.

compass.activatePreviousStep()

Triggers the 'previous' action and tries to push to the previous step.

compass.cancelStepChange()

Causes a step change to not be successful. Useful for async operations and validation.

compass.disableDone()

Makes all Elements wired to the 'done' action disabled.

compass.disableNext()

Makes all Elements wired to the 'next' action disabled. Useful for async operations or validation.

compass.disablePrevious()

Makes all Elements wired to the 'previous' action disabled.

compass.reset()

Resets a Compass Component back to it's starting configuration.

compass.stepById(compassStepId)

  • compassStepId - The id of the element that represents the Compass Step.

returns a CompassStep who's element has the id specified by compassStepId.

Properties

compass.activeStep

  • CompassStep

Gets/Sets the current active CompassStep. The active CompassStep is tracked through the data-compass-active attribute on the step elements.

compass.autowireSteps

  • boolean

Get if the Compass Component has the data-compass-autowire-steps attribute. See Auto Wire Example.

compass.stepChangeHandlers

  • ICompassStepChangeHandlers

Get/Set a Configuration object that handles Step changes for particular steps. See Using Compass's Step Change Handlers Example

compass.steps

  • CompassStep[]

Get an array of all CompassStep objects associated with this Compass Component.

compass.titleElements

  • HTMLElement[]

Get an array of elements that have [data-compass-title] to display the title from each step.

compass.triggerDoneElements

  • HTMLElement[]

Get an array of elements that have [data-compass-action="done"] to control the done action.

compass.triggerNextElements

  • HTMLElement[]

Get an array of elements that have [data-compass-action="next"] to control the next step action.

compass.triggerPreviousElements

  • HTMLElement[]

Get an array of elements that have [data-compass-action="previous"] to control the previous step action.

compassStep.active

  • boolean

Get a step who is active. Use compass.activeStep to set an active step.

compassStep.element

  • HTMLElement

Get the element associated with the CompassStep object.

compassStep.id

  • HTMLElement

Get/Set the id of the element associated with the CompassStep object.

getNextStepId

  • string

Get/Set the id of the CompassStep that would be activated by the next action.

getPreviousStepId

  • string

Get/Set the id of the CompassStep that would be activated by the previous action.

isFirst

  • boolean

Get if the step is configured to be the entry point for it's Compass.

title

  • string

Get/Set the title to be displayed when the step is presented.

Variables

Nothing is configurable in this component.

Themeability

Nothing is themeable in this component.